2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-09-17 04:31:16 +04:00
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/socket.h>
# include <linux/udp.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/in6.h>
# include <net/udp.h>
# include <net/udp_tunnel.h>
# include <net/net_namespace.h>
# include <net/netns/generic.h>
# include <net/ip6_tunnel.h>
# include <net/ip6_checksum.h>
int udp_sock_create6 ( struct net * net , struct udp_port_cfg * cfg ,
struct socket * * sockp )
{
2018-12-19 08:17:44 +03:00
struct sockaddr_in6 udp6_addr = { } ;
2014-09-17 04:31:16 +04:00
int err ;
struct socket * sock = NULL ;
2015-05-09 05:10:31 +03:00
err = sock_create_kern ( net , AF_INET6 , SOCK_DGRAM , 0 , & sock ) ;
2014-09-17 04:31:16 +04:00
if ( err < 0 )
goto error ;
2015-08-28 21:48:22 +03:00
if ( cfg - > ipv6_v6only ) {
int val = 1 ;
err = kernel_setsockopt ( sock , IPPROTO_IPV6 , IPV6_V6ONLY ,
( char * ) & val , sizeof ( val ) ) ;
if ( err < 0 )
goto error ;
}
2018-12-03 12:54:38 +03:00
if ( cfg - > bind_ifindex ) {
2019-01-15 16:42:16 +03:00
err = kernel_setsockopt ( sock , SOL_SOCKET , SO_BINDTOIFINDEX ,
( void * ) & cfg - > bind_ifindex ,
sizeof ( cfg - > bind_ifindex ) ) ;
2018-12-03 12:54:38 +03:00
if ( err < 0 )
goto error ;
}
2015-08-28 21:48:22 +03:00
2014-09-17 04:31:16 +04:00
udp6_addr . sin6_family = AF_INET6 ;
memcpy ( & udp6_addr . sin6_addr , & cfg - > local_ip6 ,
sizeof ( udp6_addr . sin6_addr ) ) ;
udp6_addr . sin6_port = cfg - > local_udp_port ;
err = kernel_bind ( sock , ( struct sockaddr * ) & udp6_addr ,
sizeof ( udp6_addr ) ) ;
if ( err < 0 )
goto error ;
if ( cfg - > peer_udp_port ) {
2018-12-19 08:17:44 +03:00
memset ( & udp6_addr , 0 , sizeof ( udp6_addr ) ) ;
2014-09-17 04:31:16 +04:00
udp6_addr . sin6_family = AF_INET6 ;
memcpy ( & udp6_addr . sin6_addr , & cfg - > peer_ip6 ,
sizeof ( udp6_addr . sin6_addr ) ) ;
udp6_addr . sin6_port = cfg - > peer_udp_port ;
err = kernel_connect ( sock ,
( struct sockaddr * ) & udp6_addr ,
sizeof ( udp6_addr ) , 0 ) ;
}
if ( err < 0 )
goto error ;
udp_set_no_check6_tx ( sock - > sk , ! cfg - > use_udp6_tx_checksums ) ;
udp_set_no_check6_rx ( sock - > sk , ! cfg - > use_udp6_rx_checksums ) ;
* sockp = sock ;
return 0 ;
error :
if ( sock ) {
kernel_sock_shutdown ( sock , SHUT_RDWR ) ;
2015-05-09 05:10:31 +03:00
sock_release ( sock ) ;
2014-09-17 04:31:16 +04:00
}
* sockp = NULL ;
return err ;
}
EXPORT_SYMBOL_GPL ( udp_sock_create6 ) ;
2014-09-17 04:31:17 +04:00
2015-04-06 05:19:09 +03:00
int udp_tunnel6_xmit_skb ( struct dst_entry * dst , struct sock * sk ,
struct sk_buff * skb ,
2015-01-20 22:23:04 +03:00
struct net_device * dev , struct in6_addr * saddr ,
struct in6_addr * daddr ,
2016-03-09 05:00:02 +03:00
__u8 prio , __u8 ttl , __be32 label ,
__be16 src_port , __be16 dst_port , bool nocheck )
2014-09-17 04:31:17 +04:00
{
struct udphdr * uh ;
struct ipv6hdr * ip6h ;
__skb_push ( skb , sizeof ( * uh ) ) ;
skb_reset_transport_header ( skb ) ;
uh = udp_hdr ( skb ) ;
uh - > dest = dst_port ;
uh - > source = src_port ;
uh - > len = htons ( skb - > len ) ;
skb_dst_set ( skb , dst ) ;
2015-01-20 22:23:04 +03:00
udp6_set_csum ( nocheck , skb , saddr , daddr , skb - > len ) ;
2014-09-17 04:31:17 +04:00
__skb_push ( skb , sizeof ( * ip6h ) ) ;
skb_reset_network_header ( skb ) ;
ip6h = ipv6_hdr ( skb ) ;
2016-03-09 05:00:02 +03:00
ip6_flow_hdr ( ip6h , prio , label ) ;
2014-09-17 04:31:17 +04:00
ip6h - > payload_len = htons ( skb - > len ) ;
ip6h - > nexthdr = IPPROTO_UDP ;
ip6h - > hop_limit = ttl ;
ip6h - > daddr = * daddr ;
ip6h - > saddr = * saddr ;
2015-04-06 05:19:09 +03:00
ip6tunnel_xmit ( sk , skb , dev ) ;
2014-09-17 04:31:17 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( udp_tunnel6_xmit_skb ) ;
2014-09-22 22:39:44 +04:00
MODULE_LICENSE ( " GPL " ) ;