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>
2015-08-27 09:46:50 +03:00
# include <net/dst_metadata.h>
# include <net/net_namespace.h>
2014-07-14 06:49:37 +04:00
# include <net/udp.h>
# include <net/udp_tunnel.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
2015-05-09 05:10:31 +03:00
err = sock_create_kern ( net , AF_INET , SOCK_DGRAM , 0 , & sock ) ;
2014-09-17 04:31:16 +04:00
if ( err < 0 )
goto error ;
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 ) ;
2015-05-09 05:10:31 +03:00
sock_release ( sock ) ;
2014-07-14 06:49:37 +04:00
}
* 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 */
2015-01-06 00:56:14 +03:00
inet_inc_convert_csum ( sk ) ;
2014-09-17 04:31:17 +04:00
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 ;
2016-04-05 18:22:52 +03:00
udp_sk ( sk ) - > gro_receive = cfg - > gro_receive ;
udp_sk ( sk ) - > gro_complete = cfg - > gro_complete ;
2014-09-17 04:31:17 +04:00
udp_tunnel_encap_enable ( sock ) ;
}
EXPORT_SYMBOL_GPL ( setup_udp_tunnel_sock ) ;
2016-06-16 22:20:52 +03:00
void udp_tunnel_push_rx_port ( struct net_device * dev , struct socket * sock ,
unsigned short type )
{
struct sock * sk = sock - > sk ;
struct udp_tunnel_info ti ;
2017-07-21 13:49:29 +03:00
if ( ! dev - > netdev_ops - > ndo_udp_tunnel_add | |
! ( dev - > features & NETIF_F_RX_UDP_TUNNEL_PORT ) )
2016-06-16 22:23:12 +03:00
return ;
2016-06-16 22:20:52 +03:00
ti . type = type ;
ti . sa_family = sk - > sk_family ;
ti . port = inet_sk ( sk ) - > inet_sport ;
2016-06-16 22:23:12 +03:00
dev - > netdev_ops - > ndo_udp_tunnel_add ( dev , & ti ) ;
2016-06-16 22:20:52 +03:00
}
EXPORT_SYMBOL_GPL ( udp_tunnel_push_rx_port ) ;
2017-07-21 13:49:30 +03:00
void udp_tunnel_drop_rx_port ( struct net_device * dev , struct socket * sock ,
unsigned short type )
{
struct sock * sk = sock - > sk ;
struct udp_tunnel_info ti ;
if ( ! dev - > netdev_ops - > ndo_udp_tunnel_del | |
! ( dev - > features & NETIF_F_RX_UDP_TUNNEL_PORT ) )
return ;
ti . type = type ;
ti . sa_family = sk - > sk_family ;
ti . port = inet_sk ( sk ) - > inet_sport ;
dev - > netdev_ops - > ndo_udp_tunnel_del ( dev , & ti ) ;
}
EXPORT_SYMBOL_GPL ( udp_tunnel_drop_rx_port ) ;
2016-06-16 22:20:52 +03:00
/* Notify netdevs that UDP port started listening */
void udp_tunnel_notify_add_rx_port ( struct socket * sock , unsigned short type )
{
struct sock * sk = sock - > sk ;
struct net * net = sock_net ( sk ) ;
struct udp_tunnel_info ti ;
struct net_device * dev ;
ti . type = type ;
ti . sa_family = sk - > sk_family ;
ti . port = inet_sk ( sk ) - > inet_sport ;
rcu_read_lock ( ) ;
2016-06-16 22:23:12 +03:00
for_each_netdev_rcu ( net , dev ) {
if ( ! dev - > netdev_ops - > ndo_udp_tunnel_add )
continue ;
2017-07-21 13:49:29 +03:00
if ( ! ( dev - > features & NETIF_F_RX_UDP_TUNNEL_PORT ) )
continue ;
2016-06-16 22:23:12 +03:00
dev - > netdev_ops - > ndo_udp_tunnel_add ( dev , & ti ) ;
}
2016-06-16 22:20:52 +03:00
rcu_read_unlock ( ) ;
}
EXPORT_SYMBOL_GPL ( udp_tunnel_notify_add_rx_port ) ;
/* Notify netdevs that UDP port is no more listening */
void udp_tunnel_notify_del_rx_port ( struct socket * sock , unsigned short type )
{
struct sock * sk = sock - > sk ;
struct net * net = sock_net ( sk ) ;
struct udp_tunnel_info ti ;
struct net_device * dev ;
ti . type = type ;
ti . sa_family = sk - > sk_family ;
ti . port = inet_sk ( sk ) - > inet_sport ;
rcu_read_lock ( ) ;
2016-06-16 22:23:12 +03:00
for_each_netdev_rcu ( net , dev ) {
if ( ! dev - > netdev_ops - > ndo_udp_tunnel_del )
continue ;
2017-07-21 13:49:29 +03:00
if ( ! ( dev - > features & NETIF_F_RX_UDP_TUNNEL_PORT ) )
continue ;
2016-06-16 22:23:12 +03:00
dev - > netdev_ops - > ndo_udp_tunnel_del ( dev , & ti ) ;
}
2016-06-16 22:20:52 +03:00
rcu_read_unlock ( ) ;
}
EXPORT_SYMBOL_GPL ( udp_tunnel_notify_del_rx_port ) ;
2015-12-25 01:34:54 +03:00
void udp_tunnel_xmit_skb ( struct rtable * rt , struct sock * sk , struct sk_buff * skb ,
__be32 src , __be32 dst , __u8 tos , __u8 ttl ,
__be16 df , __be16 src_port , __be16 dst_port ,
bool xnet , bool nocheck )
2014-09-17 04:31:17 +04:00
{
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 ) ;
2016-02-22 02:58:05 +03:00
memset ( & ( IPCB ( skb ) - > opt ) , 0 , sizeof ( IPCB ( skb ) - > opt ) ) ;
2015-01-20 22:23:04 +03:00
udp_set_csum ( nocheck , skb , src , dst , skb - > len ) ;
2014-09-17 04:31:17 +04:00
2015-12-25 01:34:54 +03:00
iptunnel_xmit ( sk , rt , skb , src , dst , IPPROTO_UDP , tos , ttl , df , xnet ) ;
2014-09-17 04:31:17 +04:00
}
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 ) ;
2015-05-09 05:10:31 +03:00
sock_release ( sock ) ;
2014-09-17 04:31:17 +04:00
}
EXPORT_SYMBOL_GPL ( udp_tunnel_sock_release ) ;
2015-08-27 09:46:50 +03:00
struct metadata_dst * udp_tun_rx_dst ( struct sk_buff * skb , unsigned short family ,
__be16 flags , __be64 tunnel_id , int md_size )
{
struct metadata_dst * tun_dst ;
struct ip_tunnel_info * info ;
if ( family = = AF_INET )
tun_dst = ip_tun_rx_dst ( skb , flags , tunnel_id , md_size ) ;
else
tun_dst = ipv6_tun_rx_dst ( skb , flags , tunnel_id , md_size ) ;
if ( ! tun_dst )
return NULL ;
info = & tun_dst - > u . tun_info ;
info - > key . tp_src = udp_hdr ( skb ) - > source ;
info - > key . tp_dst = udp_hdr ( skb ) - > dest ;
if ( udp_hdr ( skb ) - > check )
info - > key . tun_flags | = TUNNEL_CSUM ;
return tun_dst ;
}
EXPORT_SYMBOL_GPL ( udp_tun_rx_dst ) ;
2014-07-14 06:49:37 +04:00
MODULE_LICENSE ( " GPL " ) ;