5 * YOSHIFUJI Hideaki @USAGI
6 * Split up af-specific portion
7 * Derek Atkins <derek@ihtfp.com>
8 * Add Encapsulation support
12 #include <linux/module.h>
13 #include <linux/string.h>
14 #include <linux/netfilter.h>
15 #include <linux/netfilter_ipv4.h>
19 int xfrm4_rcv(struct sk_buff
*skb
)
21 return xfrm4_rcv_encap(skb
, 0);
24 EXPORT_SYMBOL(xfrm4_rcv
);
26 static int xfrm4_parse_spi(struct sk_buff
*skb
, u8 nexthdr
, __be32
*spi
, __be32
*seq
)
31 *spi
= ip_hdr(skb
)->saddr
;
36 return xfrm_parse_spi(skb
, nexthdr
, spi
, seq
);
39 #ifdef CONFIG_NETFILTER
40 static inline int xfrm4_rcv_encap_finish(struct sk_buff
*skb
)
42 if (skb
->dst
== NULL
) {
43 const struct iphdr
*iph
= ip_hdr(skb
);
45 if (ip_route_input(skb
, iph
->daddr
, iph
->saddr
, iph
->tos
,
49 return dst_input(skb
);
56 int xfrm4_rcv_encap(struct sk_buff
*skb
, __u16 encap_type
)
59 struct xfrm_state
*xfrm_vec
[XFRM_MAX_DEPTH
];
63 int err
= xfrm4_parse_spi(skb
, ip_hdr(skb
)->protocol
, &spi
, &seq
);
69 const struct iphdr
*iph
= ip_hdr(skb
);
71 if (xfrm_nr
== XFRM_MAX_DEPTH
)
74 x
= xfrm_state_lookup((xfrm_address_t
*)&iph
->daddr
, spi
,
75 iph
->protocol
!= IPPROTO_IPV6
? iph
->protocol
: IPPROTO_IPIP
, AF_INET
);
80 if (unlikely(x
->km
.state
!= XFRM_STATE_VALID
))
83 if ((x
->encap
? x
->encap
->encap_type
: 0) != encap_type
)
86 if (x
->props
.replay_window
&& xfrm_replay_check(x
, seq
))
89 if (xfrm_state_check_expire(x
))
92 if (x
->type
->input(x
, skb
))
95 /* only the first xfrm gets the encap type */
98 if (x
->props
.replay_window
)
99 xfrm_replay_advance(x
, seq
);
101 x
->curlft
.bytes
+= skb
->len
;
104 spin_unlock(&x
->lock
);
106 xfrm_vec
[xfrm_nr
++] = x
;
108 if (x
->mode
->input(x
, skb
))
111 if (x
->props
.mode
== XFRM_MODE_TUNNEL
) {
116 err
= xfrm_parse_spi(skb
, ip_hdr(skb
)->protocol
, &spi
, &seq
);
121 /* Allocate new secpath or COW existing one. */
123 if (!skb
->sp
|| atomic_read(&skb
->sp
->refcnt
) != 1) {
125 sp
= secpath_dup(skb
->sp
);
129 secpath_put(skb
->sp
);
132 if (xfrm_nr
+ skb
->sp
->len
> XFRM_MAX_DEPTH
)
135 memcpy(skb
->sp
->xvec
+ skb
->sp
->len
, xfrm_vec
,
136 xfrm_nr
* sizeof(xfrm_vec
[0]));
137 skb
->sp
->len
+= xfrm_nr
;
142 if (!(skb
->dev
->flags
&IFF_LOOPBACK
)) {
143 dst_release(skb
->dst
);
149 #ifdef CONFIG_NETFILTER
150 __skb_push(skb
, skb
->data
- skb_network_header(skb
));
151 ip_hdr(skb
)->tot_len
= htons(skb
->len
);
152 ip_send_check(ip_hdr(skb
));
154 NF_HOOK(PF_INET
, NF_IP_PRE_ROUTING
, skb
, skb
->dev
, NULL
,
155 xfrm4_rcv_encap_finish
);
158 return -ip_hdr(skb
)->protocol
;
163 spin_unlock(&x
->lock
);
166 while (--xfrm_nr
>= 0)
167 xfrm_state_put(xfrm_vec
[xfrm_nr
]);