aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/802/Makefile4
-rw-r--r--net/dccp/ipv4.c1
-rw-r--r--net/dccp/ipv6.c3
-rw-r--r--net/ipv4/ip_gre.c1
-rw-r--r--net/ipv4/ip_input.c15
-rw-r--r--net/ipv4/ip_output.c10
-rw-r--r--net/ipv4/ipip.c1
-rw-r--r--net/ipv4/netfilter.c15
-rw-r--r--net/ipv4/netfilter/Kconfig10
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_sctp.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c109
-rw-r--r--net/ipv4/netfilter/ipt_policy.c170
-rw-r--r--net/ipv4/raw.c1
-rw-r--r--net/ipv4/tcp_ipv4.c1
-rw-r--r--net/ipv4/udp.c2
-rw-r--r--net/ipv4/xfrm4_input.c31
-rw-r--r--net/ipv4/xfrm4_output.c72
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/af_inet6.c4
-rw-r--r--net/ipv6/exthdrs.c19
-rw-r--r--net/ipv6/icmp.c4
-rw-r--r--net/ipv6/inet6_connection_sock.c1
-rw-r--r--net/ipv6/ip6_input.c23
-rw-r--r--net/ipv6/ip6_tunnel.c2
-rw-r--r--net/ipv6/netfilter.c9
-rw-r--r--net/ipv6/netfilter/Kconfig10
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6t_policy.c175
-rw-r--r--net/ipv6/reassembly.c11
-rw-r--r--net/ipv6/sit.c2
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/ipv6/udp.c2
-rw-r--r--net/ipv6/xfrm6_input.c21
-rw-r--r--net/ipv6/xfrm6_output.c76
-rw-r--r--net/ipv6/xfrm6_tunnel.c6
-rw-r--r--net/sctp/input.c1
-rw-r--r--net/sctp/ipv6.c2
-rw-r--r--net/sunrpc/rpc_pipe.c2
-rw-r--r--net/xfrm/xfrm_policy.c11
40 files changed, 712 insertions, 122 deletions
diff --git a/net/802/Makefile b/net/802/Makefile
index 01861929591a..977704a54f68 100644
--- a/net/802/Makefile
+++ b/net/802/Makefile
@@ -2,8 +2,6 @@
2# Makefile for the Linux 802.x protocol layers. 2# Makefile for the Linux 802.x protocol layers.
3# 3#
4 4
5obj-y := p8023.o
6
7# Check the p8022 selections against net/core/Makefile. 5# Check the p8022 selections against net/core/Makefile.
8obj-$(CONFIG_SYSCTL) += sysctl_net_802.o 6obj-$(CONFIG_SYSCTL) += sysctl_net_802.o
9obj-$(CONFIG_LLC) += p8022.o psnap.o 7obj-$(CONFIG_LLC) += p8022.o psnap.o
@@ -11,5 +9,5 @@ obj-$(CONFIG_TR) += p8022.o psnap.o tr.o sysctl_net_802.o
11obj-$(CONFIG_NET_FC) += fc.o 9obj-$(CONFIG_NET_FC) += fc.o
12obj-$(CONFIG_FDDI) += fddi.o 10obj-$(CONFIG_FDDI) += fddi.o
13obj-$(CONFIG_HIPPI) += hippi.o 11obj-$(CONFIG_HIPPI) += hippi.o
14obj-$(CONFIG_IPX) += p8022.o psnap.o 12obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o
15obj-$(CONFIG_ATALK) += p8022.o psnap.o 13obj-$(CONFIG_ATALK) += p8022.o psnap.o
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 3f244670764a..00f983226672 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb)
986 986
987 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 987 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
988 goto discard_and_relse; 988 goto discard_and_relse;
989 nf_reset(skb);
989 990
990 return sk_receive_skb(sk, skb); 991 return sk_receive_skb(sk, skb);
991 992
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index c609dc78f487..df074259f9c3 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -27,6 +27,7 @@
27#include <net/ipv6.h> 27#include <net/ipv6.h>
28#include <net/protocol.h> 28#include <net/protocol.h>
29#include <net/transp_v6.h> 29#include <net/transp_v6.h>
30#include <net/ip6_checksum.h>
30#include <net/xfrm.h> 31#include <net/xfrm.h>
31 32
32#include "dccp.h" 33#include "dccp.h"
@@ -1028,7 +1029,7 @@ discard:
1028 return 0; 1029 return 0;
1029} 1030}
1030 1031
1031static int dccp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 1032static int dccp_v6_rcv(struct sk_buff **pskb)
1032{ 1033{
1033 const struct dccp_hdr *dh; 1034 const struct dccp_hdr *dh;
1034 struct sk_buff *skb = *pskb; 1035 struct sk_buff *skb = *pskb;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 912c42f57c79..de16e944777f 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -832,6 +832,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
832 skb->h.raw = skb->nh.raw; 832 skb->h.raw = skb->nh.raw;
833 skb->nh.raw = skb_push(skb, gre_hlen); 833 skb->nh.raw = skb_push(skb, gre_hlen);
834 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 834 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
835 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE|IPSKB_XFRM_TRANSFORMED);
835 dst_release(skb->dst); 836 dst_release(skb->dst);
836 skb->dst = &rt->u.dst; 837 skb->dst = &rt->u.dst;
837 838
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index e45846ae570b..18d7fad474d7 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -185,7 +185,6 @@ int ip_call_ra_chain(struct sk_buff *skb)
185 raw_rcv(last, skb2); 185 raw_rcv(last, skb2);
186 } 186 }
187 last = sk; 187 last = sk;
188 nf_reset(skb);
189 } 188 }
190 } 189 }
191 190
@@ -204,10 +203,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
204 203
205 __skb_pull(skb, ihl); 204 __skb_pull(skb, ihl);
206 205
207 /* Free reference early: we don't need it any more, and it may
208 hold ip_conntrack module loaded indefinitely. */
209 nf_reset(skb);
210
211 /* Point into the IP datagram, just past the header. */ 206 /* Point into the IP datagram, just past the header. */
212 skb->h.raw = skb->data; 207 skb->h.raw = skb->data;
213 208
@@ -232,10 +227,12 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
232 if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { 227 if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
233 int ret; 228 int ret;
234 229
235 if (!ipprot->no_policy && 230 if (!ipprot->no_policy) {
236 !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 231 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
237 kfree_skb(skb); 232 kfree_skb(skb);
238 goto out; 233 goto out;
234 }
235 nf_reset(skb);
239 } 236 }
240 ret = ipprot->handler(skb); 237 ret = ipprot->handler(skb);
241 if (ret < 0) { 238 if (ret < 0) {
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 8b1c9bd0091e..c2169b47ddfd 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -85,6 +85,8 @@
85 85
86int sysctl_ip_default_ttl = IPDEFTTL; 86int sysctl_ip_default_ttl = IPDEFTTL;
87 87
88static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*));
89
88/* Generate a checksum for an outgoing IP datagram. */ 90/* Generate a checksum for an outgoing IP datagram. */
89__inline__ void ip_send_check(struct iphdr *iph) 91__inline__ void ip_send_check(struct iphdr *iph)
90{ 92{
@@ -202,6 +204,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
202 204
203static inline int ip_finish_output(struct sk_buff *skb) 205static inline int ip_finish_output(struct sk_buff *skb)
204{ 206{
207#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
208 /* Policy lookup after SNAT yielded a new policy */
209 if (skb->dst->xfrm != NULL)
210 return xfrm4_output_finish(skb);
211#endif
205 if (skb->len > dst_mtu(skb->dst) && 212 if (skb->len > dst_mtu(skb->dst) &&
206 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) 213 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
207 return ip_fragment(skb, ip_finish_output2); 214 return ip_fragment(skb, ip_finish_output2);
@@ -409,7 +416,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
409 * single device frame, and queue such a frame for sending. 416 * single device frame, and queue such a frame for sending.
410 */ 417 */
411 418
412int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) 419static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
413{ 420{
414 struct iphdr *iph; 421 struct iphdr *iph;
415 int raw = 0; 422 int raw = 0;
@@ -1391,7 +1398,6 @@ void __init ip_init(void)
1391#endif 1398#endif
1392} 1399}
1393 1400
1394EXPORT_SYMBOL(ip_fragment);
1395EXPORT_SYMBOL(ip_generic_getfrag); 1401EXPORT_SYMBOL(ip_generic_getfrag);
1396EXPORT_SYMBOL(ip_queue_xmit); 1402EXPORT_SYMBOL(ip_queue_xmit);
1397EXPORT_SYMBOL(ip_send_check); 1403EXPORT_SYMBOL(ip_send_check);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 35571cff81c6..bbd85f5ec985 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -621,6 +621,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
621 skb->h.raw = skb->nh.raw; 621 skb->h.raw = skb->nh.raw;
622 skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); 622 skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
623 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 623 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
624 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE|IPSKB_XFRM_TRANSFORMED);
624 dst_release(skb->dst); 625 dst_release(skb->dst);
625 skb->dst = &rt->u.dst; 626 skb->dst = &rt->u.dst;
626 627
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index ae0779d82c5d..3321092b0914 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -7,11 +7,13 @@
7#include <linux/netfilter.h> 7#include <linux/netfilter.h>
8#include <linux/netfilter_ipv4.h> 8#include <linux/netfilter_ipv4.h>
9 9
10#include <linux/ip.h>
10#include <linux/tcp.h> 11#include <linux/tcp.h>
11#include <linux/udp.h> 12#include <linux/udp.h>
12#include <linux/icmp.h> 13#include <linux/icmp.h>
13#include <net/route.h> 14#include <net/route.h>
14#include <linux/ip.h> 15#include <net/xfrm.h>
16#include <net/ip.h>
15 17
16/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ 18/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
17int ip_route_me_harder(struct sk_buff **pskb) 19int ip_route_me_harder(struct sk_buff **pskb)
@@ -33,7 +35,6 @@ int ip_route_me_harder(struct sk_buff **pskb)
33#ifdef CONFIG_IP_ROUTE_FWMARK 35#ifdef CONFIG_IP_ROUTE_FWMARK
34 fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; 36 fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
35#endif 37#endif
36 fl.proto = iph->protocol;
37 if (ip_route_output_key(&rt, &fl) != 0) 38 if (ip_route_output_key(&rt, &fl) != 0)
38 return -1; 39 return -1;
39 40
@@ -60,6 +61,13 @@ int ip_route_me_harder(struct sk_buff **pskb)
60 if ((*pskb)->dst->error) 61 if ((*pskb)->dst->error)
61 return -1; 62 return -1;
62 63
64#ifdef CONFIG_XFRM
65 if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) &&
66 xfrm_decode_session(*pskb, &fl, AF_INET) == 0)
67 if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0))
68 return -1;
69#endif
70
63 /* Change in oif may mean change in hh_len. */ 71 /* Change in oif may mean change in hh_len. */
64 hh_len = (*pskb)->dst->dev->hard_header_len; 72 hh_len = (*pskb)->dst->dev->hard_header_len;
65 if (skb_headroom(*pskb) < hh_len) { 73 if (skb_headroom(*pskb) < hh_len) {
@@ -78,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb)
78} 86}
79EXPORT_SYMBOL(ip_route_me_harder); 87EXPORT_SYMBOL(ip_route_me_harder);
80 88
89void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
90EXPORT_SYMBOL(ip_nat_decode_session);
91
81/* 92/*
82 * Extra routing may needed on local out, as the QUEUE target never 93 * Extra routing may needed on local out, as the QUEUE target never
83 * returns control to the table. 94 * returns control to the table.
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 88a60650e6b8..a9893ec03e02 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -487,6 +487,16 @@ config IP_NF_MATCH_STRING
487 487
488 To compile it as a module, choose M here. If unsure, say N. 488 To compile it as a module, choose M here. If unsure, say N.
489 489
490config IP_NF_MATCH_POLICY
491 tristate "IPsec policy match support"
492 depends on IP_NF_IPTABLES && XFRM
493 help
494 Policy matching allows you to match packets based on the
495 IPsec policy that was used during decapsulation/will
496 be used during encapsulation.
497
498 To compile it as a module, choose M here. If unsure, say N.
499
490# `filter', generic and specific targets 500# `filter', generic and specific targets
491config IP_NF_FILTER 501config IP_NF_FILTER
492 tristate "Packet filtering" 502 tristate "Packet filtering"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index d0a447e520a2..549b01a648b3 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
72obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o 72obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
73obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o 73obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
74obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o 74obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
75obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
75obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o 76obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
76obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o 77obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
77 78
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
index 977fb59d4563..0b25050981a1 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -16,6 +16,7 @@
16#include <linux/types.h> 16#include <linux/types.h>
17#include <linux/sched.h> 17#include <linux/sched.h>
18#include <linux/timer.h> 18#include <linux/timer.h>
19#include <linux/interrupt.h>
19#include <linux/netfilter.h> 20#include <linux/netfilter.h>
20#include <linux/module.h> 21#include <linux/module.h>
21#include <linux/in.h> 22#include <linux/in.h>
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index f04111f74e09..8b8a1f00bbf4 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -55,6 +55,44 @@
55 : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ 55 : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
56 : "*ERROR*"))) 56 : "*ERROR*")))
57 57
58#ifdef CONFIG_XFRM
59static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
60{
61 struct ip_conntrack *ct;
62 struct ip_conntrack_tuple *t;
63 enum ip_conntrack_info ctinfo;
64 enum ip_conntrack_dir dir;
65 unsigned long statusbit;
66
67 ct = ip_conntrack_get(skb, &ctinfo);
68 if (ct == NULL)
69 return;
70 dir = CTINFO2DIR(ctinfo);
71 t = &ct->tuplehash[dir].tuple;
72
73 if (dir == IP_CT_DIR_ORIGINAL)
74 statusbit = IPS_DST_NAT;
75 else
76 statusbit = IPS_SRC_NAT;
77
78 if (ct->status & statusbit) {
79 fl->fl4_dst = t->dst.ip;
80 if (t->dst.protonum == IPPROTO_TCP ||
81 t->dst.protonum == IPPROTO_UDP)
82 fl->fl_ip_dport = t->dst.u.tcp.port;
83 }
84
85 statusbit ^= IPS_NAT_MASK;
86
87 if (ct->status & statusbit) {
88 fl->fl4_src = t->src.ip;
89 if (t->dst.protonum == IPPROTO_TCP ||
90 t->dst.protonum == IPPROTO_UDP)
91 fl->fl_ip_sport = t->src.u.tcp.port;
92 }
93}
94#endif
95
58static unsigned int 96static unsigned int
59ip_nat_fn(unsigned int hooknum, 97ip_nat_fn(unsigned int hooknum,
60 struct sk_buff **pskb, 98 struct sk_buff **pskb,
@@ -162,18 +200,20 @@ ip_nat_in(unsigned int hooknum,
162 const struct net_device *out, 200 const struct net_device *out,
163 int (*okfn)(struct sk_buff *)) 201 int (*okfn)(struct sk_buff *))
164{ 202{
165 u_int32_t saddr, daddr; 203 struct ip_conntrack *ct;
204 enum ip_conntrack_info ctinfo;
166 unsigned int ret; 205 unsigned int ret;
167 206
168 saddr = (*pskb)->nh.iph->saddr;
169 daddr = (*pskb)->nh.iph->daddr;
170
171 ret = ip_nat_fn(hooknum, pskb, in, out, okfn); 207 ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
172 if (ret != NF_DROP && ret != NF_STOLEN 208 if (ret != NF_DROP && ret != NF_STOLEN
173 && ((*pskb)->nh.iph->saddr != saddr 209 && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
174 || (*pskb)->nh.iph->daddr != daddr)) { 210 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
175 dst_release((*pskb)->dst); 211
176 (*pskb)->dst = NULL; 212 if (ct->tuplehash[dir].tuple.src.ip !=
213 ct->tuplehash[!dir].tuple.dst.ip) {
214 dst_release((*pskb)->dst);
215 (*pskb)->dst = NULL;
216 }
177 } 217 }
178 return ret; 218 return ret;
179} 219}
@@ -185,12 +225,30 @@ ip_nat_out(unsigned int hooknum,
185 const struct net_device *out, 225 const struct net_device *out,
186 int (*okfn)(struct sk_buff *)) 226 int (*okfn)(struct sk_buff *))
187{ 227{
228 struct ip_conntrack *ct;
229 enum ip_conntrack_info ctinfo;
230 unsigned int ret;
231
188 /* root is playing with raw sockets. */ 232 /* root is playing with raw sockets. */
189 if ((*pskb)->len < sizeof(struct iphdr) 233 if ((*pskb)->len < sizeof(struct iphdr)
190 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 234 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
191 return NF_ACCEPT; 235 return NF_ACCEPT;
192 236
193 return ip_nat_fn(hooknum, pskb, in, out, okfn); 237 ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
238 if (ret != NF_DROP && ret != NF_STOLEN
239 && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
240 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
241
242 if (ct->tuplehash[dir].tuple.src.ip !=
243 ct->tuplehash[!dir].tuple.dst.ip
244#ifdef CONFIG_XFRM
245 || ct->tuplehash[dir].tuple.src.u.all !=
246 ct->tuplehash[!dir].tuple.dst.u.all
247#endif
248 )
249 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
250 }
251 return ret;
194} 252}
195 253
196static unsigned int 254static unsigned int
@@ -200,7 +258,8 @@ ip_nat_local_fn(unsigned int hooknum,
200 const struct net_device *out, 258 const struct net_device *out,
201 int (*okfn)(struct sk_buff *)) 259 int (*okfn)(struct sk_buff *))
202{ 260{
203 u_int32_t saddr, daddr; 261 struct ip_conntrack *ct;
262 enum ip_conntrack_info ctinfo;
204 unsigned int ret; 263 unsigned int ret;
205 264
206 /* root is playing with raw sockets. */ 265 /* root is playing with raw sockets. */
@@ -208,14 +267,20 @@ ip_nat_local_fn(unsigned int hooknum,
208 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 267 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
209 return NF_ACCEPT; 268 return NF_ACCEPT;
210 269
211 saddr = (*pskb)->nh.iph->saddr;
212 daddr = (*pskb)->nh.iph->daddr;
213
214 ret = ip_nat_fn(hooknum, pskb, in, out, okfn); 270 ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
215 if (ret != NF_DROP && ret != NF_STOLEN 271 if (ret != NF_DROP && ret != NF_STOLEN
216 && ((*pskb)->nh.iph->saddr != saddr 272 && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
217 || (*pskb)->nh.iph->daddr != daddr)) 273 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
218 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; 274
275 if (ct->tuplehash[dir].tuple.dst.ip !=
276 ct->tuplehash[!dir].tuple.src.ip
277#ifdef CONFIG_XFRM
278 || ct->tuplehash[dir].tuple.dst.u.all !=
279 ct->tuplehash[dir].tuple.src.u.all
280#endif
281 )
282 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
283 }
219 return ret; 284 return ret;
220} 285}
221 286
@@ -303,10 +368,14 @@ static int init_or_cleanup(int init)
303 368
304 if (!init) goto cleanup; 369 if (!init) goto cleanup;
305 370
371#ifdef CONFIG_XFRM
372 BUG_ON(ip_nat_decode_session != NULL);
373 ip_nat_decode_session = nat_decode_session;
374#endif
306 ret = ip_nat_rule_init(); 375 ret = ip_nat_rule_init();
307 if (ret < 0) { 376 if (ret < 0) {
308 printk("ip_nat_init: can't setup rules.\n"); 377 printk("ip_nat_init: can't setup rules.\n");
309 goto cleanup_nothing; 378 goto cleanup_decode_session;
310 } 379 }
311 ret = nf_register_hook(&ip_nat_in_ops); 380 ret = nf_register_hook(&ip_nat_in_ops);
312 if (ret < 0) { 381 if (ret < 0) {
@@ -354,7 +423,11 @@ static int init_or_cleanup(int init)
354 nf_unregister_hook(&ip_nat_in_ops); 423 nf_unregister_hook(&ip_nat_in_ops);
355 cleanup_rule_init: 424 cleanup_rule_init:
356 ip_nat_rule_cleanup(); 425 ip_nat_rule_cleanup();
357 cleanup_nothing: 426 cleanup_decode_session:
427#ifdef CONFIG_XFRM
428 ip_nat_decode_session = NULL;
429 synchronize_net();
430#endif
358 return ret; 431 return ret;
359} 432}
360 433
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c
new file mode 100644
index 000000000000..709debcc69c9
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_policy.c
@@ -0,0 +1,170 @@
1/* IP tables module for matching IPsec policy
2 *
3 * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/kernel.h>
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/init.h>
15#include <net/xfrm.h>
16
17#include <linux/netfilter_ipv4.h>
18#include <linux/netfilter_ipv4/ip_tables.h>
19#include <linux/netfilter_ipv4/ipt_policy.h>
20
21MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
22MODULE_DESCRIPTION("IPtables IPsec policy matching module");
23MODULE_LICENSE("GPL");
24
25
26static inline int
27match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
28{
29#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
30
31 return MATCH(saddr, x->props.saddr.a4 & e->smask) &&
32 MATCH(daddr, x->id.daddr.a4 & e->dmask) &&
33 MATCH(proto, x->id.proto) &&
34 MATCH(mode, x->props.mode) &&
35 MATCH(spi, x->id.spi) &&
36 MATCH(reqid, x->props.reqid);
37}
38
39static int
40match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
41{
42 const struct ipt_policy_elem *e;
43 struct sec_path *sp = skb->sp;
44 int strict = info->flags & IPT_POLICY_MATCH_STRICT;
45 int i, pos;
46
47 if (sp == NULL)
48 return -1;
49 if (strict && info->len != sp->len)
50 return 0;
51
52 for (i = sp->len - 1; i >= 0; i--) {
53 pos = strict ? i - sp->len + 1 : 0;
54 if (pos >= info->len)
55 return 0;
56 e = &info->pol[pos];
57
58 if (match_xfrm_state(sp->x[i].xvec, e)) {
59 if (!strict)
60 return 1;
61 } else if (strict)
62 return 0;
63 }
64
65 return strict ? 1 : 0;
66}
67
68static int
69match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
70{
71 const struct ipt_policy_elem *e;
72 struct dst_entry *dst = skb->dst;
73 int strict = info->flags & IPT_POLICY_MATCH_STRICT;
74 int i, pos;
75
76 if (dst->xfrm == NULL)
77 return -1;
78
79 for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
80 pos = strict ? i : 0;
81 if (pos >= info->len)
82 return 0;
83 e = &info->pol[pos];
84
85 if (match_xfrm_state(dst->xfrm, e)) {
86 if (!strict)
87 return 1;
88 } else if (strict)
89 return 0;
90 }
91
92 return strict ? 1 : 0;
93}
94
95static int match(const struct sk_buff *skb,
96 const struct net_device *in,
97 const struct net_device *out,
98 const void *matchinfo, int offset, int *hotdrop)
99{
100 const struct ipt_policy_info *info = matchinfo;
101 int ret;
102
103 if (info->flags & IPT_POLICY_MATCH_IN)
104 ret = match_policy_in(skb, info);
105 else
106 ret = match_policy_out(skb, info);
107
108 if (ret < 0)
109 ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0;
110 else if (info->flags & IPT_POLICY_MATCH_NONE)
111 ret = 0;
112
113 return ret;
114}
115
116static int checkentry(const char *tablename, const struct ipt_ip *ip,
117 void *matchinfo, unsigned int matchsize,
118 unsigned int hook_mask)
119{
120 struct ipt_policy_info *info = matchinfo;
121
122 if (matchsize != IPT_ALIGN(sizeof(*info))) {
123 printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n",
124 matchsize, IPT_ALIGN(sizeof(*info)));
125 return 0;
126 }
127 if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) {
128 printk(KERN_ERR "ipt_policy: neither incoming nor "
129 "outgoing policy selected\n");
130 return 0;
131 }
132 if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
133 && info->flags & IPT_POLICY_MATCH_OUT) {
134 printk(KERN_ERR "ipt_policy: output policy not valid in "
135 "PRE_ROUTING and INPUT\n");
136 return 0;
137 }
138 if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
139 && info->flags & IPT_POLICY_MATCH_IN) {
140 printk(KERN_ERR "ipt_policy: input policy not valid in "
141 "POST_ROUTING and OUTPUT\n");
142 return 0;
143 }
144 if (info->len > IPT_POLICY_MAX_ELEM) {
145 printk(KERN_ERR "ipt_policy: too many policy elements\n");
146 return 0;
147 }
148
149 return 1;
150}
151
152static struct ipt_match policy_match = {
153 .name = "policy",
154 .match = match,
155 .checkentry = checkentry,
156 .me = THIS_MODULE,
157};
158
159static int __init init(void)
160{
161 return ipt_register_match(&policy_match);
162}
163
164static void __exit fini(void)
165{
166 ipt_unregister_match(&policy_match);
167}
168
169module_init(init);
170module_exit(fini);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 4b0d7e4d6269..165a4d81efa4 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -255,6 +255,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb)
255 kfree_skb(skb); 255 kfree_skb(skb);
256 return NET_RX_DROP; 256 return NET_RX_DROP;
257 } 257 }
258 nf_reset(skb);
258 259
259 skb_push(skb, skb->data - skb->nh.raw); 260 skb_push(skb, skb->data - skb->nh.raw);
260 261
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index e9f83e5b28ce..6ea353907af5 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1080,6 +1080,7 @@ process:
1080 1080
1081 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 1081 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
1082 goto discard_and_relse; 1082 goto discard_and_relse;
1083 nf_reset(skb);
1083 1084
1084 if (sk_filter(sk, skb, 0)) 1085 if (sk_filter(sk, skb, 0))
1085 goto discard_and_relse; 1086 goto discard_and_relse;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 223abaa72bc5..00840474a449 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -989,6 +989,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
989 kfree_skb(skb); 989 kfree_skb(skb);
990 return -1; 990 return -1;
991 } 991 }
992 nf_reset(skb);
992 993
993 if (up->encap_type) { 994 if (up->encap_type) {
994 /* 995 /*
@@ -1149,6 +1150,7 @@ int udp_rcv(struct sk_buff *skb)
1149 1150
1150 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 1151 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
1151 goto drop; 1152 goto drop;
1153 nf_reset(skb);
1152 1154
1153 /* No socket. Drop packet silently, if checksum is wrong */ 1155 /* No socket. Drop packet silently, if checksum is wrong */
1154 if (udp_checksum_complete(skb)) 1156 if (udp_checksum_complete(skb))
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 2d3849c38a0f..850d919591d1 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -11,6 +11,8 @@
11 11
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/string.h> 13#include <linux/string.h>
14#include <linux/netfilter.h>
15#include <linux/netfilter_ipv4.h>
14#include <net/inet_ecn.h> 16#include <net/inet_ecn.h>
15#include <net/ip.h> 17#include <net/ip.h>
16#include <net/xfrm.h> 18#include <net/xfrm.h>
@@ -45,6 +47,23 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
45 return xfrm_parse_spi(skb, nexthdr, spi, seq); 47 return xfrm_parse_spi(skb, nexthdr, spi, seq);
46} 48}
47 49
50#ifdef CONFIG_NETFILTER
51static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
52{
53 struct iphdr *iph = skb->nh.iph;
54
55 if (skb->dst == NULL) {
56 if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
57 skb->dev))
58 goto drop;
59 }
60 return dst_input(skb);
61drop:
62 kfree_skb(skb);
63 return NET_RX_DROP;
64}
65#endif
66
48int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) 67int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
49{ 68{
50 int err; 69 int err;
@@ -137,6 +156,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
137 memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state)); 156 memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
138 skb->sp->len += xfrm_nr; 157 skb->sp->len += xfrm_nr;
139 158
159 nf_reset(skb);
160
140 if (decaps) { 161 if (decaps) {
141 if (!(skb->dev->flags&IFF_LOOPBACK)) { 162 if (!(skb->dev->flags&IFF_LOOPBACK)) {
142 dst_release(skb->dst); 163 dst_release(skb->dst);
@@ -145,7 +166,17 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
145 netif_rx(skb); 166 netif_rx(skb);
146 return 0; 167 return 0;
147 } else { 168 } else {
169#ifdef CONFIG_NETFILTER
170 __skb_push(skb, skb->data - skb->nh.raw);
171 skb->nh.iph->tot_len = htons(skb->len);
172 ip_send_check(skb->nh.iph);
173
174 NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
175 xfrm4_rcv_encap_finish);
176 return 0;
177#else
148 return -skb->nh.iph->protocol; 178 return -skb->nh.iph->protocol;
179#endif
149 } 180 }
150 181
151drop_unlock: 182drop_unlock:
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 66620a95942a..d4df0ddd424b 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -8,8 +8,10 @@
8 * 2 of the License, or (at your option) any later version. 8 * 2 of the License, or (at your option) any later version.
9 */ 9 */
10 10
11#include <linux/compiler.h>
11#include <linux/skbuff.h> 12#include <linux/skbuff.h>
12#include <linux/spinlock.h> 13#include <linux/spinlock.h>
14#include <linux/netfilter_ipv4.h>
13#include <net/inet_ecn.h> 15#include <net/inet_ecn.h>
14#include <net/ip.h> 16#include <net/ip.h>
15#include <net/xfrm.h> 17#include <net/xfrm.h>
@@ -95,7 +97,7 @@ out:
95 return ret; 97 return ret;
96} 98}
97 99
98int xfrm4_output(struct sk_buff *skb) 100static int xfrm4_output_one(struct sk_buff *skb)
99{ 101{
100 struct dst_entry *dst = skb->dst; 102 struct dst_entry *dst = skb->dst;
101 struct xfrm_state *x = dst->xfrm; 103 struct xfrm_state *x = dst->xfrm;
@@ -113,27 +115,33 @@ int xfrm4_output(struct sk_buff *skb)
113 goto error_nolock; 115 goto error_nolock;
114 } 116 }
115 117
116 spin_lock_bh(&x->lock); 118 do {
117 err = xfrm_state_check(x, skb); 119 spin_lock_bh(&x->lock);
118 if (err) 120 err = xfrm_state_check(x, skb);
119 goto error; 121 if (err)
122 goto error;
120 123
121 xfrm4_encap(skb); 124 xfrm4_encap(skb);
122 125
123 err = x->type->output(x, skb); 126 err = x->type->output(x, skb);
124 if (err) 127 if (err)
125 goto error; 128 goto error;
126 129
127 x->curlft.bytes += skb->len; 130 x->curlft.bytes += skb->len;
128 x->curlft.packets++; 131 x->curlft.packets++;
129 132
130 spin_unlock_bh(&x->lock); 133 spin_unlock_bh(&x->lock);
131 134
132 if (!(skb->dst = dst_pop(dst))) { 135 if (!(skb->dst = dst_pop(dst))) {
133 err = -EHOSTUNREACH; 136 err = -EHOSTUNREACH;
134 goto error_nolock; 137 goto error_nolock;
135 } 138 }
136 err = NET_XMIT_BYPASS; 139 dst = skb->dst;
140 x = dst->xfrm;
141 } while (x && !x->props.mode);
142
143 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
144 err = 0;
137 145
138out_exit: 146out_exit:
139 return err; 147 return err;
@@ -143,3 +151,33 @@ error_nolock:
143 kfree_skb(skb); 151 kfree_skb(skb);
144 goto out_exit; 152 goto out_exit;
145} 153}
154
155int xfrm4_output_finish(struct sk_buff *skb)
156{
157 int err;
158
159 while (likely((err = xfrm4_output_one(skb)) == 0)) {
160 nf_reset(skb);
161
162 err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL,
163 skb->dst->dev, dst_output);
164 if (unlikely(err != 1))
165 break;
166
167 if (!skb->dst->xfrm)
168 return dst_output(skb);
169
170 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
171 skb->dst->dev, xfrm4_output_finish);
172 if (unlikely(err != 1))
173 break;
174 }
175
176 return err;
177}
178
179int xfrm4_output(struct sk_buff *skb)
180{
181 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
182 xfrm4_output_finish);
183}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 704fb73e6c5f..e53e421eeee9 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1228,7 +1228,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
1228 1228
1229/* Gets referenced address, destroys ifaddr */ 1229/* Gets referenced address, destroys ifaddr */
1230 1230
1231void addrconf_dad_stop(struct inet6_ifaddr *ifp) 1231static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
1232{ 1232{
1233 if (ifp->flags&IFA_F_PERMANENT) { 1233 if (ifp->flags&IFA_F_PERMANENT) {
1234 spin_lock_bh(&ifp->lock); 1234 spin_lock_bh(&ifp->lock);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 68afc53be662..25c3fe5005d9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -689,11 +689,11 @@ snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
689 if (ptr == NULL) 689 if (ptr == NULL)
690 return -EINVAL; 690 return -EINVAL;
691 691
692 ptr[0] = __alloc_percpu(mibsize, mibalign); 692 ptr[0] = __alloc_percpu(mibsize);
693 if (!ptr[0]) 693 if (!ptr[0])
694 goto err0; 694 goto err0;
695 695
696 ptr[1] = __alloc_percpu(mibsize, mibalign); 696 ptr[1] = __alloc_percpu(mibsize);
697 if (!ptr[1]) 697 if (!ptr[1])
698 goto err1; 698 goto err1;
699 699
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 113374dc342c..2a1e7e45b890 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -152,7 +152,7 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
152 {-1, NULL} 152 {-1, NULL}
153}; 153};
154 154
155static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) 155static int ipv6_destopt_rcv(struct sk_buff **skbp)
156{ 156{
157 struct sk_buff *skb = *skbp; 157 struct sk_buff *skb = *skbp;
158 struct inet6_skb_parm *opt = IP6CB(skb); 158 struct inet6_skb_parm *opt = IP6CB(skb);
@@ -169,7 +169,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
169 169
170 if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { 170 if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
171 skb->h.raw += ((skb->h.raw[1]+1)<<3); 171 skb->h.raw += ((skb->h.raw[1]+1)<<3);
172 *nhoffp = opt->dst1; 172 opt->nhoff = opt->dst1;
173 return 1; 173 return 1;
174 } 174 }
175 175
@@ -192,7 +192,7 @@ void __init ipv6_destopt_init(void)
192 NONE header. No data in packet. 192 NONE header. No data in packet.
193 ********************************/ 193 ********************************/
194 194
195static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp) 195static int ipv6_nodata_rcv(struct sk_buff **skbp)
196{ 196{
197 struct sk_buff *skb = *skbp; 197 struct sk_buff *skb = *skbp;
198 198
@@ -215,7 +215,7 @@ void __init ipv6_nodata_init(void)
215 Routing header. 215 Routing header.
216 ********************************/ 216 ********************************/
217 217
218static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) 218static int ipv6_rthdr_rcv(struct sk_buff **skbp)
219{ 219{
220 struct sk_buff *skb = *skbp; 220 struct sk_buff *skb = *skbp;
221 struct inet6_skb_parm *opt = IP6CB(skb); 221 struct inet6_skb_parm *opt = IP6CB(skb);
@@ -249,7 +249,7 @@ looped_back:
249 skb->h.raw += (hdr->hdrlen + 1) << 3; 249 skb->h.raw += (hdr->hdrlen + 1) << 3;
250 opt->dst0 = opt->dst1; 250 opt->dst0 = opt->dst1;
251 opt->dst1 = 0; 251 opt->dst1 = 0;
252 *nhoffp = (&hdr->nexthdr) - skb->nh.raw; 252 opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
253 return 1; 253 return 1;
254 } 254 }
255 255
@@ -487,9 +487,14 @@ static struct tlvtype_proc tlvprochopopt_lst[] = {
487 487
488int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) 488int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
489{ 489{
490 IP6CB(skb)->hop = sizeof(struct ipv6hdr); 490 struct inet6_skb_parm *opt = IP6CB(skb);
491 if (ip6_parse_tlv(tlvprochopopt_lst, skb)) 491
492 opt->hop = sizeof(struct ipv6hdr);
493 if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
494 skb->h.raw += (skb->h.raw[1]+1)<<3;
495 opt->nhoff = sizeof(struct ipv6hdr);
492 return sizeof(struct ipv6hdr); 496 return sizeof(struct ipv6hdr);
497 }
493 return -1; 498 return -1;
494} 499}
495 500
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 6ec6a2b549bb..53c81fcd20ba 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -79,7 +79,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly;
79static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL; 79static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
80#define icmpv6_socket __get_cpu_var(__icmpv6_socket) 80#define icmpv6_socket __get_cpu_var(__icmpv6_socket)
81 81
82static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); 82static int icmpv6_rcv(struct sk_buff **pskb);
83 83
84static struct inet6_protocol icmpv6_protocol = { 84static struct inet6_protocol icmpv6_protocol = {
85 .handler = icmpv6_rcv, 85 .handler = icmpv6_rcv,
@@ -581,7 +581,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
581 * Handle icmp messages 581 * Handle icmp messages
582 */ 582 */
583 583
584static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 584static int icmpv6_rcv(struct sk_buff **pskb)
585{ 585{
586 struct sk_buff *skb = *pskb; 586 struct sk_buff *skb = *pskb;
587 struct net_device *dev = skb->dev; 587 struct net_device *dev = skb->dev;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 792f90f0f9ec..f8f3a37a1494 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -25,6 +25,7 @@
25#include <net/inet_hashtables.h> 25#include <net/inet_hashtables.h>
26#include <net/ip6_route.h> 26#include <net/ip6_route.h>
27#include <net/sock.h> 27#include <net/sock.h>
28#include <net/inet6_connection_sock.h>
28 29
29int inet6_csk_bind_conflict(const struct sock *sk, 30int inet6_csk_bind_conflict(const struct sock *sk,
30 const struct inet_bind_bucket *tb) 31 const struct inet_bind_bucket *tb)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index a6026d2787d2..29f73592e68e 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -48,7 +48,7 @@
48 48
49 49
50 50
51static inline int ip6_rcv_finish( struct sk_buff *skb) 51inline int ip6_rcv_finish( struct sk_buff *skb)
52{ 52{
53 if (skb->dst == NULL) 53 if (skb->dst == NULL)
54 ip6_route_input(skb); 54 ip6_route_input(skb);
@@ -97,6 +97,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
97 if (hdr->version != 6) 97 if (hdr->version != 6)
98 goto err; 98 goto err;
99 99
100 skb->h.raw = (u8 *)(hdr + 1);
101 IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
102
100 pkt_len = ntohs(hdr->payload_len); 103 pkt_len = ntohs(hdr->payload_len);
101 104
102 /* pkt_len may be zero if Jumbo payload option is present */ 105 /* pkt_len may be zero if Jumbo payload option is present */
@@ -111,8 +114,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
111 } 114 }
112 115
113 if (hdr->nexthdr == NEXTHDR_HOP) { 116 if (hdr->nexthdr == NEXTHDR_HOP) {
114 skb->h.raw = (u8*)(hdr+1); 117 if (ipv6_parse_hopopts(skb, IP6CB(skb)->nhoff) < 0) {
115 if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
116 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); 118 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
117 return 0; 119 return 0;
118 } 120 }
@@ -143,26 +145,15 @@ static inline int ip6_input_finish(struct sk_buff *skb)
143 int nexthdr; 145 int nexthdr;
144 u8 hash; 146 u8 hash;
145 147
146 skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
147
148 /* 148 /*
149 * Parse extension headers 149 * Parse extension headers
150 */ 150 */
151 151
152 nexthdr = skb->nh.ipv6h->nexthdr;
153 nhoff = offsetof(struct ipv6hdr, nexthdr);
154
155 /* Skip hop-by-hop options, they are already parsed. */
156 if (nexthdr == NEXTHDR_HOP) {
157 nhoff = sizeof(struct ipv6hdr);
158 nexthdr = skb->h.raw[0];
159 skb->h.raw += (skb->h.raw[1]+1)<<3;
160 }
161
162 rcu_read_lock(); 152 rcu_read_lock();
163resubmit: 153resubmit:
164 if (!pskb_pull(skb, skb->h.raw - skb->data)) 154 if (!pskb_pull(skb, skb->h.raw - skb->data))
165 goto discard; 155 goto discard;
156 nhoff = IP6CB(skb)->nhoff;
166 nexthdr = skb->nh.raw[nhoff]; 157 nexthdr = skb->nh.raw[nhoff];
167 158
168 raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]); 159 raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
@@ -194,7 +185,7 @@ resubmit:
194 !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 185 !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
195 goto discard; 186 goto discard;
196 187
197 ret = ipprot->handler(&skb, &nhoff); 188 ret = ipprot->handler(&skb);
198 if (ret > 0) 189 if (ret > 0)
199 goto resubmit; 190 goto resubmit;
200 else if (ret == 0) 191 else if (ret == 0)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index e315d0f80af1..f079621c8b67 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -510,7 +510,7 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
510 **/ 510 **/
511 511
512static int 512static int
513ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 513ip6ip6_rcv(struct sk_buff **pskb)
514{ 514{
515 struct sk_buff *skb = *pskb; 515 struct sk_buff *skb = *pskb;
516 struct ipv6hdr *ipv6h; 516 struct ipv6hdr *ipv6h;
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index f8626ebf90fd..b63678328a3b 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -10,6 +10,7 @@
10#include <net/dst.h> 10#include <net/dst.h>
11#include <net/ipv6.h> 11#include <net/ipv6.h>
12#include <net/ip6_route.h> 12#include <net/ip6_route.h>
13#include <net/xfrm.h>
13 14
14int ip6_route_me_harder(struct sk_buff *skb) 15int ip6_route_me_harder(struct sk_buff *skb)
15{ 16{
@@ -21,11 +22,17 @@ int ip6_route_me_harder(struct sk_buff *skb)
21 { .ip6_u = 22 { .ip6_u =
22 { .daddr = iph->daddr, 23 { .daddr = iph->daddr,
23 .saddr = iph->saddr, } }, 24 .saddr = iph->saddr, } },
24 .proto = iph->nexthdr,
25 }; 25 };
26 26
27 dst = ip6_route_output(skb->sk, &fl); 27 dst = ip6_route_output(skb->sk, &fl);
28 28
29#ifdef CONFIG_XFRM
30 if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
31 xfrm_decode_session(skb, &fl, AF_INET6) == 0)
32 if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
33 return -1;
34#endif
35
29 if (dst->error) { 36 if (dst->error) {
30 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); 37 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
31 LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); 38 LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 04912f9b35c3..105dd69ee9fb 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -179,6 +179,16 @@ config IP6_NF_MATCH_PHYSDEV
179 179
180 To compile it as a module, choose M here. If unsure, say N. 180 To compile it as a module, choose M here. If unsure, say N.
181 181
182config IP6_NF_MATCH_POLICY
183 tristate "IPsec policy match support"
184 depends on IP6_NF_IPTABLES && XFRM
185 help
186 Policy matching allows you to match packets based on the
187 IPsec policy that was used during decapsulation/will
188 be used during encapsulation.
189
190 To compile it as a module, choose M here. If unsure, say N.
191
182# The targets 192# The targets
183config IP6_NF_FILTER 193config IP6_NF_FILTER
184 tristate "Packet filtering" 194 tristate "Packet filtering"
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 9ab5b2ca1f59..c0c809b426e8 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
13obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o 13obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
14obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o 14obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
15obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o 15obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
16obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
16obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o 17obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
17obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o 18obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
18obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o 19obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c
new file mode 100644
index 000000000000..13fedad48c1d
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_policy.c
@@ -0,0 +1,175 @@
1/* IP tables module for matching IPsec policy
2 *
3 * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/kernel.h>
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/init.h>
15#include <net/xfrm.h>
16
17#include <linux/netfilter_ipv6.h>
18#include <linux/netfilter_ipv6/ip6_tables.h>
19#include <linux/netfilter_ipv6/ip6t_policy.h>
20
21MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
22MODULE_DESCRIPTION("IPtables IPsec policy matching module");
23MODULE_LICENSE("GPL");
24
25
26static inline int
27match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
28{
29#define MATCH_ADDR(x,y,z) (!e->match.x || \
30 ((ip6_masked_addrcmp((z), &e->x, &e->y)) == 0) ^ e->invert.x)
31#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
32
33 return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
34 MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) &&
35 MATCH(proto, x->id.proto) &&
36 MATCH(mode, x->props.mode) &&
37 MATCH(spi, x->id.spi) &&
38 MATCH(reqid, x->props.reqid);
39}
40
41static int
42match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info)
43{
44 const struct ip6t_policy_elem *e;
45 struct sec_path *sp = skb->sp;
46 int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
47 int i, pos;
48
49 if (sp == NULL)
50 return -1;
51 if (strict && info->len != sp->len)
52 return 0;
53
54 for (i = sp->len - 1; i >= 0; i--) {
55 pos = strict ? i - sp->len + 1 : 0;
56 if (pos >= info->len)
57 return 0;
58 e = &info->pol[pos];
59
60 if (match_xfrm_state(sp->x[i].xvec, e)) {
61 if (!strict)
62 return 1;
63 } else if (strict)
64 return 0;
65 }
66
67 return strict ? 1 : 0;
68}
69
70static int
71match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
72{
73 const struct ip6t_policy_elem *e;
74 struct dst_entry *dst = skb->dst;
75 int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
76 int i, pos;
77
78 if (dst->xfrm == NULL)
79 return -1;
80
81 for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
82 pos = strict ? i : 0;
83 if (pos >= info->len)
84 return 0;
85 e = &info->pol[pos];
86
87 if (match_xfrm_state(dst->xfrm, e)) {
88 if (!strict)
89 return 1;
90 } else if (strict)
91 return 0;
92 }
93
94 return strict ? 1 : 0;
95}
96
97static int match(const struct sk_buff *skb,
98 const struct net_device *in,
99 const struct net_device *out,
100 const void *matchinfo,
101 int offset,
102 unsigned int protoff,
103 int *hotdrop)
104{
105 const struct ip6t_policy_info *info = matchinfo;
106 int ret;
107
108 if (info->flags & IP6T_POLICY_MATCH_IN)
109 ret = match_policy_in(skb, info);
110 else
111 ret = match_policy_out(skb, info);
112
113 if (ret < 0)
114 ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0;
115 else if (info->flags & IP6T_POLICY_MATCH_NONE)
116 ret = 0;
117
118 return ret;
119}
120
121static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
122 void *matchinfo, unsigned int matchsize,
123 unsigned int hook_mask)
124{
125 struct ip6t_policy_info *info = matchinfo;
126
127 if (matchsize != IP6T_ALIGN(sizeof(*info))) {
128 printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n",
129 matchsize, IP6T_ALIGN(sizeof(*info)));
130 return 0;
131 }
132 if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) {
133 printk(KERN_ERR "ip6t_policy: neither incoming nor "
134 "outgoing policy selected\n");
135 return 0;
136 }
137 if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN)
138 && info->flags & IP6T_POLICY_MATCH_OUT) {
139 printk(KERN_ERR "ip6t_policy: output policy not valid in "
140 "PRE_ROUTING and INPUT\n");
141 return 0;
142 }
143 if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT)
144 && info->flags & IP6T_POLICY_MATCH_IN) {
145 printk(KERN_ERR "ip6t_policy: input policy not valid in "
146 "POST_ROUTING and OUTPUT\n");
147 return 0;
148 }
149 if (info->len > IP6T_POLICY_MAX_ELEM) {
150 printk(KERN_ERR "ip6t_policy: too many policy elements\n");
151 return 0;
152 }
153
154 return 1;
155}
156
157static struct ip6t_match policy_match = {
158 .name = "policy",
159 .match = match,
160 .checkentry = checkentry,
161 .me = THIS_MODULE,
162};
163
164static int __init init(void)
165{
166 return ip6t_register_match(&policy_match);
167}
168
169static void __exit fini(void)
170{
171 ip6t_unregister_match(&policy_match);
172}
173
174module_init(init);
175module_exit(fini);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 5d316cb72ec9..15e1456b3f18 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -581,7 +581,6 @@ err:
581 * the last and the first frames arrived and all the bits are here. 581 * the last and the first frames arrived and all the bits are here.
582 */ 582 */
583static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, 583static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
584 unsigned int *nhoffp,
585 struct net_device *dev) 584 struct net_device *dev)
586{ 585{
587 struct sk_buff *fp, *head = fq->fragments; 586 struct sk_buff *fp, *head = fq->fragments;
@@ -654,6 +653,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
654 head->dev = dev; 653 head->dev = dev;
655 skb_set_timestamp(head, &fq->stamp); 654 skb_set_timestamp(head, &fq->stamp);
656 head->nh.ipv6h->payload_len = htons(payload_len); 655 head->nh.ipv6h->payload_len = htons(payload_len);
656 IP6CB(head)->nhoff = nhoff;
657 657
658 *skb_in = head; 658 *skb_in = head;
659 659
@@ -663,7 +663,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
663 663
664 IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); 664 IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
665 fq->fragments = NULL; 665 fq->fragments = NULL;
666 *nhoffp = nhoff;
667 return 1; 666 return 1;
668 667
669out_oversize: 668out_oversize:
@@ -678,7 +677,7 @@ out_fail:
678 return -1; 677 return -1;
679} 678}
680 679
681static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) 680static int ipv6_frag_rcv(struct sk_buff **skbp)
682{ 681{
683 struct sk_buff *skb = *skbp; 682 struct sk_buff *skb = *skbp;
684 struct net_device *dev = skb->dev; 683 struct net_device *dev = skb->dev;
@@ -710,7 +709,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
710 skb->h.raw += sizeof(struct frag_hdr); 709 skb->h.raw += sizeof(struct frag_hdr);
711 IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); 710 IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
712 711
713 *nhoffp = (u8*)fhdr - skb->nh.raw; 712 IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw;
714 return 1; 713 return 1;
715 } 714 }
716 715
@@ -722,11 +721,11 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
722 721
723 spin_lock(&fq->lock); 722 spin_lock(&fq->lock);
724 723
725 ip6_frag_queue(fq, skb, fhdr, *nhoffp); 724 ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
726 725
727 if (fq->last_in == (FIRST_IN|LAST_IN) && 726 if (fq->last_in == (FIRST_IN|LAST_IN) &&
728 fq->meat == fq->len) 727 fq->meat == fq->len)
729 ret = ip6_frag_reasm(fq, skbp, nhoffp, dev); 728 ret = ip6_frag_reasm(fq, skbp, dev);
730 729
731 spin_unlock(&fq->lock); 730 spin_unlock(&fq->lock);
732 fq_put(fq, NULL); 731 fq_put(fq, NULL);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 577d49732b0f..02872ae8a439 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -381,6 +381,7 @@ static int ipip6_rcv(struct sk_buff *skb)
381 skb->mac.raw = skb->nh.raw; 381 skb->mac.raw = skb->nh.raw;
382 skb->nh.raw = skb->data; 382 skb->nh.raw = skb->data;
383 memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); 383 memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
384 IPCB(skb)->flags = 0;
384 skb->protocol = htons(ETH_P_IPV6); 385 skb->protocol = htons(ETH_P_IPV6);
385 skb->pkt_type = PACKET_HOST; 386 skb->pkt_type = PACKET_HOST;
386 tunnel->stat.rx_packets++; 387 tunnel->stat.rx_packets++;
@@ -552,6 +553,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
552 skb->h.raw = skb->nh.raw; 553 skb->h.raw = skb->nh.raw;
553 skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); 554 skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
554 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 555 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
556 IPCB(skb)->flags = 0;
555 dst_release(skb->dst); 557 dst_release(skb->dst);
556 skb->dst = &rt->u.dst; 558 skb->dst = &rt->u.dst;
557 559
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2947bc56d8a0..a25f4e8a8ada 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1153,7 +1153,7 @@ ipv6_pktoptions:
1153 return 0; 1153 return 0;
1154} 1154}
1155 1155
1156static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 1156static int tcp_v6_rcv(struct sk_buff **pskb)
1157{ 1157{
1158 struct sk_buff *skb = *pskb; 1158 struct sk_buff *skb = *pskb;
1159 struct tcphdr *th; 1159 struct tcphdr *th;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d8538dcea813..c47648892c04 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -435,7 +435,7 @@ out:
435 read_unlock(&udp_hash_lock); 435 read_unlock(&udp_hash_lock);
436} 436}
437 437
438static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 438static int udpv6_rcv(struct sk_buff **pskb)
439{ 439{
440 struct sk_buff *skb = *pskb; 440 struct sk_buff *skb = *pskb;
441 struct sock *sk; 441 struct sock *sk;
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 28c29d78338e..1ca2da68ef69 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -11,6 +11,8 @@
11 11
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/string.h> 13#include <linux/string.h>
14#include <linux/netfilter.h>
15#include <linux/netfilter_ipv6.h>
14#include <net/dsfield.h> 16#include <net/dsfield.h>
15#include <net/inet_ecn.h> 17#include <net/inet_ecn.h>
16#include <net/ip.h> 18#include <net/ip.h>
@@ -26,7 +28,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
26 IP6_ECN_set_ce(inner_iph); 28 IP6_ECN_set_ce(inner_iph);
27} 29}
28 30
29int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi) 31int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi)
30{ 32{
31 struct sk_buff *skb = *pskb; 33 struct sk_buff *skb = *pskb;
32 int err; 34 int err;
@@ -38,7 +40,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
38 int nexthdr; 40 int nexthdr;
39 unsigned int nhoff; 41 unsigned int nhoff;
40 42
41 nhoff = *nhoffp; 43 nhoff = IP6CB(skb)->nhoff;
42 nexthdr = skb->nh.raw[nhoff]; 44 nexthdr = skb->nh.raw[nhoff];
43 45
44 seq = 0; 46 seq = 0;
@@ -121,6 +123,8 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
121 skb->sp->len += xfrm_nr; 123 skb->sp->len += xfrm_nr;
122 skb->ip_summed = CHECKSUM_NONE; 124 skb->ip_summed = CHECKSUM_NONE;
123 125
126 nf_reset(skb);
127
124 if (decaps) { 128 if (decaps) {
125 if (!(skb->dev->flags&IFF_LOOPBACK)) { 129 if (!(skb->dev->flags&IFF_LOOPBACK)) {
126 dst_release(skb->dst); 130 dst_release(skb->dst);
@@ -129,7 +133,16 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
129 netif_rx(skb); 133 netif_rx(skb);
130 return -1; 134 return -1;
131 } else { 135 } else {
136#ifdef CONFIG_NETFILTER
137 skb->nh.ipv6h->payload_len = htons(skb->len);
138 __skb_push(skb, skb->data - skb->nh.raw);
139
140 NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
141 ip6_rcv_finish);
142 return -1;
143#else
132 return 1; 144 return 1;
145#endif
133 } 146 }
134 147
135drop_unlock: 148drop_unlock:
@@ -144,7 +157,7 @@ drop:
144 157
145EXPORT_SYMBOL(xfrm6_rcv_spi); 158EXPORT_SYMBOL(xfrm6_rcv_spi);
146 159
147int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 160int xfrm6_rcv(struct sk_buff **pskb)
148{ 161{
149 return xfrm6_rcv_spi(pskb, nhoffp, 0); 162 return xfrm6_rcv_spi(pskb, 0);
150} 163}
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 6b9867717d11..80242172a5df 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -9,9 +9,11 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <linux/compiler.h>
12#include <linux/skbuff.h> 13#include <linux/skbuff.h>
13#include <linux/spinlock.h> 14#include <linux/spinlock.h>
14#include <linux/icmpv6.h> 15#include <linux/icmpv6.h>
16#include <linux/netfilter_ipv6.h>
15#include <net/dsfield.h> 17#include <net/dsfield.h>
16#include <net/inet_ecn.h> 18#include <net/inet_ecn.h>
17#include <net/ipv6.h> 19#include <net/ipv6.h>
@@ -92,7 +94,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
92 return ret; 94 return ret;
93} 95}
94 96
95int xfrm6_output(struct sk_buff *skb) 97static int xfrm6_output_one(struct sk_buff *skb)
96{ 98{
97 struct dst_entry *dst = skb->dst; 99 struct dst_entry *dst = skb->dst;
98 struct xfrm_state *x = dst->xfrm; 100 struct xfrm_state *x = dst->xfrm;
@@ -110,29 +112,35 @@ int xfrm6_output(struct sk_buff *skb)
110 goto error_nolock; 112 goto error_nolock;
111 } 113 }
112 114
113 spin_lock_bh(&x->lock); 115 do {
114 err = xfrm_state_check(x, skb); 116 spin_lock_bh(&x->lock);
115 if (err) 117 err = xfrm_state_check(x, skb);
116 goto error; 118 if (err)
119 goto error;
117 120
118 xfrm6_encap(skb); 121 xfrm6_encap(skb);
119 122
120 err = x->type->output(x, skb); 123 err = x->type->output(x, skb);
121 if (err) 124 if (err)
122 goto error; 125 goto error;
123 126
124 x->curlft.bytes += skb->len; 127 x->curlft.bytes += skb->len;
125 x->curlft.packets++; 128 x->curlft.packets++;
126 129
127 spin_unlock_bh(&x->lock); 130 spin_unlock_bh(&x->lock);
128 131
129 skb->nh.raw = skb->data; 132 skb->nh.raw = skb->data;
130 133
131 if (!(skb->dst = dst_pop(dst))) { 134 if (!(skb->dst = dst_pop(dst))) {
132 err = -EHOSTUNREACH; 135 err = -EHOSTUNREACH;
133 goto error_nolock; 136 goto error_nolock;
134 } 137 }
135 err = NET_XMIT_BYPASS; 138 dst = skb->dst;
139 x = dst->xfrm;
140 } while (x && !x->props.mode);
141
142 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
143 err = 0;
136 144
137out_exit: 145out_exit:
138 return err; 146 return err;
@@ -142,3 +150,33 @@ error_nolock:
142 kfree_skb(skb); 150 kfree_skb(skb);
143 goto out_exit; 151 goto out_exit;
144} 152}
153
154static int xfrm6_output_finish(struct sk_buff *skb)
155{
156 int err;
157
158 while (likely((err = xfrm6_output_one(skb)) == 0)) {
159 nf_reset(skb);
160
161 err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, &skb, NULL,
162 skb->dst->dev, dst_output);
163 if (unlikely(err != 1))
164 break;
165
166 if (!skb->dst->xfrm)
167 return dst_output(skb);
168
169 err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
170 skb->dst->dev, xfrm6_output_finish);
171 if (unlikely(err != 1))
172 break;
173 }
174
175 return err;
176}
177
178int xfrm6_output(struct sk_buff *skb)
179{
180 return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
181 xfrm6_output_finish);
182}
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index fbef7826a74f..da09ff258648 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -397,7 +397,7 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
397 397
398EXPORT_SYMBOL(xfrm6_tunnel_deregister); 398EXPORT_SYMBOL(xfrm6_tunnel_deregister);
399 399
400static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 400static int xfrm6_tunnel_rcv(struct sk_buff **pskb)
401{ 401{
402 struct sk_buff *skb = *pskb; 402 struct sk_buff *skb = *pskb;
403 struct xfrm6_tunnel *handler = xfrm6_tunnel_handler; 403 struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
@@ -405,11 +405,11 @@ static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
405 u32 spi; 405 u32 spi;
406 406
407 /* device-like_ip6ip6_handler() */ 407 /* device-like_ip6ip6_handler() */
408 if (handler && handler->handler(pskb, nhoffp) == 0) 408 if (handler && handler->handler(pskb) == 0)
409 return 0; 409 return 0;
410 410
411 spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); 411 spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
412 return xfrm6_rcv_spi(pskb, nhoffp, spi); 412 return xfrm6_rcv_spi(pskb, spi);
413} 413}
414 414
415static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 415static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 238f1bffa684..4aa6fc60357c 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -225,6 +225,7 @@ int sctp_rcv(struct sk_buff *skb)
225 225
226 if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) 226 if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
227 goto discard_release; 227 goto discard_release;
228 nf_reset(skb);
228 229
229 ret = sk_filter(sk, skb, 1); 230 ret = sk_filter(sk, skb, 1);
230 if (ret) 231 if (ret)
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 15c05165c905..04c7fab4edc4 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -905,7 +905,7 @@ static struct inet_protosw sctpv6_stream_protosw = {
905 .flags = SCTP_PROTOSW_FLAG, 905 .flags = SCTP_PROTOSW_FLAG,
906}; 906};
907 907
908static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) 908static int sctp6_rcv(struct sk_buff **pskb)
909{ 909{
910 return sctp_rcv(*pskb) ? -1 : 0; 910 return sctp_rcv(*pskb) ? -1 : 0;
911} 911}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 24cc23af9b95..e14c1cae7460 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -495,7 +495,7 @@ rpc_depopulate(struct dentry *parent)
495repeat: 495repeat:
496 spin_lock(&dcache_lock); 496 spin_lock(&dcache_lock);
497 list_for_each_safe(pos, next, &parent->d_subdirs) { 497 list_for_each_safe(pos, next, &parent->d_subdirs) {
498 dentry = list_entry(pos, struct dentry, d_child); 498 dentry = list_entry(pos, struct dentry, d_u.d_child);
499 spin_lock(&dentry->d_lock); 499 spin_lock(&dentry->d_lock);
500 if (!d_unhashed(dentry)) { 500 if (!d_unhashed(dentry)) {
501 dget_locked(dentry); 501 dget_locked(dentry);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 64a447375fdb..59614a994b4e 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -22,6 +22,7 @@
22#include <linux/workqueue.h> 22#include <linux/workqueue.h>
23#include <linux/notifier.h> 23#include <linux/notifier.h>
24#include <linux/netdevice.h> 24#include <linux/netdevice.h>
25#include <linux/netfilter.h>
25#include <linux/module.h> 26#include <linux/module.h>
26#include <net/xfrm.h> 27#include <net/xfrm.h>
27#include <net/ip.h> 28#include <net/ip.h>
@@ -951,8 +952,8 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
951 return start; 952 return start;
952} 953}
953 954
954static int 955int
955_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) 956xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
956{ 957{
957 struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); 958 struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
958 959
@@ -963,6 +964,7 @@ _decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
963 xfrm_policy_put_afinfo(afinfo); 964 xfrm_policy_put_afinfo(afinfo);
964 return 0; 965 return 0;
965} 966}
967EXPORT_SYMBOL(xfrm_decode_session);
966 968
967static inline int secpath_has_tunnel(struct sec_path *sp, int k) 969static inline int secpath_has_tunnel(struct sec_path *sp, int k)
968{ 970{
@@ -982,8 +984,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
982 u8 fl_dir = policy_to_flow_dir(dir); 984 u8 fl_dir = policy_to_flow_dir(dir);
983 u32 sk_sid; 985 u32 sk_sid;
984 986
985 if (_decode_session(skb, &fl, family) < 0) 987 if (xfrm_decode_session(skb, &fl, family) < 0)
986 return 0; 988 return 0;
989 nf_nat_decode_session(skb, &fl, family);
987 990
988 sk_sid = security_sk_sid(sk, &fl, fl_dir); 991 sk_sid = security_sk_sid(sk, &fl, fl_dir);
989 992
@@ -1055,7 +1058,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
1055{ 1058{
1056 struct flowi fl; 1059 struct flowi fl;
1057 1060
1058 if (_decode_session(skb, &fl, family) < 0) 1061 if (xfrm_decode_session(skb, &fl, family) < 0)
1059 return 0; 1062 return 0;
1060 1063
1061 return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; 1064 return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;