Commit 1df07fe0 authored by David S. Miller's avatar David S. Miller

Merge http://bk.skbuff.net:20608/linux-2.6-xfrm6tunnel

into nuts.davemloft.net:/disk1/BK/net-2.6
parents 29a54a41 b55ee909
......@@ -497,10 +497,6 @@ xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
return 0;
}
/* placeholder until xfrm6_tunnel.c is written */
static inline int xfrm6_tunnel_check_size(struct sk_buff *skb)
{ return 0; }
/* A struct encoding bundle of transformations to apply to some set of flow.
*
* dst->child points to the next element of bundle.
......@@ -783,6 +779,12 @@ struct xfrm_tunnel {
void (*err_handler)(struct sk_buff *skb, void *info);
};
struct xfrm6_tunnel {
int (*handler)(struct sk_buff **pskb, unsigned int *nhoffp);
void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info);
};
extern void xfrm_init(void);
extern void xfrm4_init(void);
extern void xfrm4_fini(void);
......@@ -793,6 +795,8 @@ extern void xfrm4_state_init(void);
extern void xfrm4_state_fini(void);
extern void xfrm6_state_init(void);
extern void xfrm6_state_fini(void);
extern void xfrm6_tunnel_init(void);
extern void xfrm6_tunnel_fini(void);
extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *);
extern struct xfrm_state *xfrm_state_alloc(void);
......@@ -812,12 +816,18 @@ extern void xfrm_state_flush(u8 proto);
extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
extern int xfrm_check_output(struct xfrm_state *x, struct sk_buff *skb, unsigned short family);
extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_check_size(struct sk_buff *skb);
extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
extern int xfrm6_tunnel_check_size(struct sk_buff *skb);
extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
#ifdef CONFIG_XFRM
extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
......
......@@ -74,12 +74,15 @@ static int ah_output(struct sk_buff **pskb)
}
spin_lock_bh(&x->lock);
err = xfrm_check_output(x, *pskb, AF_INET);
err = xfrm_state_check(x, *pskb);
if (err)
goto error;
iph = (*pskb)->nh.iph;
if (x->props.mode) {
err = xfrm4_tunnel_check_size(*pskb);
if (err)
goto error;
top_iph = (struct iphdr*)skb_push(*pskb, x->props.header_len);
top_iph->ihl = 5;
top_iph->version = 4;
......
......@@ -49,19 +49,24 @@ int esp_output(struct sk_buff **pskb)
}
spin_lock_bh(&x->lock);
err = xfrm_check_output(x, *pskb, AF_INET);
err = xfrm_state_check(x, *pskb);
if (err)
goto error;
err = -ENOMEM;
/* Strip IP header in transport mode. Save it. */
if (!x->props.mode) {
if (x->props.mode) {
err = xfrm4_tunnel_check_size(*pskb);
if (err)
goto error;
} else {
/* Strip IP header in transport mode. Save it. */
iph = (*pskb)->nh.iph;
memcpy(&tmp_iph, iph, iph->ihl*4);
__skb_pull(*pskb, iph->ihl*4);
}
/* Now skb is pure payload to encrypt */
err = -ENOMEM;
/* Round to block size */
clen = (*pskb)->len;
......
......@@ -164,12 +164,16 @@ static int ipcomp_output(struct sk_buff **pskb)
}
spin_lock_bh(&x->lock);
err = xfrm_check_output(x, *pskb, AF_INET);
err = xfrm_state_check(x, *pskb);
if (err)
goto error;
/* Don't bother compressing */
if (!x->props.mode) {
if (x->props.mode) {
err = xfrm4_tunnel_check_size(*pskb);
if (err)
goto error;
} else {
/* Don't bother compressing */
iph = (*pskb)->nh.iph;
hdr_len = iph->ihl * 4;
}
......
......@@ -10,7 +10,8 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
ip6_flowlabel.o ipv6_syms.o
ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o
ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
xfrm6_tunnel.o
ipv6-objs += $(ipv6-y)
obj-$(CONFIG_INET6_AH) += ah6.o
......
......@@ -163,11 +163,15 @@ int ah6_output(struct sk_buff **pskb)
}
spin_lock_bh(&x->lock);
err = xfrm_check_output(x, *pskb, AF_INET6);
err = xfrm_state_check(x, *pskb);
if (err)
goto error;
if (x->props.mode) {
err = xfrm6_tunnel_check_size(*pskb);
if (err)
goto error;
iph = (*pskb)->nh.ipv6h;
(*pskb)->nh.ipv6h = (struct ipv6hdr*)skb_push(*pskb, x->props.header_len);
(*pskb)->nh.ipv6h->version = 6;
......
......@@ -65,14 +65,16 @@ int esp6_output(struct sk_buff **pskb)
}
spin_lock_bh(&x->lock);
err = xfrm_check_output(x, *pskb, AF_INET6);
err = xfrm_state_check(x, *pskb);
if (err)
goto error;
err = -ENOMEM;
/* Strip IP header in transport mode. Save it. */
if (!x->props.mode) {
if (x->props.mode) {
err = xfrm6_tunnel_check_size(*pskb);
if (err)
goto error;
} else {
/* Strip IP header in transport mode. Save it. */
hdr_len = ip6_find_1stfragopt(*pskb, &prevhdr);
nexthdr = *prevhdr;
*prevhdr = IPPROTO_ESP;
......@@ -86,6 +88,7 @@ int esp6_output(struct sk_buff **pskb)
}
/* Now skb is pure payload to encrypt */
err = -ENOMEM;
/* Round to block size */
clen = (*pskb)->len;
......
......@@ -123,7 +123,7 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
* else %NULL
**/
struct ip6_tnl *
static struct ip6_tnl *
ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
{
unsigned h0 = HASH(remote);
......@@ -387,8 +387,9 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
* to the specifications in RFC 2473.
**/
void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
static void
ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
struct ip6_tnl *t;
......@@ -496,7 +497,8 @@ void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
* Return: 0
**/
int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
static int
ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
{
struct sk_buff *skb = *pskb;
struct ipv6hdr *ipv6h;
......@@ -510,6 +512,11 @@ int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
read_lock(&ip6ip6_lock);
if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
kfree_skb(skb);
return 0;
}
if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) {
t->stat.rx_dropped++;
read_unlock(&ip6ip6_lock);
......@@ -533,8 +540,7 @@ int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
read_unlock(&ip6ip6_lock);
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
discard:
kfree_skb(skb);
return 0;
return 1;
}
static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
......@@ -598,7 +604,8 @@ ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
* 0
**/
int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
static int
ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
struct net_device_stats *stats = &t->stat;
......@@ -1079,7 +1086,8 @@ ip6ip6_tnl_dev_init(struct net_device *dev)
* Return: 0
**/
int ip6ip6_fb_tnl_dev_init(struct net_device *dev)
static int
ip6ip6_fb_tnl_dev_init(struct net_device *dev)
{
struct ip6_tnl *t = dev->priv;
ip6ip6_tnl_dev_init_gen(dev);
......@@ -1088,10 +1096,9 @@ int ip6ip6_fb_tnl_dev_init(struct net_device *dev)
return 0;
}
static struct inet6_protocol ip6ip6_protocol = {
static struct xfrm6_tunnel ip6ip6_handler = {
.handler = ip6ip6_rcv,
.err_handler = ip6ip6_err,
.flags = INET6_PROTO_FINAL
};
/**
......@@ -1104,9 +1111,9 @@ static int __init ip6_tunnel_init(void)
{
int err;
if ((err = inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6)) < 0) {
printk(KERN_ERR "Failed to register IPv6 protocol\n");
return err;
if (xfrm6_tunnel_register(&ip6ip6_handler) < 0) {
printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
return -EAGAIN;
}
ip6ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
ip6ip6_tnl_dev_setup);
......@@ -1123,7 +1130,7 @@ static int __init ip6_tunnel_init(void)
}
return 0;
fail:
inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6);
xfrm6_tunnel_deregister(&ip6ip6_handler);
return err;
}
......@@ -1133,8 +1140,10 @@ static int __init ip6_tunnel_init(void)
static void __exit ip6_tunnel_cleanup(void)
{
if (xfrm6_tunnel_deregister(&ip6ip6_handler) < 0)
printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
unregister_netdev(ip6ip6_fb_tnl_dev);
inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6);
}
module_init(ip6_tunnel_init);
......
......@@ -140,11 +140,15 @@ static int ipcomp6_output(struct sk_buff **pskb)
spin_lock_bh(&x->lock);
err = xfrm_check_output(x, *pskb, AF_INET6);
err = xfrm_state_check(x, *pskb);
if (err)
goto error;
if (x->props.mode) {
err = xfrm6_tunnel_check_size(*pskb);
if (err)
goto error;
hdr_len = sizeof(struct ipv6hdr);
nexthdr = IPPROTO_IPV6;
iph = (*pskb)->nh.ipv6h;
......@@ -258,6 +262,66 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
xfrm_state_put(x);
}
static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
{
struct xfrm_state *t = NULL;
t = xfrm_state_alloc();
if (!t)
goto out;
t->id.proto = IPPROTO_IPV6;
t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr);
memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
memcpy(&t->sel, &x->sel, sizeof(t->sel));
t->props.family = AF_INET6;
t->props.mode = 1;
memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
t->type = xfrm_get_type(IPPROTO_IPV6, t->props.family);
if (t->type == NULL)
goto error;
if (t->type->init_state(t, NULL))
goto error;
t->km.state = XFRM_STATE_VALID;
atomic_set(&t->tunnel_users, 1);
out:
return t;
error:
xfrm_state_put(t);
goto out;
}
static int ipcomp6_tunnel_attach(struct xfrm_state *x)
{
int err = 0;
struct xfrm_state *t = NULL;
u32 spi;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
if (spi)
t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr,
spi, IPPROTO_IPV6, AF_INET6);
if (!t) {
t = ipcomp6_tunnel_create(x);
if (!t) {
err = -EINVAL;
goto out;
}
xfrm_state_insert(t);
xfrm_state_hold(t);
}
x->tunnel = t;
atomic_inc(&t->tunnel_users);
out:
return err;
}
static void ipcomp6_free_data(struct ipcomp_data *ipcd)
{
if (ipcd->tfm)
......@@ -271,8 +335,11 @@ static void ipcomp6_destroy(struct xfrm_state *x)
struct ipcomp_data *ipcd = x->data;
if (!ipcd)
return;
xfrm_state_delete_tunnel(x);
ipcomp6_free_data(ipcd);
kfree(ipcd);
xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
}
static int ipcomp6_init_state(struct xfrm_state *x, void *args)
......@@ -303,6 +370,12 @@ static int ipcomp6_init_state(struct xfrm_state *x, void *args)
if (!ipcd->tfm)
goto error;
if (x->props.mode) {
err = ipcomp6_tunnel_attach(x);
if (err)
goto error;
}
calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
BUG_ON(!calg_desc);
ipcd->threshold = calg_desc->uinfo.comp.threshold;
......
......@@ -277,10 +277,12 @@ void __init xfrm6_init(void)
{
xfrm6_policy_init();
xfrm6_state_init();
xfrm6_tunnel_init();
}
void __exit xfrm6_fini(void)
{
xfrm6_tunnel_fini();
//xfrm6_input_fini();
xfrm6_policy_fini();
xfrm6_state_fini();
......
This diff is collapsed.
......@@ -2,7 +2,7 @@
# Makefile for the XFRM subsystem.
#
obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o xfrm_output.o \
obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o \
xfrm_export.o
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
......@@ -18,6 +18,7 @@ EXPORT_SYMBOL(xfrm_state_add);
EXPORT_SYMBOL(xfrm_state_update);
EXPORT_SYMBOL(xfrm_state_check_expire);
EXPORT_SYMBOL(xfrm_state_check_space);
EXPORT_SYMBOL(xfrm_state_check);
EXPORT_SYMBOL(xfrm_state_lookup);
EXPORT_SYMBOL(xfrm_state_register_afinfo);
EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
......@@ -27,7 +28,6 @@ EXPORT_SYMBOL(xfrm_state_delete_tunnel);
EXPORT_SYMBOL(xfrm_replay_check);
EXPORT_SYMBOL(xfrm_replay_advance);
EXPORT_SYMBOL(xfrm_check_selectors);
EXPORT_SYMBOL(xfrm_check_output);
EXPORT_SYMBOL(__secpath_destroy);
EXPORT_SYMBOL(secpath_dup);
EXPORT_SYMBOL(xfrm_get_acqseq);
......
/*
* generic xfrm output routines
*
* Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <net/xfrm.h>
int xfrm_check_output(struct xfrm_state *x,
struct sk_buff *skb, unsigned short family)
{
int err;
err = xfrm_state_check_expire(x);
if (err)
goto out;
if (x->props.mode) {
switch (family) {
case AF_INET:
err = xfrm4_tunnel_check_size(skb);
break;
case AF_INET6:
err = xfrm6_tunnel_check_size(skb);
break;
default:
err = -EINVAL;
}
if (err)
goto out;
}
err = xfrm_state_check_space(x, skb);
out:
return err;
}
......@@ -531,6 +531,16 @@ int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
return 0;
}
int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
{
int err = xfrm_state_check_expire(x);
if (err < 0)
goto err;
err = xfrm_state_check_space(x, skb);
err:
return err;
}
struct xfrm_state *
xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
unsigned short family)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment