Merge branch 'udp_tunnel'
Tom Herbert says: ==================== udp: UDP tunnel enhancements - Add udp_sock_create in new helper module udp_tunnel. Tunnel implementations call this function to create listener UDP ports. - Make vxlan and l2tp call udp_sock_create. - Move udp_tunnel_segment into udp_offload.c. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
64bbca3c4b
@ -148,6 +148,7 @@ config VXLAN
|
||||
tristate "Virtual eXtensible Local Area Network (VXLAN)"
|
||||
depends on INET
|
||||
select NET_IP_TUNNEL
|
||||
select NET_UDP_TUNNEL
|
||||
---help---
|
||||
This allows one to create vxlan virtual interfaces that provide
|
||||
Layer 2 Networks over Layer 3 Networks. VXLAN is often used
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <net/ip_tunnels.h>
|
||||
#include <net/icmp.h>
|
||||
#include <net/udp.h>
|
||||
#include <net/udp_tunnel.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/route.h>
|
||||
#include <net/dsfield.h>
|
||||
@ -2339,102 +2340,37 @@ static void vxlan_del_work(struct work_struct *work)
|
||||
kfree_rcu(vs, rcu);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
/* Create UDP socket for encapsulation receive. AF_INET6 socket
|
||||
* could be used for both IPv4 and IPv6 communications, but
|
||||
* users may set bindv6only=1.
|
||||
*/
|
||||
static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags)
|
||||
static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
|
||||
__be16 port, u32 flags)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct socket *sock;
|
||||
struct sockaddr_in6 vxlan_addr = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_port = port,
|
||||
};
|
||||
int rc, val = 1;
|
||||
struct udp_port_cfg udp_conf;
|
||||
int err;
|
||||
|
||||
rc = sock_create_kern(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
|
||||
if (rc < 0) {
|
||||
pr_debug("UDPv6 socket create failed\n");
|
||||
return ERR_PTR(rc);
|
||||
memset(&udp_conf, 0, sizeof(udp_conf));
|
||||
|
||||
if (ipv6) {
|
||||
udp_conf.family = AF_INET6;
|
||||
udp_conf.use_udp6_tx_checksums =
|
||||
!!(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
|
||||
udp_conf.use_udp6_rx_checksums =
|
||||
!!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
|
||||
} else {
|
||||
udp_conf.family = AF_INET;
|
||||
udp_conf.local_ip.s_addr = INADDR_ANY;
|
||||
udp_conf.use_udp_checksums =
|
||||
!!(flags & VXLAN_F_UDP_CSUM);
|
||||
}
|
||||
|
||||
/* Put in proper namespace */
|
||||
sk = sock->sk;
|
||||
sk_change_net(sk, net);
|
||||
udp_conf.local_udp_port = port;
|
||||
|
||||
kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
|
||||
(char *)&val, sizeof(val));
|
||||
rc = kernel_bind(sock, (struct sockaddr *)&vxlan_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
if (rc < 0) {
|
||||
pr_debug("bind for UDPv6 socket %pI6:%u (%d)\n",
|
||||
&vxlan_addr.sin6_addr, ntohs(vxlan_addr.sin6_port), rc);
|
||||
sk_release_kernel(sk);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
/* At this point, IPv6 module should have been loaded in
|
||||
* sock_create_kern().
|
||||
*/
|
||||
BUG_ON(!ipv6_stub);
|
||||
/* Open UDP socket */
|
||||
err = udp_sock_create(net, &udp_conf, &sock);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* Disable multicast loopback */
|
||||
inet_sk(sk)->mc_loop = 0;
|
||||
|
||||
if (flags & VXLAN_F_UDP_ZERO_CSUM6_TX)
|
||||
udp_set_no_check6_tx(sk, true);
|
||||
|
||||
if (flags & VXLAN_F_UDP_ZERO_CSUM6_RX)
|
||||
udp_set_no_check6_rx(sk, true);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags)
|
||||
{
|
||||
return ERR_PTR(-EPFNOSUPPORT);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct socket *create_v4_sock(struct net *net, __be16 port, u32 flags)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct socket *sock;
|
||||
struct sockaddr_in vxlan_addr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_ANY),
|
||||
.sin_port = port,
|
||||
};
|
||||
int rc;
|
||||
|
||||
/* Create UDP socket for encapsulation receive. */
|
||||
rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
|
||||
if (rc < 0) {
|
||||
pr_debug("UDP socket create failed\n");
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
/* Put in proper namespace */
|
||||
sk = sock->sk;
|
||||
sk_change_net(sk, net);
|
||||
|
||||
rc = kernel_bind(sock, (struct sockaddr *) &vxlan_addr,
|
||||
sizeof(vxlan_addr));
|
||||
if (rc < 0) {
|
||||
pr_debug("bind for UDP socket %pI4:%u (%d)\n",
|
||||
&vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
|
||||
sk_release_kernel(sk);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
/* Disable multicast loopback */
|
||||
inet_sk(sk)->mc_loop = 0;
|
||||
|
||||
if (!(flags & VXLAN_F_UDP_CSUM))
|
||||
sock->sk->sk_no_check_tx = 1;
|
||||
inet_sk(sock->sk)->mc_loop = 0;
|
||||
|
||||
return sock;
|
||||
}
|
||||
@ -2460,10 +2396,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
|
||||
|
||||
INIT_WORK(&vs->del_work, vxlan_del_work);
|
||||
|
||||
if (ipv6)
|
||||
sock = create_v6_sock(net, port, flags);
|
||||
else
|
||||
sock = create_v4_sock(net, port, flags);
|
||||
sock = vxlan_create_sock(net, ipv6, port, flags);
|
||||
if (IS_ERR(sock)) {
|
||||
kfree(vs);
|
||||
return ERR_CAST(sock);
|
||||
|
32
include/net/udp_tunnel.h
Normal file
32
include/net/udp_tunnel.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __NET_UDP_TUNNEL_H
|
||||
#define __NET_UDP_TUNNEL_H
|
||||
|
||||
struct udp_port_cfg {
|
||||
u8 family;
|
||||
|
||||
/* Used only for kernel-created sockets */
|
||||
union {
|
||||
struct in_addr local_ip;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct in6_addr local_ip6;
|
||||
#endif
|
||||
};
|
||||
|
||||
union {
|
||||
struct in_addr peer_ip;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct in6_addr peer_ip6;
|
||||
#endif
|
||||
};
|
||||
|
||||
__be16 local_udp_port;
|
||||
__be16 peer_udp_port;
|
||||
unsigned int use_udp_checksums:1,
|
||||
use_udp6_tx_checksums:1,
|
||||
use_udp6_rx_checksums:1;
|
||||
};
|
||||
|
||||
int udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
|
||||
struct socket **sockp);
|
||||
|
||||
#endif
|
@ -307,6 +307,10 @@ config NET_IPVTI
|
||||
the notion of a secure tunnel for IPSEC and then use routing protocol
|
||||
on top.
|
||||
|
||||
config NET_UDP_TUNNEL
|
||||
tristate
|
||||
default n
|
||||
|
||||
config INET_AH
|
||||
tristate "IP: AH transformation"
|
||||
select XFRM_ALGO
|
||||
|
@ -22,6 +22,7 @@ obj-$(CONFIG_NET_IPIP) += ipip.o
|
||||
gre-y := gre_demux.o
|
||||
obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
|
||||
obj-$(CONFIG_NET_IPGRE) += ip_gre.o
|
||||
obj-$(CONFIG_NET_UDP_TUNNEL) += udp_tunnel.o
|
||||
obj-$(CONFIG_NET_IPVTI) += ip_vti.o
|
||||
obj-$(CONFIG_SYN_COOKIES) += syncookies.o
|
||||
obj-$(CONFIG_INET_AH) += ah4.o
|
||||
|
@ -2522,79 +2522,3 @@ void __init udp_init(void)
|
||||
sysctl_udp_rmem_min = SK_MEM_QUANTUM;
|
||||
sysctl_udp_wmem_min = SK_MEM_QUANTUM;
|
||||
}
|
||||
|
||||
struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct sk_buff *segs = ERR_PTR(-EINVAL);
|
||||
u16 mac_offset = skb->mac_header;
|
||||
int mac_len = skb->mac_len;
|
||||
int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
|
||||
__be16 protocol = skb->protocol;
|
||||
netdev_features_t enc_features;
|
||||
int udp_offset, outer_hlen;
|
||||
unsigned int oldlen;
|
||||
bool need_csum;
|
||||
|
||||
oldlen = (u16)~skb->len;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
|
||||
goto out;
|
||||
|
||||
skb->encapsulation = 0;
|
||||
__skb_pull(skb, tnl_hlen);
|
||||
skb_reset_mac_header(skb);
|
||||
skb_set_network_header(skb, skb_inner_network_offset(skb));
|
||||
skb->mac_len = skb_inner_network_offset(skb);
|
||||
skb->protocol = htons(ETH_P_TEB);
|
||||
|
||||
need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
|
||||
if (need_csum)
|
||||
skb->encap_hdr_csum = 1;
|
||||
|
||||
/* segment inner packet. */
|
||||
enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
|
||||
segs = skb_mac_gso_segment(skb, enc_features);
|
||||
if (!segs || IS_ERR(segs)) {
|
||||
skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
|
||||
mac_len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
outer_hlen = skb_tnl_header_len(skb);
|
||||
udp_offset = outer_hlen - tnl_hlen;
|
||||
skb = segs;
|
||||
do {
|
||||
struct udphdr *uh;
|
||||
int len;
|
||||
|
||||
skb_reset_inner_headers(skb);
|
||||
skb->encapsulation = 1;
|
||||
|
||||
skb->mac_len = mac_len;
|
||||
|
||||
skb_push(skb, outer_hlen);
|
||||
skb_reset_mac_header(skb);
|
||||
skb_set_network_header(skb, mac_len);
|
||||
skb_set_transport_header(skb, udp_offset);
|
||||
len = skb->len - udp_offset;
|
||||
uh = udp_hdr(skb);
|
||||
uh->len = htons(len);
|
||||
|
||||
if (need_csum) {
|
||||
__be32 delta = htonl(oldlen + len);
|
||||
|
||||
uh->check = ~csum_fold((__force __wsum)
|
||||
((__force u32)uh->check +
|
||||
(__force u32)delta));
|
||||
uh->check = gso_make_checksum(skb, ~uh->check);
|
||||
|
||||
if (uh->check == 0)
|
||||
uh->check = CSUM_MANGLED_0;
|
||||
}
|
||||
|
||||
skb->protocol = protocol;
|
||||
} while ((skb = skb->next));
|
||||
out:
|
||||
return segs;
|
||||
}
|
||||
|
@ -47,6 +47,82 @@ static int udp4_ufo_send_check(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct sk_buff *segs = ERR_PTR(-EINVAL);
|
||||
u16 mac_offset = skb->mac_header;
|
||||
int mac_len = skb->mac_len;
|
||||
int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
|
||||
__be16 protocol = skb->protocol;
|
||||
netdev_features_t enc_features;
|
||||
int udp_offset, outer_hlen;
|
||||
unsigned int oldlen;
|
||||
bool need_csum;
|
||||
|
||||
oldlen = (u16)~skb->len;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
|
||||
goto out;
|
||||
|
||||
skb->encapsulation = 0;
|
||||
__skb_pull(skb, tnl_hlen);
|
||||
skb_reset_mac_header(skb);
|
||||
skb_set_network_header(skb, skb_inner_network_offset(skb));
|
||||
skb->mac_len = skb_inner_network_offset(skb);
|
||||
skb->protocol = htons(ETH_P_TEB);
|
||||
|
||||
need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
|
||||
if (need_csum)
|
||||
skb->encap_hdr_csum = 1;
|
||||
|
||||
/* segment inner packet. */
|
||||
enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
|
||||
segs = skb_mac_gso_segment(skb, enc_features);
|
||||
if (!segs || IS_ERR(segs)) {
|
||||
skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
|
||||
mac_len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
outer_hlen = skb_tnl_header_len(skb);
|
||||
udp_offset = outer_hlen - tnl_hlen;
|
||||
skb = segs;
|
||||
do {
|
||||
struct udphdr *uh;
|
||||
int len;
|
||||
|
||||
skb_reset_inner_headers(skb);
|
||||
skb->encapsulation = 1;
|
||||
|
||||
skb->mac_len = mac_len;
|
||||
|
||||
skb_push(skb, outer_hlen);
|
||||
skb_reset_mac_header(skb);
|
||||
skb_set_network_header(skb, mac_len);
|
||||
skb_set_transport_header(skb, udp_offset);
|
||||
len = skb->len - udp_offset;
|
||||
uh = udp_hdr(skb);
|
||||
uh->len = htons(len);
|
||||
|
||||
if (need_csum) {
|
||||
__be32 delta = htonl(oldlen + len);
|
||||
|
||||
uh->check = ~csum_fold((__force __wsum)
|
||||
((__force u32)uh->check +
|
||||
(__force u32)delta));
|
||||
uh->check = gso_make_checksum(skb, ~uh->check);
|
||||
|
||||
if (uh->check == 0)
|
||||
uh->check = CSUM_MANGLED_0;
|
||||
}
|
||||
|
||||
skb->protocol = protocol;
|
||||
} while ((skb = skb->next));
|
||||
out:
|
||||
return segs;
|
||||
}
|
||||
|
||||
static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
|
100
net/ipv4/udp_tunnel.c
Normal file
100
net/ipv4/udp_tunnel.c
Normal file
@ -0,0 +1,100 @@
|
||||
#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>
|
||||
|
||||
int udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
|
||||
struct socket **sockp)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct socket *sock = NULL;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (cfg->family == AF_INET6) {
|
||||
struct sockaddr_in6 udp6_addr;
|
||||
|
||||
err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
sk_change_net(sock->sk, net);
|
||||
|
||||
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) {
|
||||
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);
|
||||
} else
|
||||
#endif
|
||||
if (cfg->family == AF_INET) {
|
||||
struct sockaddr_in udp_addr;
|
||||
|
||||
err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
sk_change_net(sock->sk, net);
|
||||
|
||||
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;
|
||||
|
||||
if (cfg->peer_udp_port) {
|
||||
udp_addr.sin_family = AF_INET;
|
||||
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);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
sock->sk->sk_no_check_tx = !cfg->use_udp_checksums;
|
||||
} else {
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
|
||||
*sockp = sock;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (sock) {
|
||||
kernel_sock_shutdown(sock, SHUT_RDWR);
|
||||
sk_release_kernel(sock->sk);
|
||||
}
|
||||
*sockp = NULL;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(udp_sock_create);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -6,6 +6,7 @@ menuconfig L2TP
|
||||
tristate "Layer Two Tunneling Protocol (L2TP)"
|
||||
depends on (IPV6 || IPV6=n)
|
||||
depends on INET
|
||||
select NET_UDP_TUNNEL
|
||||
---help---
|
||||
Layer Two Tunneling Protocol
|
||||
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include <net/dst.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/udp.h>
|
||||
#include <net/udp_tunnel.h>
|
||||
#include <net/inet_common.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/protocol.h>
|
||||
@ -1358,81 +1359,46 @@ static int l2tp_tunnel_sock_create(struct net *net,
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct socket *sock = NULL;
|
||||
struct sockaddr_in udp_addr = {0};
|
||||
struct sockaddr_l2tpip ip_addr = {0};
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct sockaddr_in6 udp6_addr = {0};
|
||||
struct sockaddr_l2tpip6 ip6_addr = {0};
|
||||
#endif
|
||||
struct udp_port_cfg udp_conf;
|
||||
|
||||
switch (cfg->encap) {
|
||||
case L2TP_ENCAPTYPE_UDP:
|
||||
memset(&udp_conf, 0, sizeof(udp_conf));
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (cfg->local_ip6 && cfg->peer_ip6) {
|
||||
err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
sk_change_net(sock->sk, net);
|
||||
|
||||
udp6_addr.sin6_family = AF_INET6;
|
||||
memcpy(&udp6_addr.sin6_addr, cfg->local_ip6,
|
||||
sizeof(udp6_addr.sin6_addr));
|
||||
udp6_addr.sin6_port = htons(cfg->local_udp_port);
|
||||
err = kernel_bind(sock, (struct sockaddr *) &udp6_addr,
|
||||
sizeof(udp6_addr));
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
udp6_addr.sin6_family = AF_INET6;
|
||||
memcpy(&udp6_addr.sin6_addr, cfg->peer_ip6,
|
||||
sizeof(udp6_addr.sin6_addr));
|
||||
udp6_addr.sin6_port = htons(cfg->peer_udp_port);
|
||||
err = kernel_connect(sock,
|
||||
(struct sockaddr *) &udp6_addr,
|
||||
sizeof(udp6_addr), 0);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (cfg->udp6_zero_tx_checksums)
|
||||
udp_set_no_check6_tx(sock->sk, true);
|
||||
if (cfg->udp6_zero_rx_checksums)
|
||||
udp_set_no_check6_rx(sock->sk, true);
|
||||
udp_conf.family = AF_INET6;
|
||||
memcpy(&udp_conf.local_ip6, cfg->local_ip6,
|
||||
sizeof(udp_conf.local_ip6));
|
||||
memcpy(&udp_conf.peer_ip6, cfg->peer_ip6,
|
||||
sizeof(udp_conf.peer_ip6));
|
||||
udp_conf.use_udp6_tx_checksums =
|
||||
cfg->udp6_zero_tx_checksums;
|
||||
udp_conf.use_udp6_rx_checksums =
|
||||
cfg->udp6_zero_rx_checksums;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
sk_change_net(sock->sk, net);
|
||||
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_addr = cfg->local_ip;
|
||||
udp_addr.sin_port = htons(cfg->local_udp_port);
|
||||
err = kernel_bind(sock, (struct sockaddr *) &udp_addr,
|
||||
sizeof(udp_addr));
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_addr = cfg->peer_ip;
|
||||
udp_addr.sin_port = htons(cfg->peer_udp_port);
|
||||
err = kernel_connect(sock,
|
||||
(struct sockaddr *) &udp_addr,
|
||||
sizeof(udp_addr), 0);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
udp_conf.family = AF_INET;
|
||||
udp_conf.local_ip = cfg->local_ip;
|
||||
udp_conf.peer_ip = cfg->peer_ip;
|
||||
udp_conf.use_udp_checksums = cfg->use_udp_checksums;
|
||||
}
|
||||
|
||||
if (!cfg->use_udp_checksums)
|
||||
sock->sk->sk_no_check_tx = 1;
|
||||
udp_conf.local_udp_port = htons(cfg->local_udp_port);
|
||||
udp_conf.peer_udp_port = htons(cfg->peer_udp_port);
|
||||
|
||||
err = udp_sock_create(net, &udp_conf, &sock);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
break;
|
||||
|
||||
case L2TP_ENCAPTYPE_IP:
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (cfg->local_ip6 && cfg->peer_ip6) {
|
||||
struct sockaddr_l2tpip6 ip6_addr = {0};
|
||||
|
||||
err = sock_create_kern(AF_INET6, SOCK_DGRAM,
|
||||
IPPROTO_L2TP, &sock);
|
||||
if (err < 0)
|
||||
@ -1461,6 +1427,8 @@ static int l2tp_tunnel_sock_create(struct net *net,
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_l2tpip ip_addr = {0};
|
||||
|
||||
err = sock_create_kern(AF_INET, SOCK_DGRAM,
|
||||
IPPROTO_L2TP, &sock);
|
||||
if (err < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user