mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 07:50:53 +07:00
[IPSEC] xfrm: Abstract out encapsulation modes
This patch adds the structure xfrm_mode. It is meant to represent the operations carried out by transport/tunnel modes. By doing this we allow additional encapsulation modes to be added without clogging up the xfrm_input/xfrm_output paths. Candidate modes include 4-to-6 tunnel mode, 6-to-4 tunnel mode, and BEET modes. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
546be2405b
commit
b59f45d0b2
@ -118,6 +118,10 @@ enum
|
|||||||
XFRM_SHARE_UNIQUE /* Use once */
|
XFRM_SHARE_UNIQUE /* Use once */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define XFRM_MODE_TRANSPORT 0
|
||||||
|
#define XFRM_MODE_TUNNEL 1
|
||||||
|
#define XFRM_MODE_MAX 2
|
||||||
|
|
||||||
/* Netlink configuration messages. */
|
/* Netlink configuration messages. */
|
||||||
enum {
|
enum {
|
||||||
XFRM_MSG_BASE = 0x10,
|
XFRM_MSG_BASE = 0x10,
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include <net/ip6_fib.h>
|
#include <net/ip6_fib.h>
|
||||||
|
|
||||||
#define XFRM_ALIGN8(len) (((len) + 7) & ~7)
|
#define XFRM_ALIGN8(len) (((len) + 7) & ~7)
|
||||||
|
#define MODULE_ALIAS_XFRM_MODE(family, encap) \
|
||||||
|
MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
|
||||||
|
|
||||||
extern struct sock *xfrm_nl;
|
extern struct sock *xfrm_nl;
|
||||||
extern u32 sysctl_xfrm_aevent_etime;
|
extern u32 sysctl_xfrm_aevent_etime;
|
||||||
@ -164,6 +166,7 @@ struct xfrm_state
|
|||||||
/* Reference to data common to all the instances of this
|
/* Reference to data common to all the instances of this
|
||||||
* transformer. */
|
* transformer. */
|
||||||
struct xfrm_type *type;
|
struct xfrm_type *type;
|
||||||
|
struct xfrm_mode *mode;
|
||||||
|
|
||||||
/* Security context */
|
/* Security context */
|
||||||
struct xfrm_sec_ctx *security;
|
struct xfrm_sec_ctx *security;
|
||||||
@ -205,6 +208,7 @@ struct xfrm_dst;
|
|||||||
struct xfrm_policy_afinfo {
|
struct xfrm_policy_afinfo {
|
||||||
unsigned short family;
|
unsigned short family;
|
||||||
struct xfrm_type *type_map[256];
|
struct xfrm_type *type_map[256];
|
||||||
|
struct xfrm_mode *mode_map[XFRM_MODE_MAX];
|
||||||
struct dst_ops *dst_ops;
|
struct dst_ops *dst_ops;
|
||||||
void (*garbage_collect)(void);
|
void (*garbage_collect)(void);
|
||||||
int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
|
int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
|
||||||
@ -267,6 +271,19 @@ extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family);
|
|||||||
extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family);
|
extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family);
|
||||||
extern void xfrm_put_type(struct xfrm_type *type);
|
extern void xfrm_put_type(struct xfrm_type *type);
|
||||||
|
|
||||||
|
struct xfrm_mode {
|
||||||
|
int (*input)(struct xfrm_state *x, struct sk_buff *skb);
|
||||||
|
int (*output)(struct sk_buff *skb);
|
||||||
|
|
||||||
|
struct module *owner;
|
||||||
|
unsigned int encap;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int xfrm_register_mode(struct xfrm_mode *mode, int family);
|
||||||
|
extern int xfrm_unregister_mode(struct xfrm_mode *mode, int family);
|
||||||
|
extern struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family);
|
||||||
|
extern void xfrm_put_mode(struct xfrm_mode *mode);
|
||||||
|
|
||||||
struct xfrm_tmpl
|
struct xfrm_tmpl
|
||||||
{
|
{
|
||||||
/* id in template is interpreted as:
|
/* id in template is interpreted as:
|
||||||
|
@ -414,6 +414,24 @@ config INET_TUNNEL
|
|||||||
tristate
|
tristate
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config INET_XFRM_MODE_TRANSPORT
|
||||||
|
tristate "IP: IPsec transport mode"
|
||||||
|
default y
|
||||||
|
select XFRM
|
||||||
|
---help---
|
||||||
|
Support for IPsec transport mode.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config INET_XFRM_MODE_TUNNEL
|
||||||
|
tristate "IP: IPsec tunnel mode"
|
||||||
|
default y
|
||||||
|
select XFRM
|
||||||
|
---help---
|
||||||
|
Support for IPsec tunnel mode.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
config INET_DIAG
|
config INET_DIAG
|
||||||
tristate "INET: socket monitoring interface"
|
tristate "INET: socket monitoring interface"
|
||||||
default y
|
default y
|
||||||
|
@ -24,6 +24,8 @@ obj-$(CONFIG_INET_ESP) += esp4.o
|
|||||||
obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
|
obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
|
||||||
obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
|
obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
|
||||||
obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
|
obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
|
||||||
|
obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
|
||||||
|
obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
|
||||||
obj-$(CONFIG_IP_PNP) += ipconfig.o
|
obj-$(CONFIG_IP_PNP) += ipconfig.o
|
||||||
obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
|
obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
|
||||||
obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
|
obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_ipv4.h>
|
#include <linux/netfilter_ipv4.h>
|
||||||
#include <net/inet_ecn.h>
|
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
@ -24,15 +23,6 @@ int xfrm4_rcv(struct sk_buff *skb)
|
|||||||
|
|
||||||
EXPORT_SYMBOL(xfrm4_rcv);
|
EXPORT_SYMBOL(xfrm4_rcv);
|
||||||
|
|
||||||
static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct iphdr *outer_iph = skb->nh.iph;
|
|
||||||
struct iphdr *inner_iph = skb->h.ipiph;
|
|
||||||
|
|
||||||
if (INET_ECN_is_ce(outer_iph->tos))
|
|
||||||
IP_ECN_set_ce(inner_iph);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
|
static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
|
||||||
{
|
{
|
||||||
switch (nexthdr) {
|
switch (nexthdr) {
|
||||||
@ -113,24 +103,10 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
|
|||||||
|
|
||||||
xfrm_vec[xfrm_nr++] = x;
|
xfrm_vec[xfrm_nr++] = x;
|
||||||
|
|
||||||
iph = skb->nh.iph;
|
if (x->mode->input(x, skb))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
if (x->props.mode) {
|
if (x->props.mode) {
|
||||||
if (iph->protocol != IPPROTO_IPIP)
|
|
||||||
goto drop;
|
|
||||||
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
|
|
||||||
goto drop;
|
|
||||||
if (skb_cloned(skb) &&
|
|
||||||
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
|
|
||||||
goto drop;
|
|
||||||
if (x->props.flags & XFRM_STATE_DECAP_DSCP)
|
|
||||||
ipv4_copy_dscp(iph, skb->h.ipiph);
|
|
||||||
if (!(x->props.flags & XFRM_STATE_NOECN))
|
|
||||||
ipip_ecn_decapsulate(skb);
|
|
||||||
skb->mac.raw = memmove(skb->data - skb->mac_len,
|
|
||||||
skb->mac.raw, skb->mac_len);
|
|
||||||
skb->nh.raw = skb->data;
|
|
||||||
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
|
|
||||||
decaps = 1;
|
decaps = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
69
net/ipv4/xfrm4_mode_transport.c
Normal file
69
net/ipv4/xfrm4_mode_transport.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* xfrm4_mode_transport.c - Transport mode encapsulation for IPv4.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/stringify.h>
|
||||||
|
#include <net/dst.h>
|
||||||
|
#include <net/ip.h>
|
||||||
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
|
/* Add encapsulation header.
|
||||||
|
*
|
||||||
|
* The IP header will be moved forward to make space for the encapsulation
|
||||||
|
* header.
|
||||||
|
*
|
||||||
|
* On exit, skb->h will be set to the start of the payload to be processed
|
||||||
|
* by x->type->output and skb->nh will be set to the top IP header.
|
||||||
|
*/
|
||||||
|
static int xfrm4_transport_output(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct xfrm_state *x;
|
||||||
|
struct iphdr *iph;
|
||||||
|
int ihl;
|
||||||
|
|
||||||
|
iph = skb->nh.iph;
|
||||||
|
skb->h.ipiph = iph;
|
||||||
|
|
||||||
|
ihl = iph->ihl * 4;
|
||||||
|
skb->h.raw += ihl;
|
||||||
|
|
||||||
|
x = skb->dst->xfrm;
|
||||||
|
skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xfrm_mode xfrm4_transport_mode = {
|
||||||
|
.input = xfrm4_transport_input,
|
||||||
|
.output = xfrm4_transport_output,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.encap = XFRM_MODE_TRANSPORT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init xfrm4_transport_init(void)
|
||||||
|
{
|
||||||
|
return xfrm_register_mode(&xfrm4_transport_mode, AF_INET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit xfrm4_transport_exit(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xfrm_unregister_mode(&xfrm4_transport_mode, AF_INET);
|
||||||
|
BUG_ON(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(xfrm4_transport_init);
|
||||||
|
module_exit(xfrm4_transport_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TRANSPORT);
|
125
net/ipv4/xfrm4_mode_tunnel.c
Normal file
125
net/ipv4/xfrm4_mode_tunnel.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* xfrm4_mode_tunnel.c - Tunnel mode encapsulation for IPv4.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/stringify.h>
|
||||||
|
#include <net/dst.h>
|
||||||
|
#include <net/inet_ecn.h>
|
||||||
|
#include <net/ip.h>
|
||||||
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
|
static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct iphdr *outer_iph = skb->nh.iph;
|
||||||
|
struct iphdr *inner_iph = skb->h.ipiph;
|
||||||
|
|
||||||
|
if (INET_ECN_is_ce(outer_iph->tos))
|
||||||
|
IP_ECN_set_ce(inner_iph);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add encapsulation header.
|
||||||
|
*
|
||||||
|
* The top IP header will be constructed per RFC 2401. The following fields
|
||||||
|
* in it shall be filled in by x->type->output:
|
||||||
|
* tot_len
|
||||||
|
* check
|
||||||
|
*
|
||||||
|
* On exit, skb->h will be set to the start of the payload to be processed
|
||||||
|
* by x->type->output and skb->nh will be set to the top IP header.
|
||||||
|
*/
|
||||||
|
static int xfrm4_tunnel_output(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct dst_entry *dst = skb->dst;
|
||||||
|
struct xfrm_state *x = dst->xfrm;
|
||||||
|
struct iphdr *iph, *top_iph;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
iph = skb->nh.iph;
|
||||||
|
skb->h.ipiph = iph;
|
||||||
|
|
||||||
|
skb->nh.raw = skb_push(skb, x->props.header_len);
|
||||||
|
top_iph = skb->nh.iph;
|
||||||
|
|
||||||
|
top_iph->ihl = 5;
|
||||||
|
top_iph->version = 4;
|
||||||
|
|
||||||
|
/* DS disclosed */
|
||||||
|
top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
|
||||||
|
|
||||||
|
flags = x->props.flags;
|
||||||
|
if (flags & XFRM_STATE_NOECN)
|
||||||
|
IP_ECN_clear(top_iph);
|
||||||
|
|
||||||
|
top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
|
||||||
|
0 : (iph->frag_off & htons(IP_DF));
|
||||||
|
if (!top_iph->frag_off)
|
||||||
|
__ip_select_ident(top_iph, dst->child, 0);
|
||||||
|
|
||||||
|
top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
|
||||||
|
|
||||||
|
top_iph->saddr = x->props.saddr.a4;
|
||||||
|
top_iph->daddr = x->id.daddr.a4;
|
||||||
|
top_iph->protocol = IPPROTO_IPIP;
|
||||||
|
|
||||||
|
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct iphdr *iph = skb->nh.iph;
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
|
if (iph->protocol != IPPROTO_IPIP)
|
||||||
|
goto out;
|
||||||
|
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (skb_cloned(skb) &&
|
||||||
|
(err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (x->props.flags & XFRM_STATE_DECAP_DSCP)
|
||||||
|
ipv4_copy_dscp(iph, skb->h.ipiph);
|
||||||
|
if (!(x->props.flags & XFRM_STATE_NOECN))
|
||||||
|
ipip_ecn_decapsulate(skb);
|
||||||
|
skb->mac.raw = memmove(skb->data - skb->mac_len,
|
||||||
|
skb->mac.raw, skb->mac_len);
|
||||||
|
skb->nh.raw = skb->data;
|
||||||
|
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xfrm_mode xfrm4_tunnel_mode = {
|
||||||
|
.input = xfrm4_tunnel_input,
|
||||||
|
.output = xfrm4_tunnel_output,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.encap = XFRM_MODE_TUNNEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init xfrm4_tunnel_init(void)
|
||||||
|
{
|
||||||
|
return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit xfrm4_tunnel_exit(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET);
|
||||||
|
BUG_ON(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(xfrm4_tunnel_init);
|
||||||
|
module_exit(xfrm4_tunnel_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TUNNEL);
|
@ -12,67 +12,10 @@
|
|||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/netfilter_ipv4.h>
|
#include <linux/netfilter_ipv4.h>
|
||||||
#include <net/inet_ecn.h>
|
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
#include <net/icmp.h>
|
#include <net/icmp.h>
|
||||||
|
|
||||||
/* Add encapsulation header.
|
|
||||||
*
|
|
||||||
* In transport mode, the IP header will be moved forward to make space
|
|
||||||
* for the encapsulation header.
|
|
||||||
*
|
|
||||||
* In tunnel mode, the top IP header will be constructed per RFC 2401.
|
|
||||||
* The following fields in it shall be filled in by x->type->output:
|
|
||||||
* tot_len
|
|
||||||
* check
|
|
||||||
*
|
|
||||||
* On exit, skb->h will be set to the start of the payload to be processed
|
|
||||||
* by x->type->output and skb->nh will be set to the top IP header.
|
|
||||||
*/
|
|
||||||
static void xfrm4_encap(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct dst_entry *dst = skb->dst;
|
|
||||||
struct xfrm_state *x = dst->xfrm;
|
|
||||||
struct iphdr *iph, *top_iph;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
iph = skb->nh.iph;
|
|
||||||
skb->h.ipiph = iph;
|
|
||||||
|
|
||||||
skb->nh.raw = skb_push(skb, x->props.header_len);
|
|
||||||
top_iph = skb->nh.iph;
|
|
||||||
|
|
||||||
if (!x->props.mode) {
|
|
||||||
skb->h.raw += iph->ihl*4;
|
|
||||||
memmove(top_iph, iph, iph->ihl*4);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
top_iph->ihl = 5;
|
|
||||||
top_iph->version = 4;
|
|
||||||
|
|
||||||
/* DS disclosed */
|
|
||||||
top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
|
|
||||||
|
|
||||||
flags = x->props.flags;
|
|
||||||
if (flags & XFRM_STATE_NOECN)
|
|
||||||
IP_ECN_clear(top_iph);
|
|
||||||
|
|
||||||
top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
|
|
||||||
0 : (iph->frag_off & htons(IP_DF));
|
|
||||||
if (!top_iph->frag_off)
|
|
||||||
__ip_select_ident(top_iph, dst->child, 0);
|
|
||||||
|
|
||||||
top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
|
|
||||||
|
|
||||||
top_iph->saddr = x->props.saddr.a4;
|
|
||||||
top_iph->daddr = x->id.daddr.a4;
|
|
||||||
top_iph->protocol = IPPROTO_IPIP;
|
|
||||||
|
|
||||||
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
|
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int mtu, ret = 0;
|
int mtu, ret = 0;
|
||||||
@ -121,7 +64,9 @@ static int xfrm4_output_one(struct sk_buff *skb)
|
|||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
xfrm4_encap(skb);
|
err = x->mode->output(skb);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
err = x->type->output(x, skb);
|
err = x->type->output(x, skb);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -106,6 +106,26 @@ config INET6_TUNNEL
|
|||||||
tristate
|
tristate
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config INET6_XFRM_MODE_TRANSPORT
|
||||||
|
tristate "IPv6: IPsec transport mode"
|
||||||
|
depends on IPV6
|
||||||
|
default IPV6
|
||||||
|
select XFRM
|
||||||
|
---help---
|
||||||
|
Support for IPsec transport mode.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config INET6_XFRM_MODE_TUNNEL
|
||||||
|
tristate "IPv6: IPsec tunnel mode"
|
||||||
|
depends on IPV6
|
||||||
|
default IPV6
|
||||||
|
select XFRM
|
||||||
|
---help---
|
||||||
|
Support for IPsec tunnel mode.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
config IPV6_TUNNEL
|
config IPV6_TUNNEL
|
||||||
tristate "IPv6: IPv6-in-IPv6 tunnel"
|
tristate "IPv6: IPv6-in-IPv6 tunnel"
|
||||||
select INET6_TUNNEL
|
select INET6_TUNNEL
|
||||||
|
@ -20,6 +20,8 @@ obj-$(CONFIG_INET6_ESP) += esp6.o
|
|||||||
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
|
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
|
||||||
obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
|
obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
|
||||||
obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
|
obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
|
||||||
|
obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
|
||||||
|
obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
|
||||||
obj-$(CONFIG_NETFILTER) += netfilter/
|
obj-$(CONFIG_NETFILTER) += netfilter/
|
||||||
|
|
||||||
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
|
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
#include <linux/tcp.h>
|
#include <linux/tcp.h>
|
||||||
#include <linux/route.h>
|
#include <linux/route.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_ipv6.h>
|
#include <linux/netfilter_ipv6.h>
|
||||||
@ -488,6 +489,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
|||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ip6_find_1stfragopt);
|
||||||
|
|
||||||
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
||||||
{
|
{
|
||||||
|
@ -13,21 +13,9 @@
|
|||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_ipv6.h>
|
#include <linux/netfilter_ipv6.h>
|
||||||
#include <net/dsfield.h>
|
|
||||||
#include <net/inet_ecn.h>
|
|
||||||
#include <net/ip.h>
|
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct ipv6hdr *outer_iph = skb->nh.ipv6h;
|
|
||||||
struct ipv6hdr *inner_iph = skb->h.ipv6h;
|
|
||||||
|
|
||||||
if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
|
|
||||||
IP6_ECN_set_ce(inner_iph);
|
|
||||||
}
|
|
||||||
|
|
||||||
int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
|
int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -81,21 +69,10 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
|
|||||||
|
|
||||||
xfrm_vec[xfrm_nr++] = x;
|
xfrm_vec[xfrm_nr++] = x;
|
||||||
|
|
||||||
|
if (x->mode->input(x, skb))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
if (x->props.mode) { /* XXX */
|
if (x->props.mode) { /* XXX */
|
||||||
if (nexthdr != IPPROTO_IPV6)
|
|
||||||
goto drop;
|
|
||||||
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
|
|
||||||
goto drop;
|
|
||||||
if (skb_cloned(skb) &&
|
|
||||||
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
|
|
||||||
goto drop;
|
|
||||||
if (x->props.flags & XFRM_STATE_DECAP_DSCP)
|
|
||||||
ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
|
|
||||||
if (!(x->props.flags & XFRM_STATE_NOECN))
|
|
||||||
ipip6_ecn_decapsulate(skb);
|
|
||||||
skb->mac.raw = memmove(skb->data - skb->mac_len,
|
|
||||||
skb->mac.raw, skb->mac_len);
|
|
||||||
skb->nh.raw = skb->data;
|
|
||||||
decaps = 1;
|
decaps = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
73
net/ipv6/xfrm6_mode_transport.c
Normal file
73
net/ipv6/xfrm6_mode_transport.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* xfrm6_mode_transport.c - Transport mode encapsulation for IPv6.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 USAGI/WIDE Project
|
||||||
|
* Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/stringify.h>
|
||||||
|
#include <net/dst.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
|
/* Add encapsulation header.
|
||||||
|
*
|
||||||
|
* The IP header and mutable extension headers will be moved forward to make
|
||||||
|
* space for the encapsulation header.
|
||||||
|
*
|
||||||
|
* On exit, skb->h will be set to the start of the encapsulation header to be
|
||||||
|
* filled in by x->type->output and skb->nh will be set to the nextheader field
|
||||||
|
* of the extension header directly preceding the encapsulation header, or in
|
||||||
|
* its absence, that of the top IP header. The value of skb->data will always
|
||||||
|
* point to the top IP header.
|
||||||
|
*/
|
||||||
|
static int xfrm6_transport_output(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct xfrm_state *x = skb->dst->xfrm;
|
||||||
|
struct ipv6hdr *iph;
|
||||||
|
u8 *prevhdr;
|
||||||
|
int hdr_len;
|
||||||
|
|
||||||
|
skb_push(skb, x->props.header_len);
|
||||||
|
iph = skb->nh.ipv6h;
|
||||||
|
|
||||||
|
hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
|
||||||
|
skb->nh.raw = prevhdr - x->props.header_len;
|
||||||
|
skb->h.raw = skb->data + hdr_len;
|
||||||
|
memmove(skb->data, iph, hdr_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xfrm_mode xfrm6_transport_mode = {
|
||||||
|
.input = xfrm6_transport_input,
|
||||||
|
.output = xfrm6_transport_output,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.encap = XFRM_MODE_TRANSPORT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init xfrm6_transport_init(void)
|
||||||
|
{
|
||||||
|
return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit xfrm6_transport_exit(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6);
|
||||||
|
BUG_ON(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(xfrm6_transport_init);
|
||||||
|
module_exit(xfrm6_transport_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT);
|
121
net/ipv6/xfrm6_mode_tunnel.c
Normal file
121
net/ipv6/xfrm6_mode_tunnel.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 USAGI/WIDE Project
|
||||||
|
* Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/stringify.h>
|
||||||
|
#include <net/dsfield.h>
|
||||||
|
#include <net/dst.h>
|
||||||
|
#include <net/inet_ecn.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
|
static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct ipv6hdr *outer_iph = skb->nh.ipv6h;
|
||||||
|
struct ipv6hdr *inner_iph = skb->h.ipv6h;
|
||||||
|
|
||||||
|
if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
|
||||||
|
IP6_ECN_set_ce(inner_iph);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add encapsulation header.
|
||||||
|
*
|
||||||
|
* The top IP header will be constructed per RFC 2401. The following fields
|
||||||
|
* in it shall be filled in by x->type->output:
|
||||||
|
* payload_len
|
||||||
|
*
|
||||||
|
* On exit, skb->h will be set to the start of the encapsulation header to be
|
||||||
|
* filled in by x->type->output and skb->nh will be set to the nextheader field
|
||||||
|
* of the extension header directly preceding the encapsulation header, or in
|
||||||
|
* its absence, that of the top IP header. The value of skb->data will always
|
||||||
|
* point to the top IP header.
|
||||||
|
*/
|
||||||
|
static int xfrm6_tunnel_output(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct dst_entry *dst = skb->dst;
|
||||||
|
struct xfrm_state *x = dst->xfrm;
|
||||||
|
struct ipv6hdr *iph, *top_iph;
|
||||||
|
int dsfield;
|
||||||
|
|
||||||
|
skb_push(skb, x->props.header_len);
|
||||||
|
iph = skb->nh.ipv6h;
|
||||||
|
|
||||||
|
skb->nh.raw = skb->data;
|
||||||
|
top_iph = skb->nh.ipv6h;
|
||||||
|
skb->nh.raw = &top_iph->nexthdr;
|
||||||
|
skb->h.ipv6h = top_iph + 1;
|
||||||
|
|
||||||
|
top_iph->version = 6;
|
||||||
|
top_iph->priority = iph->priority;
|
||||||
|
top_iph->flow_lbl[0] = iph->flow_lbl[0];
|
||||||
|
top_iph->flow_lbl[1] = iph->flow_lbl[1];
|
||||||
|
top_iph->flow_lbl[2] = iph->flow_lbl[2];
|
||||||
|
dsfield = ipv6_get_dsfield(top_iph);
|
||||||
|
dsfield = INET_ECN_encapsulate(dsfield, dsfield);
|
||||||
|
if (x->props.flags & XFRM_STATE_NOECN)
|
||||||
|
dsfield &= ~INET_ECN_MASK;
|
||||||
|
ipv6_change_dsfield(top_iph, 0, dsfield);
|
||||||
|
top_iph->nexthdr = IPPROTO_IPV6;
|
||||||
|
top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
|
||||||
|
ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
|
||||||
|
ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
|
if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6)
|
||||||
|
goto out;
|
||||||
|
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (skb_cloned(skb) &&
|
||||||
|
(err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (x->props.flags & XFRM_STATE_DECAP_DSCP)
|
||||||
|
ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
|
||||||
|
if (!(x->props.flags & XFRM_STATE_NOECN))
|
||||||
|
ipip6_ecn_decapsulate(skb);
|
||||||
|
skb->mac.raw = memmove(skb->data - skb->mac_len,
|
||||||
|
skb->mac.raw, skb->mac_len);
|
||||||
|
skb->nh.raw = skb->data;
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xfrm_mode xfrm6_tunnel_mode = {
|
||||||
|
.input = xfrm6_tunnel_input,
|
||||||
|
.output = xfrm6_tunnel_output,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.encap = XFRM_MODE_TUNNEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init xfrm6_tunnel_init(void)
|
||||||
|
{
|
||||||
|
return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit xfrm6_tunnel_exit(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6);
|
||||||
|
BUG_ON(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(xfrm6_tunnel_init);
|
||||||
|
module_exit(xfrm6_tunnel_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL);
|
@ -14,68 +14,9 @@
|
|||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/icmpv6.h>
|
#include <linux/icmpv6.h>
|
||||||
#include <linux/netfilter_ipv6.h>
|
#include <linux/netfilter_ipv6.h>
|
||||||
#include <net/dsfield.h>
|
|
||||||
#include <net/inet_ecn.h>
|
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
/* Add encapsulation header.
|
|
||||||
*
|
|
||||||
* In transport mode, the IP header and mutable extension headers will be moved
|
|
||||||
* forward to make space for the encapsulation header.
|
|
||||||
*
|
|
||||||
* In tunnel mode, the top IP header will be constructed per RFC 2401.
|
|
||||||
* The following fields in it shall be filled in by x->type->output:
|
|
||||||
* payload_len
|
|
||||||
*
|
|
||||||
* On exit, skb->h will be set to the start of the encapsulation header to be
|
|
||||||
* filled in by x->type->output and skb->nh will be set to the nextheader field
|
|
||||||
* of the extension header directly preceding the encapsulation header, or in
|
|
||||||
* its absence, that of the top IP header. The value of skb->data will always
|
|
||||||
* point to the top IP header.
|
|
||||||
*/
|
|
||||||
static void xfrm6_encap(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct dst_entry *dst = skb->dst;
|
|
||||||
struct xfrm_state *x = dst->xfrm;
|
|
||||||
struct ipv6hdr *iph, *top_iph;
|
|
||||||
int dsfield;
|
|
||||||
|
|
||||||
skb_push(skb, x->props.header_len);
|
|
||||||
iph = skb->nh.ipv6h;
|
|
||||||
|
|
||||||
if (!x->props.mode) {
|
|
||||||
u8 *prevhdr;
|
|
||||||
int hdr_len;
|
|
||||||
|
|
||||||
hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
|
|
||||||
skb->nh.raw = prevhdr - x->props.header_len;
|
|
||||||
skb->h.raw = skb->data + hdr_len;
|
|
||||||
memmove(skb->data, iph, hdr_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb->nh.raw = skb->data;
|
|
||||||
top_iph = skb->nh.ipv6h;
|
|
||||||
skb->nh.raw = &top_iph->nexthdr;
|
|
||||||
skb->h.ipv6h = top_iph + 1;
|
|
||||||
|
|
||||||
top_iph->version = 6;
|
|
||||||
top_iph->priority = iph->priority;
|
|
||||||
top_iph->flow_lbl[0] = iph->flow_lbl[0];
|
|
||||||
top_iph->flow_lbl[1] = iph->flow_lbl[1];
|
|
||||||
top_iph->flow_lbl[2] = iph->flow_lbl[2];
|
|
||||||
dsfield = ipv6_get_dsfield(top_iph);
|
|
||||||
dsfield = INET_ECN_encapsulate(dsfield, dsfield);
|
|
||||||
if (x->props.flags & XFRM_STATE_NOECN)
|
|
||||||
dsfield &= ~INET_ECN_MASK;
|
|
||||||
ipv6_change_dsfield(top_iph, 0, dsfield);
|
|
||||||
top_iph->nexthdr = IPPROTO_IPV6;
|
|
||||||
top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
|
|
||||||
ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
|
|
||||||
ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int xfrm6_tunnel_check_size(struct sk_buff *skb)
|
static int xfrm6_tunnel_check_size(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int mtu, ret = 0;
|
int mtu, ret = 0;
|
||||||
@ -118,7 +59,9 @@ static int xfrm6_output_one(struct sk_buff *skb)
|
|||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
xfrm6_encap(skb);
|
err = x->mode->output(skb);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
err = x->type->output(x, skb);
|
err = x->type->output(x, skb);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -138,6 +138,89 @@ void xfrm_put_type(struct xfrm_type *type)
|
|||||||
module_put(type->owner);
|
module_put(type->owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xfrm_register_mode(struct xfrm_mode *mode, int family)
|
||||||
|
{
|
||||||
|
struct xfrm_policy_afinfo *afinfo;
|
||||||
|
struct xfrm_mode **modemap;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (unlikely(mode->encap >= XFRM_MODE_MAX))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
afinfo = xfrm_policy_lock_afinfo(family);
|
||||||
|
if (unlikely(afinfo == NULL))
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
|
err = -EEXIST;
|
||||||
|
modemap = afinfo->mode_map;
|
||||||
|
if (likely(modemap[mode->encap] == NULL)) {
|
||||||
|
modemap[mode->encap] = mode;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfrm_policy_unlock_afinfo(afinfo);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(xfrm_register_mode);
|
||||||
|
|
||||||
|
int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
|
||||||
|
{
|
||||||
|
struct xfrm_policy_afinfo *afinfo;
|
||||||
|
struct xfrm_mode **modemap;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (unlikely(mode->encap >= XFRM_MODE_MAX))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
afinfo = xfrm_policy_lock_afinfo(family);
|
||||||
|
if (unlikely(afinfo == NULL))
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
|
err = -ENOENT;
|
||||||
|
modemap = afinfo->mode_map;
|
||||||
|
if (likely(modemap[mode->encap] == mode)) {
|
||||||
|
modemap[mode->encap] = NULL;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfrm_policy_unlock_afinfo(afinfo);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(xfrm_unregister_mode);
|
||||||
|
|
||||||
|
struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
|
||||||
|
{
|
||||||
|
struct xfrm_policy_afinfo *afinfo;
|
||||||
|
struct xfrm_mode *mode;
|
||||||
|
int modload_attempted = 0;
|
||||||
|
|
||||||
|
if (unlikely(encap >= XFRM_MODE_MAX))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
afinfo = xfrm_policy_get_afinfo(family);
|
||||||
|
if (unlikely(afinfo == NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mode = afinfo->mode_map[encap];
|
||||||
|
if (unlikely(mode && !try_module_get(mode->owner)))
|
||||||
|
mode = NULL;
|
||||||
|
if (!mode && !modload_attempted) {
|
||||||
|
xfrm_policy_put_afinfo(afinfo);
|
||||||
|
request_module("xfrm-mode-%d-%d", family, encap);
|
||||||
|
modload_attempted = 1;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfrm_policy_put_afinfo(afinfo);
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xfrm_put_mode(struct xfrm_mode *mode)
|
||||||
|
{
|
||||||
|
module_put(mode->owner);
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned long make_jiffies(long secs)
|
static inline unsigned long make_jiffies(long secs)
|
||||||
{
|
{
|
||||||
if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
|
if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
|
||||||
|
@ -77,6 +77,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
|
|||||||
kfree(x->ealg);
|
kfree(x->ealg);
|
||||||
kfree(x->calg);
|
kfree(x->calg);
|
||||||
kfree(x->encap);
|
kfree(x->encap);
|
||||||
|
if (x->mode)
|
||||||
|
xfrm_put_mode(x->mode);
|
||||||
if (x->type) {
|
if (x->type) {
|
||||||
x->type->destructor(x);
|
x->type->destructor(x);
|
||||||
xfrm_put_type(x->type);
|
xfrm_put_type(x->type);
|
||||||
@ -1193,6 +1195,10 @@ int xfrm_init_state(struct xfrm_state *x)
|
|||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
x->mode = xfrm_get_mode(x->props.mode, family);
|
||||||
|
if (x->mode == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
x->km.state = XFRM_STATE_VALID;
|
x->km.state = XFRM_STATE_VALID;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
Loading…
Reference in New Issue
Block a user