@ -6,6 +6,7 @@
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/mpls.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/slab.h>
@ -16,11 +17,14 @@
static struct xfrm_tunnel __rcu * tunnel4_handlers __read_mostly ;
static struct xfrm_tunnel __rcu * tunnel64_handlers __read_mostly ;
static struct xfrm_tunnel __rcu * tunnelmpls4_handlers __read_mostly ;
static DEFINE_MUTEX ( tunnel4_mutex ) ;
static inline struct xfrm_tunnel __rcu * * fam_handlers ( unsigned short family )
{
return ( family = = AF_INET ) ? & tunnel4_handlers : & tunnel64_handlers ;
return ( family = = AF_INET ) ? & tunnel4_handlers :
( family = = AF_INET6 ) ? & tunnel64_handlers :
& tunnelmpls4_handlers ;
}
int xfrm4_tunnel_register ( struct xfrm_tunnel * handler , unsigned short family )
@ -125,6 +129,26 @@ drop:
}
# endif
# if IS_ENABLED(CONFIG_MPLS)
static int tunnelmpls4_rcv ( struct sk_buff * skb )
{
struct xfrm_tunnel * handler ;
if ( ! pskb_may_pull ( skb , sizeof ( struct mpls_label ) ) )
goto drop ;
for_each_tunnel_rcu ( tunnelmpls4_handlers , handler )
if ( ! handler - > handler ( skb ) )
return 0 ;
icmp_send ( skb , ICMP_DEST_UNREACH , ICMP_PORT_UNREACH , 0 ) ;
drop :
kfree_skb ( skb ) ;
return 0 ;
}
# endif
static void tunnel4_err ( struct sk_buff * skb , u32 info )
{
struct xfrm_tunnel * handler ;
@ -145,6 +169,17 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
}
# endif
# if IS_ENABLED(CONFIG_MPLS)
static void tunnelmpls4_err ( struct sk_buff * skb , u32 info )
{
struct xfrm_tunnel * handler ;
for_each_tunnel_rcu ( tunnelmpls4_handlers , handler )
if ( ! handler - > err_handler ( skb , info ) )
break ;
}
# endif
static const struct net_protocol tunnel4_protocol = {
. handler = tunnel4_rcv ,
. err_handler = tunnel4_err ,
@ -161,24 +196,46 @@ static const struct net_protocol tunnel64_protocol = {
} ;
# endif
# if IS_ENABLED(CONFIG_MPLS)
static const struct net_protocol tunnelmpls4_protocol = {
. handler = tunnelmpls4_rcv ,
. err_handler = tunnelmpls4_err ,
. no_policy = 1 ,
. netns_ok = 1 ,
} ;
# endif
static int __init tunnel4_init ( void )
{
if ( inet_add_protocol ( & tunnel4_protocol , IPPROTO_IPIP ) ) {
pr_err ( " %s: can't add protocol \n " , __func__ ) ;
return - EAGAIN ;
}
if ( inet_add_protocol ( & tunnel4_protocol , IPPROTO_IPIP ) )
goto err_ipip ;
# if IS_ENABLED(CONFIG_IPV6)
if ( inet_add_protocol ( & tunnel64_protocol , IPPROTO_IPV6 ) ) {
pr_err ( " tunnel64 init: can't add protocol \n " ) ;
inet_del_protocol ( & tunnel4_protocol , IPPROTO_IPIP ) ;
return - EAGAIN ;
}
if ( inet_add_protocol ( & tunnel64_protocol , IPPROTO_IPV6 ) )
goto err_ipv6 ;
# endif
# if IS_ENABLED(CONFIG_MPLS)
if ( inet_add_protocol ( & tunnelmpls4_protocol , IPPROTO_MPLS ) )
goto err_mpls ;
# endif
return 0 ;
# if IS_ENABLED(CONFIG_IPV6)
err_mpls :
inet_del_protocol ( & tunnel4_protocol , IPPROTO_IPV6 ) ;
# endif
err_ipv6 :
inet_del_protocol ( & tunnel4_protocol , IPPROTO_IPIP ) ;
err_ipip :
pr_err ( " %s: can't add protocol \n " , __func__ ) ;
return - EAGAIN ;
}
static void __exit tunnel4_fini ( void )
{
# if IS_ENABLED(CONFIG_MPLS)
if ( inet_del_protocol ( & tunnelmpls4_protocol , IPPROTO_MPLS ) )
pr_err ( " tunnelmpls4 close: can't remove protocol \n " ) ;
# endif
# if IS_ENABLED(CONFIG_IPV6)
if ( inet_del_protocol ( & tunnel64_protocol , IPPROTO_IPV6 ) )
pr_err ( " tunnel64 close: can't remove protocol \n " ) ;