2014-07-14 06:49:37 +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 <net/udp.h>
# include <net/udp_tunnel.h>
# include <net/net_namespace.h>
2014-09-17 04:31:16 +04:00
int udp_sock_create4 ( struct net * net , struct udp_port_cfg * cfg ,
struct socket * * sockp )
2014-07-14 06:49:37 +04:00
{
2014-09-17 04:31:17 +04:00
int err ;
2014-07-14 06:49:37 +04:00
struct socket * sock = NULL ;
2014-09-17 04:31:16 +04:00
struct sockaddr_in udp_addr ;
2014-07-14 06:49:37 +04:00
2014-09-17 04:31:16 +04:00
err = sock_create_kern ( AF_INET , SOCK_DGRAM , 0 , & sock ) ;
if ( err < 0 )
goto error ;
2014-07-14 06:49:37 +04:00
2014-09-17 04:31:16 +04:00
sk_change_net ( sock - > sk , net ) ;
2014-07-14 06:49:37 +04:00
2014-09-17 04:31:16 +04:00
udp_addr . sin_family = AF_INET ;
udp_addr . sin_addr = cfg - > local_ip ;
udp_addr . sin_port = cfg - > local_udp_port ;
err = kernel_bind ( sock , ( struct sockaddr * ) & udp_addr ,
sizeof ( udp_addr ) ) ;
if ( err < 0 )
goto error ;
2014-07-14 06:49:37 +04:00
2014-09-17 04:31:16 +04:00
if ( cfg - > peer_udp_port ) {
2014-07-14 06:49:37 +04:00
udp_addr . sin_family = AF_INET ;
2014-09-17 04:31:16 +04:00
udp_addr . sin_addr = cfg - > peer_ip ;
udp_addr . sin_port = cfg - > peer_udp_port ;
err = kernel_connect ( sock , ( struct sockaddr * ) & udp_addr ,
sizeof ( udp_addr ) , 0 ) ;
2014-07-14 06:49:37 +04:00
if ( err < 0 )
goto error ;
}
2014-09-17 04:31:16 +04:00
sock - > sk - > sk_no_check_tx = ! cfg - > use_udp_checksums ;
2014-07-14 06:49:37 +04:00
* sockp = sock ;
return 0 ;
error :
if ( sock ) {
kernel_sock_shutdown ( sock , SHUT_RDWR ) ;
sk_release_kernel ( sock - > sk ) ;
}
* sockp = NULL ;
return err ;
}
2014-09-17 04:31:16 +04:00
EXPORT_SYMBOL ( udp_sock_create4 ) ;
2014-07-14 06:49:37 +04:00
2014-09-17 04:31:17 +04:00
void setup_udp_tunnel_sock ( struct net * net , struct socket * sock ,
struct udp_tunnel_sock_cfg * cfg )
{
struct sock * sk = sock - > sk ;
/* Disable multicast loopback */
inet_sk ( sk ) - > mc_loop = 0 ;
/* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */
udp_set_convert_csum ( sk , true ) ;
rcu_assign_sk_user_data ( sk , cfg - > sk_user_data ) ;
udp_sk ( sk ) - > encap_type = cfg - > encap_type ;
udp_sk ( sk ) - > encap_rcv = cfg - > encap_rcv ;
udp_sk ( sk ) - > encap_destroy = cfg - > encap_destroy ;
udp_tunnel_encap_enable ( sock ) ;
}
EXPORT_SYMBOL_GPL ( setup_udp_tunnel_sock ) ;
int udp_tunnel_xmit_skb ( struct socket * sock , struct rtable * rt ,
struct sk_buff * skb , __be32 src , __be32 dst ,
__u8 tos , __u8 ttl , __be16 df , __be16 src_port ,
__be16 dst_port , bool xnet )
{
struct udphdr * uh ;
__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 ) ;
udp_set_csum ( sock - > sk - > sk_no_check_tx , skb , src , dst , skb - > len ) ;
return iptunnel_xmit ( sock - > sk , rt , skb , src , dst , IPPROTO_UDP ,
tos , ttl , df , xnet ) ;
}
EXPORT_SYMBOL_GPL ( udp_tunnel_xmit_skb ) ;
void udp_tunnel_sock_release ( struct socket * sock )
{
rcu_assign_sk_user_data ( sock - > sk , NULL ) ;
kernel_sock_shutdown ( sock , SHUT_RDWR ) ;
sk_release_kernel ( sock - > sk ) ;
}
EXPORT_SYMBOL_GPL ( udp_tunnel_sock_release ) ;
2014-07-14 06:49:37 +04:00
MODULE_LICENSE ( " GPL " ) ;