Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
0d51db7b
Commit
0d51db7b
authored
Jun 19, 2004
by
Hideaki Yoshifuji
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[IPV6] XFRM: support (uncompressed) tunnel mode ipcomp6 using xfrm6_tunnel infrastructure.
parent
b4c8b9eb
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
719 additions
and
14 deletions
+719
-14
include/net/xfrm.h
include/net/xfrm.h
+14
-4
net/ipv6/Makefile
net/ipv6/Makefile
+2
-1
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_tunnel.c
+9
-9
net/ipv6/ipcomp6.c
net/ipv6/ipcomp6.c
+69
-0
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_policy.c
+2
-0
net/ipv6/xfrm6_tunnel.c
net/ipv6/xfrm6_tunnel.c
+623
-0
No files found.
include/net/xfrm.h
View file @
0d51db7b
...
...
@@ -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
);
...
...
@@ -818,6 +822,12 @@ 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
);
...
...
net/ipv6/Makefile
View file @
0d51db7b
...
...
@@ -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
...
...
net/ipv6/ip6_tunnel.c
View file @
0d51db7b
...
...
@@ -540,8 +540,7 @@ 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
)
...
...
@@ -1097,10 +1096,9 @@ 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
};
/**
...
...
@@ -1113,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 protoco
l
\n
"
);
return
err
;
if
(
xfrm6_tunnel_register
(
&
ip6ip6_handler
)
<
0
)
{
printk
(
KERN_ERR
"
ip6ip6 init: can't register tunne
l
\n
"
);
return
-
EAGAIN
;
}
ip6ip6_fb_tnl_dev
=
alloc_netdev
(
sizeof
(
struct
ip6_tnl
),
"ip6tnl0"
,
ip6ip6_tnl_dev_setup
);
...
...
@@ -1132,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
;
}
...
...
@@ -1142,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
);
...
...
net/ipv6/ipcomp6.c
View file @
0d51db7b
...
...
@@ -258,6 +258,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 +331,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 +366,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
;
...
...
net/ipv6/xfrm6_policy.c
View file @
0d51db7b
...
...
@@ -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
();
...
...
net/ipv6/xfrm6_tunnel.c
0 → 100644
View file @
0d51db7b
/*
* Copyright (C)2003,2004 USAGI/WIDE Project
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors Mitsuru KANDA <mk@linux-ipv6.org>
* YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
*
* Based on net/ipv4/xfrm4_tunnel.c
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/xfrm.h>
#include <linux/list.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
#include <net/ipv6.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
# define X6TDEBUG 3
#else
# define X6TDEBUG 1
#endif
#define X6TPRINTK(fmt, args...) printk(fmt, ## args)
#define X6TNOPRINTK(fmt, args...) do { ; } while(0)
#if X6TDEBUG >= 1
# define X6TPRINTK1 X6TPRINTK
#else
# define X6TPRINTK1 X6TNOPRINTK
#endif
#if X6TDEBUG >= 3
# define X6TPRINTK3 X6TPRINTK
#else
# define X6TPRINTK3 X6TNOPRINTK
#endif
/*
* xfrm_tunnel_spi things are for allocating unique id ("spi")
* per xfrm_address_t.
*/
struct
xfrm6_tunnel_spi
{
struct
hlist_node
list_byaddr
;
struct
hlist_node
list_byspi
;
xfrm_address_t
addr
;
u32
spi
;
atomic_t
refcnt
;
#ifdef XFRM6_TUNNEL_SPI_MAGIC
u32
magic
;
#endif
};
#ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
# define XFRM6_TUNNEL_SPI_MAGIC 0xdeadbeef
#endif
static
rwlock_t
xfrm6_tunnel_spi_lock
=
RW_LOCK_UNLOCKED
;
static
u32
xfrm6_tunnel_spi
;
#define XFRM6_TUNNEL_SPI_MIN 1
#define XFRM6_TUNNEL_SPI_MAX 0xffffffff
static
kmem_cache_t
*
xfrm6_tunnel_spi_kmem
;
#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
static
struct
hlist_head
xfrm6_tunnel_spi_byaddr
[
XFRM6_TUNNEL_SPI_BYADDR_HSIZE
];
static
struct
hlist_head
xfrm6_tunnel_spi_byspi
[
XFRM6_TUNNEL_SPI_BYSPI_HSIZE
];
#ifdef XFRM6_TUNNEL_SPI_MAGIC
static
int
x6spi_check_magic
(
const
struct
xfrm6_tunnel_spi
*
x6spi
,
const
char
*
name
)
{
if
(
unlikely
(
x6spi
->
magic
!=
XFRM6_TUNNEL_SPI_MAGIC
))
{
X6TPRINTK3
(
KERN_DEBUG
"%s(): x6spi object "
"at %p has corrupted magic %08x "
"(should be %08x)
\n
"
,
name
,
x6spi
,
x6spi
->
magic
,
XFRM6_TUNNEL_SPI_MAGIC
);
return
-
1
;
}
return
0
;
}
#else
static
int
inline
x6spi_check_magic
(
const
struct
xfrm6_tunnel_spi
*
x6spi
,
const
char
*
name
)
{
return
0
;
}
#endif
#define X6SPI_CHECK_MAGIC(x6spi) x6spi_check_magic((x6spi), __FUNCTION__)
static
unsigned
inline
xfrm6_tunnel_spi_hash_byaddr
(
xfrm_address_t
*
addr
)
{
unsigned
h
;
X6TPRINTK3
(
KERN_DEBUG
"%s(addr=%p)
\n
"
,
__FUNCTION__
,
addr
);
h
=
addr
->
a6
[
0
]
^
addr
->
a6
[
1
]
^
addr
->
a6
[
2
]
^
addr
->
a6
[
3
];
h
^=
h
>>
16
;
h
^=
h
>>
8
;
h
&=
XFRM6_TUNNEL_SPI_BYADDR_HSIZE
-
1
;
X6TPRINTK3
(
KERN_DEBUG
"%s() = %u
\n
"
,
__FUNCTION__
,
h
);
return
h
;
}
static
unsigned
inline
xfrm6_tunnel_spi_hash_byspi
(
u32
spi
)
{
return
spi
%
XFRM6_TUNNEL_SPI_BYSPI_HSIZE
;
}
static
int
xfrm6_tunnel_spi_init
(
void
)
{
int
i
;
X6TPRINTK3
(
KERN_DEBUG
"%s()
\n
"
,
__FUNCTION__
);
xfrm6_tunnel_spi
=
0
;
xfrm6_tunnel_spi_kmem
=
kmem_cache_create
(
"xfrm6_tunnel_spi"
,
sizeof
(
struct
xfrm6_tunnel_spi
),
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
if
(
!
xfrm6_tunnel_spi_kmem
)
{
X6TPRINTK1
(
KERN_ERR
"%s(): failed to allocate xfrm6_tunnel_spi_kmem
\n
"
,
__FUNCTION__
);
return
-
ENOMEM
;
}
for
(
i
=
0
;
i
<
XFRM6_TUNNEL_SPI_BYADDR_HSIZE
;
i
++
)
INIT_HLIST_HEAD
(
&
xfrm6_tunnel_spi_byaddr
[
i
]);
for
(
i
=
0
;
i
<
XFRM6_TUNNEL_SPI_BYSPI_HSIZE
;
i
++
)
INIT_HLIST_HEAD
(
&
xfrm6_tunnel_spi_byspi
[
i
]);
return
0
;
}
static
void
xfrm6_tunnel_spi_fini
(
void
)
{
int
i
;
X6TPRINTK3
(
KERN_DEBUG
"%s()
\n
"
,
__FUNCTION__
);
for
(
i
=
0
;
i
<
XFRM6_TUNNEL_SPI_BYADDR_HSIZE
;
i
++
)
{
if
(
!
hlist_empty
(
&
xfrm6_tunnel_spi_byaddr
[
i
]))
goto
err
;
}
for
(
i
=
0
;
i
<
XFRM6_TUNNEL_SPI_BYSPI_HSIZE
;
i
++
)
{
if
(
!
hlist_empty
(
&
xfrm6_tunnel_spi_byspi
[
i
]))
goto
err
;
}
kmem_cache_destroy
(
xfrm6_tunnel_spi_kmem
);
xfrm6_tunnel_spi_kmem
=
NULL
;
return
;
err:
X6TPRINTK1
(
KERN_ERR
"%s(): table is not empty
\n
"
,
__FUNCTION__
);
return
;
}
static
struct
xfrm6_tunnel_spi
*
__xfrm6_tunnel_spi_lookup
(
xfrm_address_t
*
saddr
)
{
struct
xfrm6_tunnel_spi
*
x6spi
;
struct
hlist_node
*
pos
;
X6TPRINTK3
(
KERN_DEBUG
"%s(saddr=%p)
\n
"
,
__FUNCTION__
,
saddr
);
hlist_for_each_entry
(
x6spi
,
pos
,
&
xfrm6_tunnel_spi_byaddr
[
xfrm6_tunnel_spi_hash_byaddr
(
saddr
)],
list_byaddr
)
{
if
(
memcmp
(
&
x6spi
->
addr
,
saddr
,
sizeof
(
x6spi
->
addr
))
==
0
)
{
X6SPI_CHECK_MAGIC
(
x6spi
);
X6TPRINTK3
(
KERN_DEBUG
"%s() = %p(%u)
\n
"
,
__FUNCTION__
,
x6spi
,
x6spi
->
spi
);
return
x6spi
;
}
}
X6TPRINTK3
(
KERN_DEBUG
"%s() = NULL(0)
\n
"
,
__FUNCTION__
);
return
NULL
;
}
u32
xfrm6_tunnel_spi_lookup
(
xfrm_address_t
*
saddr
)
{
struct
xfrm6_tunnel_spi
*
x6spi
;
u32
spi
;
X6TPRINTK3
(
KERN_DEBUG
"%s(saddr=%p)
\n
"
,
__FUNCTION__
,
saddr
);
read_lock_bh
(
&
xfrm6_tunnel_spi_lock
);
x6spi
=
__xfrm6_tunnel_spi_lookup
(
saddr
);
spi
=
x6spi
?
x6spi
->
spi
:
0
;
read_unlock_bh
(
&
xfrm6_tunnel_spi_lock
);
return
spi
;
}
static
u32
__xfrm6_tunnel_alloc_spi
(
xfrm_address_t
*
saddr
)
{
u32
spi
;
struct
xfrm6_tunnel_spi
*
x6spi
;
struct
hlist_node
*
pos
;
unsigned
index
;
X6TPRINTK3
(
KERN_DEBUG
"%s(saddr=%p)
\n
"
,
__FUNCTION__
,
saddr
);
if
(
xfrm6_tunnel_spi
<
XFRM6_TUNNEL_SPI_MIN
||
xfrm6_tunnel_spi
>=
XFRM6_TUNNEL_SPI_MAX
)
xfrm6_tunnel_spi
=
XFRM6_TUNNEL_SPI_MIN
;
else
xfrm6_tunnel_spi
++
;
for
(
spi
=
xfrm6_tunnel_spi
;
spi
<=
XFRM6_TUNNEL_SPI_MAX
;
spi
++
)
{
index
=
xfrm6_tunnel_spi_hash_byspi
(
spi
);
hlist_for_each_entry
(
x6spi
,
pos
,
&
xfrm6_tunnel_spi_byspi
[
index
],
list_byspi
)
{
if
(
x6spi
->
spi
==
spi
)
goto
try_next_1
;
}
xfrm6_tunnel_spi
=
spi
;
goto
alloc_spi
;
try_next_1:
;
}
for
(
spi
=
XFRM6_TUNNEL_SPI_MIN
;
spi
<
xfrm6_tunnel_spi
;
spi
++
)
{
index
=
xfrm6_tunnel_spi_hash_byspi
(
spi
);
hlist_for_each_entry
(
x6spi
,
pos
,
&
xfrm6_tunnel_spi_byspi
[
index
],
list_byspi
)
{
if
(
x6spi
->
spi
==
spi
)
goto
try_next_2
;
}
xfrm6_tunnel_spi
=
spi
;
goto
alloc_spi
;
try_next_2:
;
}
spi
=
0
;
goto
out
;
alloc_spi:
X6TPRINTK3
(
KERN_DEBUG
"%s(): allocate new spi for "
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
__FUNCTION__
,
NIP6
(
*
(
struct
in6_addr
*
)
saddr
));
x6spi
=
kmem_cache_alloc
(
xfrm6_tunnel_spi_kmem
,
SLAB_ATOMIC
);
if
(
!
x6spi
)
{
X6TPRINTK1
(
KERN_ERR
"%s(): kmem_cache_alloc() failed
\n
"
,
__FUNCTION__
);
goto
out
;
}
#ifdef XFRM6_TUNNEL_SPI_MAGIC
x6spi
->
magic
=
XFRM6_TUNNEL_SPI_MAGIC
;
#endif
memcpy
(
&
x6spi
->
addr
,
saddr
,
sizeof
(
x6spi
->
addr
));
x6spi
->
spi
=
spi
;
atomic_set
(
&
x6spi
->
refcnt
,
1
);
hlist_add_head
(
&
x6spi
->
list_byspi
,
&
xfrm6_tunnel_spi_byspi
[
index
]);
index
=
xfrm6_tunnel_spi_hash_byaddr
(
saddr
);
hlist_add_head
(
&
x6spi
->
list_byaddr
,
&
xfrm6_tunnel_spi_byaddr
[
index
]);
X6SPI_CHECK_MAGIC
(
x6spi
);
out:
X6TPRINTK3
(
KERN_DEBUG
"%s() = %u
\n
"
,
__FUNCTION__
,
spi
);
return
spi
;
}
u32
xfrm6_tunnel_alloc_spi
(
xfrm_address_t
*
saddr
)
{
struct
xfrm6_tunnel_spi
*
x6spi
;
u32
spi
;
X6TPRINTK3
(
KERN_DEBUG
"%s(saddr=%p)
\n
"
,
__FUNCTION__
,
saddr
);
write_lock_bh
(
&
xfrm6_tunnel_spi_lock
);
x6spi
=
__xfrm6_tunnel_spi_lookup
(
saddr
);
if
(
x6spi
)
{
atomic_inc
(
&
x6spi
->
refcnt
);
spi
=
x6spi
->
spi
;
}
else
spi
=
__xfrm6_tunnel_alloc_spi
(
saddr
);
write_unlock_bh
(
&
xfrm6_tunnel_spi_lock
);
X6TPRINTK3
(
KERN_DEBUG
"%s() = %u
\n
"
,
__FUNCTION__
,
spi
);
return
spi
;
}
void
xfrm6_tunnel_free_spi
(
xfrm_address_t
*
saddr
)
{
struct
xfrm6_tunnel_spi
*
x6spi
;
struct
hlist_node
*
pos
,
*
n
;
X6TPRINTK3
(
KERN_DEBUG
"%s(saddr=%p)
\n
"
,
__FUNCTION__
,
saddr
);
write_lock_bh
(
&
xfrm6_tunnel_spi_lock
);
hlist_for_each_entry_safe
(
x6spi
,
pos
,
n
,
&
xfrm6_tunnel_spi_byaddr
[
xfrm6_tunnel_spi_hash_byaddr
(
saddr
)],
list_byaddr
)
{
if
(
memcmp
(
&
x6spi
->
addr
,
saddr
,
sizeof
(
x6spi
->
addr
))
==
0
)
{
X6TPRINTK3
(
KERN_DEBUG
"%s(): x6spi object "
"for %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
"found at %p
\n
"
,
__FUNCTION__
,
NIP6
(
*
(
struct
in6_addr
*
)
saddr
),
x6spi
);
X6SPI_CHECK_MAGIC
(
x6spi
);
if
(
atomic_dec_and_test
(
&
x6spi
->
refcnt
))
{
hlist_del
(
&
x6spi
->
list_byaddr
);
hlist_del
(
&
x6spi
->
list_byspi
);
kmem_cache_free
(
xfrm6_tunnel_spi_kmem
,
x6spi
);
break
;
}
}
}
write_unlock_bh
(
&
xfrm6_tunnel_spi_lock
);
}
int
xfrm6_tunnel_check_size
(
struct
sk_buff
*
skb
)
{
int
mtu
,
ret
=
0
;
struct
dst_entry
*
dst
=
skb
->
dst
;
mtu
=
dst_pmtu
(
dst
)
-
sizeof
(
struct
ipv6hdr
);
if
(
mtu
<
IPV6_MIN_MTU
)
mtu
=
IPV6_MIN_MTU
;
if
(
skb
->
len
>
mtu
)
{
icmpv6_send
(
skb
,
ICMPV6_PKT_TOOBIG
,
0
,
mtu
,
skb
->
dev
);
ret
=
-
EMSGSIZE
;
}
return
ret
;
}
static
int
xfrm6_tunnel_output
(
struct
sk_buff
**
pskb
)
{
struct
sk_buff
*
skb
=
*
pskb
;
struct
dst_entry
*
dst
=
skb
->
dst
;
struct
xfrm_state
*
x
=
dst
->
xfrm
;
struct
ipv6hdr
*
iph
,
*
top_iph
;
int
err
;
if
((
err
=
xfrm6_tunnel_check_size
(
skb
))
!=
0
)
goto
error_nolock
;
iph
=
skb
->
nh
.
ipv6h
;
top_iph
=
(
struct
ipv6hdr
*
)
skb_push
(
skb
,
x
->
props
.
header_len
);
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
];
top_iph
->
nexthdr
=
IPPROTO_IPV6
;
top_iph
->
payload_len
=
htons
(
skb
->
len
-
sizeof
(
struct
ipv6hdr
));
top_iph
->
hop_limit
=
iph
->
hop_limit
;
memcpy
(
&
top_iph
->
saddr
,
(
struct
in6_addr
*
)
&
x
->
props
.
saddr
,
sizeof
(
struct
in6_addr
));
memcpy
(
&
top_iph
->
daddr
,
(
struct
in6_addr
*
)
&
x
->
id
.
daddr
,
sizeof
(
struct
in6_addr
));
skb
->
nh
.
raw
=
skb
->
data
;
skb
->
h
.
raw
=
skb
->
nh
.
raw
+
sizeof
(
struct
ipv6hdr
);
x
->
curlft
.
bytes
+=
skb
->
len
;
x
->
curlft
.
packets
++
;
spin_unlock_bh
(
&
x
->
lock
);
if
((
skb
->
dst
=
dst_pop
(
dst
))
==
NULL
)
{
kfree_skb
(
skb
);
err
=
-
EHOSTUNREACH
;
goto
error_nolock
;
}
return
NET_XMIT_BYPASS
;
error_nolock:
kfree_skb
(
skb
);
return
err
;
}
static
int
xfrm6_tunnel_input
(
struct
xfrm_state
*
x
,
struct
xfrm_decap_state
*
decap
,
struct
sk_buff
*
skb
)
{
if
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
ipv6hdr
)))
return
-
EINVAL
;
skb
->
mac
.
raw
=
skb
->
nh
.
raw
;
skb
->
nh
.
raw
=
skb
->
data
;
dst_release
(
skb
->
dst
);
skb
->
dst
=
NULL
;
skb
->
protocol
=
htons
(
ETH_P_IPV6
);
skb
->
pkt_type
=
PACKET_HOST
;
netif_rx
(
skb
);
return
0
;
}
static
struct
xfrm6_tunnel
*
xfrm6_tunnel_handler
;
static
DECLARE_MUTEX
(
xfrm6_tunnel_sem
);
int
xfrm6_tunnel_register
(
struct
xfrm6_tunnel
*
handler
)
{
int
ret
;
down
(
&
xfrm6_tunnel_sem
);
ret
=
0
;
if
(
xfrm6_tunnel_handler
!=
NULL
)
ret
=
-
EINVAL
;
if
(
!
ret
)
xfrm6_tunnel_handler
=
handler
;
up
(
&
xfrm6_tunnel_sem
);
return
ret
;
}
int
xfrm6_tunnel_deregister
(
struct
xfrm6_tunnel
*
handler
)
{
int
ret
;
down
(
&
xfrm6_tunnel_sem
);
ret
=
0
;
if
(
xfrm6_tunnel_handler
!=
handler
)
ret
=
-
EINVAL
;
if
(
!
ret
)
xfrm6_tunnel_handler
=
NULL
;
up
(
&
xfrm6_tunnel_sem
);
synchronize_net
();
return
ret
;
}
static
int
xfrm6_tunnel_rcv
(
struct
sk_buff
**
pskb
,
unsigned
int
*
nhoffp
)
{
struct
sk_buff
*
skb
=
*
pskb
;
struct
xfrm6_tunnel
*
handler
=
xfrm6_tunnel_handler
;
struct
xfrm_state
*
x
=
NULL
;
struct
ipv6hdr
*
iph
=
skb
->
nh
.
ipv6h
;
int
err
=
0
;
u32
spi
;
/* device-like_ip6ip6_handler() */
if
(
handler
)
{
err
=
handler
->
handler
(
pskb
,
nhoffp
);
if
(
!
err
)
goto
out
;
}
spi
=
xfrm6_tunnel_spi_lookup
((
xfrm_address_t
*
)
&
iph
->
saddr
);
x
=
xfrm_state_lookup
((
xfrm_address_t
*
)
&
iph
->
daddr
,
spi
,
IPPROTO_IPV6
,
AF_INET6
);
if
(
!
x
)
goto
drop
;
spin_lock
(
&
x
->
lock
);
if
(
unlikely
(
x
->
km
.
state
!=
XFRM_STATE_VALID
))
goto
drop_unlock
;
err
=
xfrm6_tunnel_input
(
x
,
NULL
,
skb
);
if
(
err
)
goto
drop_unlock
;
x
->
curlft
.
bytes
+=
skb
->
len
;
x
->
curlft
.
packets
++
;
spin_unlock
(
&
x
->
lock
);
xfrm_state_put
(
x
);
out:
return
0
;
drop_unlock:
spin_unlock
(
&
x
->
lock
);
xfrm_state_put
(
x
);
drop:
kfree_skb
(
skb
);
return
-
1
;
}
static
void
xfrm6_tunnel_err
(
struct
sk_buff
*
skb
,
struct
inet6_skb_parm
*
opt
,
int
type
,
int
code
,
int
offset
,
__u32
info
)
{
struct
xfrm6_tunnel
*
handler
=
xfrm6_tunnel_handler
;
/* call here first for device-like ip6ip6 err handling */
if
(
handler
)
{
handler
->
err_handler
(
skb
,
opt
,
type
,
code
,
offset
,
info
);
return
;
}
/* xfrm6_tunnel native err handling */
switch
(
type
)
{
case
ICMPV6_DEST_UNREACH
:
switch
(
code
)
{
case
ICMPV6_NOROUTE
:
case
ICMPV6_ADM_PROHIBITED
:
case
ICMPV6_NOT_NEIGHBOUR
:
case
ICMPV6_ADDR_UNREACH
:
case
ICMPV6_PORT_UNREACH
:
default:
X6TPRINTK3
(
KERN_DEBUG
"xfrm6_tunnel: Destination Unreach.
\n
"
);
break
;
}
break
;
case
ICMPV6_PKT_TOOBIG
:
X6TPRINTK3
(
KERN_DEBUG
"xfrm6_tunnel: Packet Too Big.
\n
"
);
break
;
case
ICMPV6_TIME_EXCEED
:
switch
(
code
)
{
case
ICMPV6_EXC_HOPLIMIT
:
X6TPRINTK3
(
KERN_DEBUG
"xfrm6_tunnel: Too small Hoplimit.
\n
"
);
break
;
case
ICMPV6_EXC_FRAGTIME
:
default:
break
;
}
break
;
case
ICMPV6_PARAMPROB
:
switch
(
code
)
{
case
ICMPV6_HDR_FIELD
:
break
;
case
ICMPV6_UNK_NEXTHDR
:
break
;
case
ICMPV6_UNK_OPTION
:
break
;
}
break
;
default:
break
;
}
return
;
}
static
int
xfrm6_tunnel_init_state
(
struct
xfrm_state
*
x
,
void
*
args
)
{
if
(
!
x
->
props
.
mode
)
return
-
EINVAL
;
x
->
props
.
header_len
=
sizeof
(
struct
ipv6hdr
);
return
0
;
}
static
void
xfrm6_tunnel_destroy
(
struct
xfrm_state
*
x
)
{
xfrm6_tunnel_free_spi
((
xfrm_address_t
*
)
&
x
->
props
.
saddr
);
}
static
struct
xfrm_type
xfrm6_tunnel_type
=
{
.
description
=
"IP6IP6"
,
.
owner
=
THIS_MODULE
,
.
proto
=
IPPROTO_IPV6
,
.
init_state
=
xfrm6_tunnel_init_state
,
.
destructor
=
xfrm6_tunnel_destroy
,
.
input
=
xfrm6_tunnel_input
,
.
output
=
xfrm6_tunnel_output
,
};
static
struct
inet6_protocol
xfrm6_tunnel_protocol
=
{
.
handler
=
xfrm6_tunnel_rcv
,
.
err_handler
=
xfrm6_tunnel_err
,
.
flags
=
INET6_PROTO_NOPOLICY
|
INET6_PROTO_FINAL
,
};
void
__init
xfrm6_tunnel_init
(
void
)
{
X6TPRINTK3
(
KERN_DEBUG
"%s()
\n
"
,
__FUNCTION__
);
if
(
xfrm_register_type
(
&
xfrm6_tunnel_type
,
AF_INET6
)
<
0
)
{
X6TPRINTK1
(
KERN_ERR
"xfrm6_tunnel init: can't add xfrm type
\n
"
);
return
;
}
if
(
inet6_add_protocol
(
&
xfrm6_tunnel_protocol
,
IPPROTO_IPV6
)
<
0
)
{
X6TPRINTK1
(
KERN_ERR
"xfrm6_tunnel init(): can't add protocol
\n
"
);
xfrm_unregister_type
(
&
xfrm6_tunnel_type
,
AF_INET6
);
return
;
}
if
(
xfrm6_tunnel_spi_init
()
<
0
)
{
X6TPRINTK1
(
KERN_ERR
"xfrm6_tunnel init: failed to initialize spi
\n
"
);
inet6_del_protocol
(
&
xfrm6_tunnel_protocol
,
IPPROTO_IPV6
);
xfrm_unregister_type
(
&
xfrm6_tunnel_type
,
AF_INET6
);
return
;
}
}
void
__exit
xfrm6_tunnel_fini
(
void
)
{
X6TPRINTK3
(
KERN_DEBUG
"%s()
\n
"
,
__FUNCTION__
);
xfrm6_tunnel_spi_fini
();
if
(
inet6_del_protocol
(
&
xfrm6_tunnel_protocol
,
IPPROTO_IPV6
)
<
0
)
X6TPRINTK1
(
KERN_ERR
"xfrm6_tunnel close: can't remove protocol
\n
"
);
if
(
xfrm_unregister_type
(
&
xfrm6_tunnel_type
,
AF_INET6
)
<
0
)
X6TPRINTK1
(
KERN_ERR
"xfrm6_tunnel close: can't remove xfrm type
\n
"
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment