[IPSEC]: Kill post_input hook and do NAT-T in esp_input directly

The only reason post_input exists at all is that it gives us the
potential to adjust the checksums incrementally in future which
we ought to do.

However, after thinking about it for a bit we can adjust the
checksums without using this post_input stuff at all.  The crucial
point is that only the inner-most NAT-T SA needs to be considered
when adjusting checksums.  What's more, the checksum adjustment
comes down to a single u32 due to the linearity of IP checksums.

We just happen to have a spare u32 lying around in our skb structure :)
When ip_summed is set to CHECKSUM_NONE on input, the value of skb->csum
is currently unused.  All we have to do is to make that the checksum
adjustment and voila, there goes all the post_input and decap structures!

I've left in the decap data structures for now since it's intricately
woven into the sec_path stuff.  We can kill them later too.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Herbert Xu 2006-02-27 13:00:40 -08:00 committed by David S. Miller
parent 4bf05eceec
commit 752c1f4c78
3 changed files with 38 additions and 98 deletions

View file

@ -233,7 +233,6 @@ struct xfrm_type
int (*init_state)(struct xfrm_state *x);
void (*destructor)(struct xfrm_state *);
int (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
int (*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
/* Estimate maximal size of result of transformation of a dgram */
u32 (*get_max_size)(struct xfrm_state *, int size);

View file

@ -12,13 +12,6 @@
#include <net/protocol.h>
#include <net/udp.h>
/* decapsulation data for use when post-processing */
struct esp_decap_data {
xfrm_address_t saddr;
__u16 sport;
__u8 proto;
};
static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
@ -210,72 +203,28 @@ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc
/* ... check padding bits here. Silly. :-) */
if (x->encap && decap && decap->decap_type) {
struct esp_decap_data *encap_data;
struct udphdr *uh = (struct udphdr *) (iph+1);
encap_data = (struct esp_decap_data *) (decap->decap_data);
encap_data->proto = 0;
switch (decap->decap_type) {
case UDP_ENCAP_ESPINUDP:
case UDP_ENCAP_ESPINUDP_NON_IKE:
encap_data->proto = AF_INET;
encap_data->saddr.a4 = iph->saddr;
encap_data->sport = uh->source;
encap_len = (void*)esph - (void*)uh;
break;
default:
goto out;
}
}
iph->protocol = nexthdr[1];
pskb_trim(skb, skb->len - alen - padlen - 2);
memcpy(workbuf, skb->nh.raw, iph->ihl*4);
skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
memcpy(skb->nh.raw, workbuf, iph->ihl*4);
skb->nh.iph->tot_len = htons(skb->len);
return 0;
out:
return -EINVAL;
}
static int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
{
if (x->encap) {
struct xfrm_encap_tmpl *encap;
struct esp_decap_data *decap_data;
struct xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh;
encap = x->encap;
decap_data = (struct esp_decap_data *)(decap->decap_data);
/* first, make sure that the decap type == the encap type */
if (encap->encap_type != decap->decap_type)
return -EINVAL;
goto out;
uh = (struct udphdr *)(iph + 1);
encap_len = (void*)esph - (void*)uh;
switch (encap->encap_type) {
default:
case UDP_ENCAP_ESPINUDP:
case UDP_ENCAP_ESPINUDP_NON_IKE:
/*
* 1) if the NAT-T peer's IP or port changed then
* advertize the change to the keying daemon.
* This is an inbound SA, so just compare
* SRC ports.
*/
if (decap_data->proto == AF_INET &&
(decap_data->saddr.a4 != x->props.saddr.a4 ||
decap_data->sport != encap->encap_sport)) {
if (iph->saddr != x->props.saddr.a4 ||
uh->source != encap->encap_sport) {
xfrm_address_t ipaddr;
ipaddr.a4 = decap_data->saddr.a4;
km_new_mapping(x, &ipaddr, decap_data->sport);
ipaddr.a4 = iph->saddr;
km_new_mapping(x, &ipaddr, uh->source);
/* XXX: perhaps add an extra
* policy check here, to see
@ -290,16 +239,25 @@ static int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap,
* 2) ignore UDP/TCP checksums in case
* of NAT-T in Transport Mode, or
* perform other post-processing fixes
* as per * draft-ietf-ipsec-udp-encaps-06,
* as per draft-ietf-ipsec-udp-encaps-06,
* section 3.1.2
*/
if (!x->props.mode)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
iph->protocol = nexthdr[1];
pskb_trim(skb, skb->len - alen - padlen - 2);
memcpy(workbuf, skb->nh.raw, iph->ihl*4);
skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
memcpy(skb->nh.raw, workbuf, iph->ihl*4);
skb->nh.iph->tot_len = htons(skb->len);
break;
}
}
return 0;
out:
return -EINVAL;
}
static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
@ -457,7 +415,6 @@ static struct xfrm_type esp_type =
.destructor = esp_destroy,
.get_max_size = esp4_get_max_size,
.input = esp_input,
.post_input = esp_post_input,
.output = esp_output
};
@ -469,15 +426,6 @@ static struct net_protocol esp4_protocol = {
static int __init esp4_init(void)
{
struct xfrm_decap_state decap;
if (sizeof(struct esp_decap_data) >
sizeof(decap.decap_data)) {
extern void decap_data_too_small(void);
decap_data_too_small();
}
if (xfrm_register_type(&esp_type, AF_INET) < 0) {
printk(KERN_INFO "ip esp init: can't add xfrm type\n");
return -EAGAIN;

View file

@ -996,13 +996,6 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
struct sec_decap_state *xvec = &(skb->sp->x[i]);
if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family))
return 0;
/* If there is a post_input processor, try running it */
if (xvec->xvec->type->post_input &&
(xvec->xvec->type->post_input)(xvec->xvec,
&(xvec->decap),
skb) != 0)
return 0;
}
}