1 | #include <linux/module.h> |
2 | #include <linux/errno.h> |
3 | #include <linux/socket.h> |
4 | #include <linux/udp.h> |
5 | #include <linux/types.h> |
6 | #include <linux/kernel.h> |
7 | #include <net/dst_metadata.h> |
8 | #include <net/net_namespace.h> |
9 | #include <net/udp.h> |
10 | #include <net/udp_tunnel.h> |
11 | |
12 | int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, |
13 | struct socket **sockp) |
14 | { |
15 | int err; |
16 | struct socket *sock = NULL; |
17 | struct sockaddr_in udp_addr; |
18 | |
19 | err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock); |
20 | if (err < 0) |
21 | goto error; |
22 | |
23 | if (cfg->bind_ifindex) { |
24 | err = kernel_setsockopt(sock, SOL_SOCKET, SO_BINDTOIFINDEX, |
25 | (void *)&cfg->bind_ifindex, |
26 | sizeof(cfg->bind_ifindex)); |
27 | if (err < 0) |
28 | goto error; |
29 | } |
30 | |
31 | udp_addr.sin_family = AF_INET; |
32 | udp_addr.sin_addr = cfg->local_ip; |
33 | udp_addr.sin_port = cfg->local_udp_port; |
34 | err = kernel_bind(sock, (struct sockaddr *)&udp_addr, |
35 | sizeof(udp_addr)); |
36 | if (err < 0) |
37 | goto error; |
38 | |
39 | if (cfg->peer_udp_port) { |
40 | udp_addr.sin_family = AF_INET; |
41 | udp_addr.sin_addr = cfg->peer_ip; |
42 | udp_addr.sin_port = cfg->peer_udp_port; |
43 | err = kernel_connect(sock, (struct sockaddr *)&udp_addr, |
44 | sizeof(udp_addr), 0); |
45 | if (err < 0) |
46 | goto error; |
47 | } |
48 | |
49 | sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; |
50 | |
51 | *sockp = sock; |
52 | return 0; |
53 | |
54 | error: |
55 | if (sock) { |
56 | kernel_sock_shutdown(sock, SHUT_RDWR); |
57 | sock_release(sock); |
58 | } |
59 | *sockp = NULL; |
60 | return err; |
61 | } |
62 | EXPORT_SYMBOL(udp_sock_create4); |
63 | |
64 | void setup_udp_tunnel_sock(struct net *net, struct socket *sock, |
65 | struct udp_tunnel_sock_cfg *cfg) |
66 | { |
67 | struct sock *sk = sock->sk; |
68 | |
69 | /* Disable multicast loopback */ |
70 | inet_sk(sk)->mc_loop = 0; |
71 | |
72 | /* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */ |
73 | inet_inc_convert_csum(sk); |
74 | |
75 | rcu_assign_sk_user_data(sk, cfg->sk_user_data); |
76 | |
77 | udp_sk(sk)->encap_type = cfg->encap_type; |
78 | udp_sk(sk)->encap_rcv = cfg->encap_rcv; |
79 | udp_sk(sk)->encap_err_lookup = cfg->encap_err_lookup; |
80 | udp_sk(sk)->encap_destroy = cfg->encap_destroy; |
81 | udp_sk(sk)->gro_receive = cfg->gro_receive; |
82 | udp_sk(sk)->gro_complete = cfg->gro_complete; |
83 | |
84 | udp_tunnel_encap_enable(sock); |
85 | } |
86 | EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); |
87 | |
88 | void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock, |
89 | unsigned short type) |
90 | { |
91 | struct sock *sk = sock->sk; |
92 | struct udp_tunnel_info ti; |
93 | |
94 | if (!dev->netdev_ops->ndo_udp_tunnel_add || |
95 | !(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT)) |
96 | return; |
97 | |
98 | ti.type = type; |
99 | ti.sa_family = sk->sk_family; |
100 | ti.port = inet_sk(sk)->inet_sport; |
101 | |
102 | dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti); |
103 | } |
104 | EXPORT_SYMBOL_GPL(udp_tunnel_push_rx_port); |
105 | |
106 | void udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock, |
107 | unsigned short type) |
108 | { |
109 | struct sock *sk = sock->sk; |
110 | struct udp_tunnel_info ti; |
111 | |
112 | if (!dev->netdev_ops->ndo_udp_tunnel_del || |
113 | !(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT)) |
114 | return; |
115 | |
116 | ti.type = type; |
117 | ti.sa_family = sk->sk_family; |
118 | ti.port = inet_sk(sk)->inet_sport; |
119 | |
120 | dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti); |
121 | } |
122 | EXPORT_SYMBOL_GPL(udp_tunnel_drop_rx_port); |
123 | |
124 | /* Notify netdevs that UDP port started listening */ |
125 | void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type) |
126 | { |
127 | struct sock *sk = sock->sk; |
128 | struct net *net = sock_net(sk); |
129 | struct udp_tunnel_info ti; |
130 | struct net_device *dev; |
131 | |
132 | ti.type = type; |
133 | ti.sa_family = sk->sk_family; |
134 | ti.port = inet_sk(sk)->inet_sport; |
135 | |
136 | rcu_read_lock(); |
137 | for_each_netdev_rcu(net, dev) { |
138 | if (!dev->netdev_ops->ndo_udp_tunnel_add) |
139 | continue; |
140 | if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT)) |
141 | continue; |
142 | dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti); |
143 | } |
144 | rcu_read_unlock(); |
145 | } |
146 | EXPORT_SYMBOL_GPL(udp_tunnel_notify_add_rx_port); |
147 | |
148 | /* Notify netdevs that UDP port is no more listening */ |
149 | void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type) |
150 | { |
151 | struct sock *sk = sock->sk; |
152 | struct net *net = sock_net(sk); |
153 | struct udp_tunnel_info ti; |
154 | struct net_device *dev; |
155 | |
156 | ti.type = type; |
157 | ti.sa_family = sk->sk_family; |
158 | ti.port = inet_sk(sk)->inet_sport; |
159 | |
160 | rcu_read_lock(); |
161 | for_each_netdev_rcu(net, dev) { |
162 | if (!dev->netdev_ops->ndo_udp_tunnel_del) |
163 | continue; |
164 | if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT)) |
165 | continue; |
166 | dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti); |
167 | } |
168 | rcu_read_unlock(); |
169 | } |
170 | EXPORT_SYMBOL_GPL(udp_tunnel_notify_del_rx_port); |
171 | |
172 | void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, |
173 | __be32 src, __be32 dst, __u8 tos, __u8 ttl, |
174 | __be16 df, __be16 src_port, __be16 dst_port, |
175 | bool xnet, bool nocheck) |
176 | { |
177 | struct udphdr *uh; |
178 | |
179 | __skb_push(skb, sizeof(*uh)); |
180 | skb_reset_transport_header(skb); |
181 | uh = udp_hdr(skb); |
182 | |
183 | uh->dest = dst_port; |
184 | uh->source = src_port; |
185 | uh->len = htons(skb->len); |
186 | |
187 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
188 | |
189 | udp_set_csum(nocheck, skb, src, dst, skb->len); |
190 | |
191 | iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet); |
192 | } |
193 | EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); |
194 | |
195 | void udp_tunnel_sock_release(struct socket *sock) |
196 | { |
197 | rcu_assign_sk_user_data(sock->sk, NULL); |
198 | kernel_sock_shutdown(sock, SHUT_RDWR); |
199 | sock_release(sock); |
200 | } |
201 | EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); |
202 | |
203 | struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, |
204 | __be16 flags, __be64 tunnel_id, int md_size) |
205 | { |
206 | struct metadata_dst *tun_dst; |
207 | struct ip_tunnel_info *info; |
208 | |
209 | if (family == AF_INET) |
210 | tun_dst = ip_tun_rx_dst(skb, flags, tunnel_id, md_size); |
211 | else |
212 | tun_dst = ipv6_tun_rx_dst(skb, flags, tunnel_id, md_size); |
213 | if (!tun_dst) |
214 | return NULL; |
215 | |
216 | info = &tun_dst->u.tun_info; |
217 | info->key.tp_src = udp_hdr(skb)->source; |
218 | info->key.tp_dst = udp_hdr(skb)->dest; |
219 | if (udp_hdr(skb)->check) |
220 | info->key.tun_flags |= TUNNEL_CSUM; |
221 | return tun_dst; |
222 | } |
223 | EXPORT_SYMBOL_GPL(udp_tun_rx_dst); |
224 | |
225 | MODULE_LICENSE("GPL" ); |
226 | |