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
= skb
->nh
.iph
->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 struct iphdr
*iph
= skb
->nh
.iph
;
44 if (skb
->dst
== NULL
) {
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
)
60 struct xfrm_state
*xfrm_vec
[XFRM_MAX_DEPTH
];
65 if ((err
= xfrm4_parse_spi(skb
, skb
->nh
.iph
->protocol
, &spi
, &seq
)) != 0)
69 struct iphdr
*iph
= skb
->nh
.iph
;
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 if ((err
= xfrm_parse_spi(skb
, skb
->nh
.iph
->protocol
, &spi
, &seq
)) < 0)
120 /* Allocate new secpath or COW existing one. */
122 if (!skb
->sp
|| atomic_read(&skb
->sp
->refcnt
) != 1) {
124 sp
= secpath_dup(skb
->sp
);
128 secpath_put(skb
->sp
);
131 if (xfrm_nr
+ skb
->sp
->len
> XFRM_MAX_DEPTH
)
134 memcpy(skb
->sp
->xvec
+ skb
->sp
->len
, xfrm_vec
,
135 xfrm_nr
* sizeof(xfrm_vec
[0]));
136 skb
->sp
->len
+= xfrm_nr
;
141 if (!(skb
->dev
->flags
&IFF_LOOPBACK
)) {
142 dst_release(skb
->dst
);
148 #ifdef CONFIG_NETFILTER
149 __skb_push(skb
, skb
->data
- skb
->nh
.raw
);
150 skb
->nh
.iph
->tot_len
= htons(skb
->len
);
151 ip_send_check(skb
->nh
.iph
);
153 NF_HOOK(PF_INET
, NF_IP_PRE_ROUTING
, skb
, skb
->dev
, NULL
,
154 xfrm4_rcv_encap_finish
);
157 return -skb
->nh
.iph
->protocol
;
162 spin_unlock(&x
->lock
);
165 while (--xfrm_nr
>= 0)
166 xfrm_state_put(xfrm_vec
[xfrm_nr
]);