1 #include <linux/version.h>
3 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
5 #include <linux/module.h>
6 #include <linux/errno.h>
7 #include <linux/socket.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <net/ip_tunnels.h>
13 #include <net/udp_tunnel.h>
14 #include <net/net_namespace.h>
16 int rpl_udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
17 struct socket **sockp)
20 struct socket *sock = NULL;
22 #if IS_ENABLED(CONFIG_IPV6)
23 if (cfg->family == AF_INET6) {
24 struct sockaddr_in6 udp6_addr;
26 err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
30 udp6_addr.sin6_family = AF_INET6;
31 memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
32 sizeof(udp6_addr.sin6_addr));
33 udp6_addr.sin6_port = cfg->local_udp_port;
34 err = kernel_bind(sock, (struct sockaddr *)&udp6_addr,
39 if (cfg->peer_udp_port) {
40 udp6_addr.sin6_family = AF_INET6;
41 memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
42 sizeof(udp6_addr.sin6_addr));
43 udp6_addr.sin6_port = cfg->peer_udp_port;
44 err = kernel_connect(sock,
45 (struct sockaddr *)&udp6_addr,
46 sizeof(udp6_addr), 0);
52 if (cfg->family == AF_INET) {
53 struct sockaddr_in udp_addr;
55 err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
59 udp_addr.sin_family = AF_INET;
60 udp_addr.sin_addr = cfg->local_ip;
61 udp_addr.sin_port = cfg->local_udp_port;
62 err = kernel_bind(sock, (struct sockaddr *)&udp_addr,
67 if (cfg->peer_udp_port) {
68 udp_addr.sin_family = AF_INET;
69 udp_addr.sin_addr = cfg->peer_ip;
70 udp_addr.sin_port = cfg->peer_udp_port;
71 err = kernel_connect(sock,
72 (struct sockaddr *)&udp_addr,
88 kernel_sock_shutdown(sock, SHUT_RDWR);
94 EXPORT_SYMBOL_GPL(rpl_udp_sock_create);
96 void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock,
97 struct udp_tunnel_sock_cfg *cfg)
99 struct sock *sk = sock->sk;
101 /* Disable multicast loopback */
102 inet_sk(sk)->mc_loop = 0;
104 rcu_assign_sk_user_data(sk, cfg->sk_user_data);
106 udp_sk(sk)->encap_type = cfg->encap_type;
107 udp_sk(sk)->encap_rcv = cfg->encap_rcv;
108 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
109 udp_sk(sk)->encap_destroy = cfg->encap_destroy;
112 udp_tunnel_encap_enable(sock);
114 EXPORT_SYMBOL_GPL(rpl_setup_udp_tunnel_sock);
116 void ovs_udp_gso(struct sk_buff *skb)
118 int udp_offset = skb_transport_offset(skb);
122 uh->len = htons(skb->len - udp_offset);
124 EXPORT_SYMBOL_GPL(ovs_udp_gso);
126 void ovs_udp_csum_gso(struct sk_buff *skb)
128 struct iphdr *iph = ip_hdr(skb);
129 int udp_offset = skb_transport_offset(skb);
133 /* csum segment if tunnel sets skb with csum. The cleanest way
134 * to do this just to set it up from scratch. */
135 skb->ip_summed = CHECKSUM_NONE;
136 udp_set_csum(true, skb, iph->saddr, iph->daddr,
137 skb->len - udp_offset);
139 EXPORT_SYMBOL_GPL(ovs_udp_csum_gso);
141 int rpl_udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk,
142 struct sk_buff *skb, __be32 src, __be32 dst,
143 __u8 tos, __u8 ttl, __be16 df, __be16 src_port,
144 __be16 dst_port, bool xnet, bool nocheck)
148 __skb_push(skb, sizeof(*uh));
149 skb_reset_transport_header(skb);
153 uh->source = src_port;
154 uh->len = htons(skb->len);
156 udp_set_csum(nocheck, skb, src, dst, skb->len);
158 return iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP,
161 EXPORT_SYMBOL_GPL(rpl_udp_tunnel_xmit_skb);
163 void rpl_udp_tunnel_sock_release(struct socket *sock)
165 rcu_assign_sk_user_data(sock->sk, NULL);
166 kernel_sock_shutdown(sock, SHUT_RDWR);
169 EXPORT_SYMBOL_GPL(rpl_udp_tunnel_sock_release);
171 #endif /* Linux version < 4.0 */