1 | #include <machine/rtems-bsd-config.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 |
---|
5 | * The Regents of the University of California. |
---|
6 | * Copyright (c) 2008 Robert N. M. Watson |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * 4. Neither the name of the University nor the names of its contributors |
---|
18 | * may be used to endorse or promote products derived from this software |
---|
19 | * without specific prior written permission. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
31 | * SUCH DAMAGE. |
---|
32 | * |
---|
33 | * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 |
---|
34 | */ |
---|
35 | |
---|
36 | #ifdef __rtems__ |
---|
37 | #include <errno.h> |
---|
38 | #undef errno |
---|
39 | #endif /* __rtems__ */ |
---|
40 | #include <sys/cdefs.h> |
---|
41 | __FBSDID("$FreeBSD$"); |
---|
42 | |
---|
43 | #include <rtems/bsd/local/opt_ipfw.h> |
---|
44 | #include <rtems/bsd/local/opt_inet6.h> |
---|
45 | #include <rtems/bsd/local/opt_ipsec.h> |
---|
46 | |
---|
47 | #include <rtems/bsd/sys/param.h> |
---|
48 | #include <sys/domain.h> |
---|
49 | #include <sys/eventhandler.h> |
---|
50 | #include <sys/jail.h> |
---|
51 | #include <sys/kernel.h> |
---|
52 | #include <rtems/bsd/sys/lock.h> |
---|
53 | #include <sys/malloc.h> |
---|
54 | #include <sys/mbuf.h> |
---|
55 | #include <sys/priv.h> |
---|
56 | #include <sys/proc.h> |
---|
57 | #include <sys/protosw.h> |
---|
58 | #include <sys/signalvar.h> |
---|
59 | #include <sys/socket.h> |
---|
60 | #include <sys/socketvar.h> |
---|
61 | #include <sys/sx.h> |
---|
62 | #include <sys/sysctl.h> |
---|
63 | #include <sys/syslog.h> |
---|
64 | #include <sys/systm.h> |
---|
65 | |
---|
66 | #include <vm/uma.h> |
---|
67 | |
---|
68 | #include <net/if.h> |
---|
69 | #include <net/route.h> |
---|
70 | |
---|
71 | #include <netinet/in.h> |
---|
72 | #include <netinet/in_pcb.h> |
---|
73 | #include <netinet/in_systm.h> |
---|
74 | #include <netinet/in_var.h> |
---|
75 | #include <netinet/ip.h> |
---|
76 | #ifdef INET6 |
---|
77 | #include <netinet/ip6.h> |
---|
78 | #endif |
---|
79 | #include <netinet/ip_icmp.h> |
---|
80 | #include <netinet/icmp_var.h> |
---|
81 | #include <netinet/ip_var.h> |
---|
82 | #include <netinet/ip_options.h> |
---|
83 | #ifdef INET6 |
---|
84 | #include <netinet6/ip6_var.h> |
---|
85 | #endif |
---|
86 | #include <netinet/udp.h> |
---|
87 | #include <netinet/udp_var.h> |
---|
88 | |
---|
89 | #ifdef IPSEC |
---|
90 | #include <netipsec/ipsec.h> |
---|
91 | #include <netipsec/esp.h> |
---|
92 | #endif |
---|
93 | |
---|
94 | #include <machine/in_cksum.h> |
---|
95 | |
---|
96 | #include <security/mac/mac_framework.h> |
---|
97 | |
---|
98 | /* |
---|
99 | * UDP protocol implementation. |
---|
100 | * Per RFC 768, August, 1980. |
---|
101 | */ |
---|
102 | |
---|
103 | /* |
---|
104 | * BSD 4.2 defaulted the udp checksum to be off. Turning off udp checksums |
---|
105 | * removes the only data integrity mechanism for packets and malformed |
---|
106 | * packets that would otherwise be discarded due to bad checksums, and may |
---|
107 | * cause problems (especially for NFS data blocks). |
---|
108 | */ |
---|
109 | static int udp_cksum = 1; |
---|
110 | SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, &udp_cksum, |
---|
111 | 0, "compute udp checksum"); |
---|
112 | |
---|
113 | int udp_log_in_vain = 0; |
---|
114 | SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, |
---|
115 | &udp_log_in_vain, 0, "Log all incoming UDP packets"); |
---|
116 | |
---|
117 | VNET_DEFINE(int, udp_blackhole) = 0; |
---|
118 | SYSCTL_VNET_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW, |
---|
119 | &VNET_NAME(udp_blackhole), 0, |
---|
120 | "Do not send port unreachables for refused connects"); |
---|
121 | |
---|
122 | u_long udp_sendspace = 9216; /* really max datagram size */ |
---|
123 | /* 40 1K datagrams */ |
---|
124 | SYSCTL_ULONG(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, |
---|
125 | &udp_sendspace, 0, "Maximum outgoing UDP datagram size"); |
---|
126 | |
---|
127 | u_long udp_recvspace = 40 * (1024 + |
---|
128 | #ifdef INET6 |
---|
129 | sizeof(struct sockaddr_in6) |
---|
130 | #else |
---|
131 | sizeof(struct sockaddr_in) |
---|
132 | #endif |
---|
133 | ); |
---|
134 | |
---|
135 | SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, |
---|
136 | &udp_recvspace, 0, "Maximum space for incoming UDP datagrams"); |
---|
137 | |
---|
138 | VNET_DEFINE(struct inpcbhead, udb); /* from udp_var.h */ |
---|
139 | VNET_DEFINE(struct inpcbinfo, udbinfo); |
---|
140 | static VNET_DEFINE(uma_zone_t, udpcb_zone); |
---|
141 | #define V_udpcb_zone VNET(udpcb_zone) |
---|
142 | |
---|
143 | #ifndef UDBHASHSIZE |
---|
144 | #define UDBHASHSIZE 128 |
---|
145 | #endif |
---|
146 | |
---|
147 | VNET_DEFINE(struct udpstat, udpstat); /* from udp_var.h */ |
---|
148 | SYSCTL_VNET_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RW, |
---|
149 | &VNET_NAME(udpstat), udpstat, |
---|
150 | "UDP statistics (struct udpstat, netinet/udp_var.h)"); |
---|
151 | |
---|
152 | static void udp_detach(struct socket *so); |
---|
153 | static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *, |
---|
154 | struct mbuf *, struct thread *); |
---|
155 | #ifdef IPSEC |
---|
156 | #ifdef IPSEC_NAT_T |
---|
157 | #define UF_ESPINUDP_ALL (UF_ESPINUDP_NON_IKE|UF_ESPINUDP) |
---|
158 | #ifdef INET |
---|
159 | static struct mbuf *udp4_espdecap(struct inpcb *, struct mbuf *, int); |
---|
160 | #endif |
---|
161 | #endif /* IPSEC_NAT_T */ |
---|
162 | #endif /* IPSEC */ |
---|
163 | |
---|
164 | static void |
---|
165 | udp_zone_change(void *tag) |
---|
166 | { |
---|
167 | |
---|
168 | uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets); |
---|
169 | uma_zone_set_max(V_udpcb_zone, maxsockets); |
---|
170 | } |
---|
171 | |
---|
172 | static int |
---|
173 | udp_inpcb_init(void *mem, int size, int flags) |
---|
174 | { |
---|
175 | struct inpcb *inp; |
---|
176 | |
---|
177 | inp = mem; |
---|
178 | INP_LOCK_INIT(inp, "inp", "udpinp"); |
---|
179 | return (0); |
---|
180 | } |
---|
181 | |
---|
182 | void |
---|
183 | udp_init(void) |
---|
184 | { |
---|
185 | |
---|
186 | |
---|
187 | INP_INFO_LOCK_INIT(&V_udbinfo, "udp"); |
---|
188 | LIST_INIT(&V_udb); |
---|
189 | #ifdef VIMAGE |
---|
190 | V_udbinfo.ipi_vnet = curvnet; |
---|
191 | #endif |
---|
192 | V_udbinfo.ipi_listhead = &V_udb; |
---|
193 | V_udbinfo.ipi_hashbase = hashinit(UDBHASHSIZE, M_PCB, |
---|
194 | &V_udbinfo.ipi_hashmask); |
---|
195 | V_udbinfo.ipi_porthashbase = hashinit(UDBHASHSIZE, M_PCB, |
---|
196 | &V_udbinfo.ipi_porthashmask); |
---|
197 | V_udbinfo.ipi_zone = uma_zcreate("udp_inpcb", sizeof(struct inpcb), |
---|
198 | NULL, NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); |
---|
199 | uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets); |
---|
200 | |
---|
201 | V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb), |
---|
202 | NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); |
---|
203 | uma_zone_set_max(V_udpcb_zone, maxsockets); |
---|
204 | |
---|
205 | EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL, |
---|
206 | EVENTHANDLER_PRI_ANY); |
---|
207 | } |
---|
208 | |
---|
209 | /* |
---|
210 | * Kernel module interface for updating udpstat. The argument is an index |
---|
211 | * into udpstat treated as an array of u_long. While this encodes the |
---|
212 | * general layout of udpstat into the caller, it doesn't encode its location, |
---|
213 | * so that future changes to add, for example, per-CPU stats support won't |
---|
214 | * cause binary compatibility problems for kernel modules. |
---|
215 | */ |
---|
216 | void |
---|
217 | kmod_udpstat_inc(int statnum) |
---|
218 | { |
---|
219 | |
---|
220 | (*((u_long *)&V_udpstat + statnum))++; |
---|
221 | } |
---|
222 | |
---|
223 | int |
---|
224 | udp_newudpcb(struct inpcb *inp) |
---|
225 | { |
---|
226 | struct udpcb *up; |
---|
227 | |
---|
228 | up = uma_zalloc(V_udpcb_zone, M_NOWAIT | M_ZERO); |
---|
229 | if (up == NULL) |
---|
230 | return (ENOBUFS); |
---|
231 | inp->inp_ppcb = up; |
---|
232 | return (0); |
---|
233 | } |
---|
234 | |
---|
235 | void |
---|
236 | udp_discardcb(struct udpcb *up) |
---|
237 | { |
---|
238 | |
---|
239 | uma_zfree(V_udpcb_zone, up); |
---|
240 | } |
---|
241 | |
---|
242 | #ifdef VIMAGE |
---|
243 | void |
---|
244 | udp_destroy(void) |
---|
245 | { |
---|
246 | |
---|
247 | hashdestroy(V_udbinfo.ipi_hashbase, M_PCB, |
---|
248 | V_udbinfo.ipi_hashmask); |
---|
249 | hashdestroy(V_udbinfo.ipi_porthashbase, M_PCB, |
---|
250 | V_udbinfo.ipi_porthashmask); |
---|
251 | |
---|
252 | uma_zdestroy(V_udpcb_zone); |
---|
253 | uma_zdestroy(V_udbinfo.ipi_zone); |
---|
254 | INP_INFO_LOCK_DESTROY(&V_udbinfo); |
---|
255 | } |
---|
256 | #endif |
---|
257 | |
---|
258 | /* |
---|
259 | * Subroutine of udp_input(), which appends the provided mbuf chain to the |
---|
260 | * passed pcb/socket. The caller must provide a sockaddr_in via udp_in that |
---|
261 | * contains the source address. If the socket ends up being an IPv6 socket, |
---|
262 | * udp_append() will convert to a sockaddr_in6 before passing the address |
---|
263 | * into the socket code. |
---|
264 | */ |
---|
265 | static void |
---|
266 | udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, |
---|
267 | struct sockaddr_in *udp_in) |
---|
268 | { |
---|
269 | struct sockaddr *append_sa; |
---|
270 | struct socket *so; |
---|
271 | struct mbuf *opts = 0; |
---|
272 | #ifdef INET6 |
---|
273 | struct sockaddr_in6 udp_in6; |
---|
274 | #endif |
---|
275 | #ifdef IPSEC |
---|
276 | #ifdef IPSEC_NAT_T |
---|
277 | #ifdef INET |
---|
278 | struct udpcb *up; |
---|
279 | #endif |
---|
280 | #endif |
---|
281 | #endif |
---|
282 | |
---|
283 | INP_RLOCK_ASSERT(inp); |
---|
284 | |
---|
285 | #ifdef IPSEC |
---|
286 | /* Check AH/ESP integrity. */ |
---|
287 | if (ipsec4_in_reject(n, inp)) { |
---|
288 | m_freem(n); |
---|
289 | V_ipsec4stat.in_polvio++; |
---|
290 | return; |
---|
291 | } |
---|
292 | #ifdef IPSEC_NAT_T |
---|
293 | #ifdef INET |
---|
294 | up = intoudpcb(inp); |
---|
295 | KASSERT(up != NULL, ("%s: udpcb NULL", __func__)); |
---|
296 | if (up->u_flags & UF_ESPINUDP_ALL) { /* IPSec UDP encaps. */ |
---|
297 | n = udp4_espdecap(inp, n, off); |
---|
298 | if (n == NULL) /* Consumed. */ |
---|
299 | return; |
---|
300 | } |
---|
301 | #endif /* INET */ |
---|
302 | #endif /* IPSEC_NAT_T */ |
---|
303 | #endif /* IPSEC */ |
---|
304 | #ifdef MAC |
---|
305 | if (mac_inpcb_check_deliver(inp, n) != 0) { |
---|
306 | m_freem(n); |
---|
307 | return; |
---|
308 | } |
---|
309 | #endif |
---|
310 | if (inp->inp_flags & INP_CONTROLOPTS || |
---|
311 | inp->inp_socket->so_options & (SO_TIMESTAMP | SO_BINTIME)) { |
---|
312 | #ifdef INET6 |
---|
313 | if (inp->inp_vflag & INP_IPV6) |
---|
314 | (void)ip6_savecontrol_v4(inp, n, &opts, NULL); |
---|
315 | else |
---|
316 | #endif |
---|
317 | ip_savecontrol(inp, &opts, ip, n); |
---|
318 | } |
---|
319 | #ifdef INET6 |
---|
320 | if (inp->inp_vflag & INP_IPV6) { |
---|
321 | bzero(&udp_in6, sizeof(udp_in6)); |
---|
322 | udp_in6.sin6_len = sizeof(udp_in6); |
---|
323 | udp_in6.sin6_family = AF_INET6; |
---|
324 | in6_sin_2_v4mapsin6(udp_in, &udp_in6); |
---|
325 | append_sa = (struct sockaddr *)&udp_in6; |
---|
326 | } else |
---|
327 | #endif |
---|
328 | append_sa = (struct sockaddr *)udp_in; |
---|
329 | m_adj(n, off); |
---|
330 | |
---|
331 | so = inp->inp_socket; |
---|
332 | SOCKBUF_LOCK(&so->so_rcv); |
---|
333 | if (sbappendaddr_locked(&so->so_rcv, append_sa, n, opts) == 0) { |
---|
334 | SOCKBUF_UNLOCK(&so->so_rcv); |
---|
335 | m_freem(n); |
---|
336 | if (opts) |
---|
337 | m_freem(opts); |
---|
338 | UDPSTAT_INC(udps_fullsock); |
---|
339 | } else |
---|
340 | sorwakeup_locked(so); |
---|
341 | } |
---|
342 | |
---|
343 | void |
---|
344 | udp_input(struct mbuf *m, int off) |
---|
345 | { |
---|
346 | int iphlen = off; |
---|
347 | struct ip *ip; |
---|
348 | struct udphdr *uh; |
---|
349 | struct ifnet *ifp; |
---|
350 | struct inpcb *inp; |
---|
351 | struct udpcb *up; |
---|
352 | int len; |
---|
353 | struct ip save_ip; |
---|
354 | struct sockaddr_in udp_in; |
---|
355 | #ifdef IPFIREWALL_FORWARD |
---|
356 | struct m_tag *fwd_tag; |
---|
357 | #endif |
---|
358 | |
---|
359 | ifp = m->m_pkthdr.rcvif; |
---|
360 | UDPSTAT_INC(udps_ipackets); |
---|
361 | |
---|
362 | /* |
---|
363 | * Strip IP options, if any; should skip this, make available to |
---|
364 | * user, and use on returned packets, but we don't yet have a way to |
---|
365 | * check the checksum with options still present. |
---|
366 | */ |
---|
367 | if (iphlen > sizeof (struct ip)) { |
---|
368 | ip_stripoptions(m, (struct mbuf *)0); |
---|
369 | iphlen = sizeof(struct ip); |
---|
370 | } |
---|
371 | |
---|
372 | /* |
---|
373 | * Get IP and UDP header together in first mbuf. |
---|
374 | */ |
---|
375 | ip = mtod(m, struct ip *); |
---|
376 | if (m->m_len < iphlen + sizeof(struct udphdr)) { |
---|
377 | if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { |
---|
378 | UDPSTAT_INC(udps_hdrops); |
---|
379 | return; |
---|
380 | } |
---|
381 | ip = mtod(m, struct ip *); |
---|
382 | } |
---|
383 | uh = (struct udphdr *)((caddr_t)ip + iphlen); |
---|
384 | |
---|
385 | /* |
---|
386 | * Destination port of 0 is illegal, based on RFC768. |
---|
387 | */ |
---|
388 | if (uh->uh_dport == 0) |
---|
389 | goto badunlocked; |
---|
390 | |
---|
391 | /* |
---|
392 | * Construct sockaddr format source address. Stuff source address |
---|
393 | * and datagram in user buffer. |
---|
394 | */ |
---|
395 | bzero(&udp_in, sizeof(udp_in)); |
---|
396 | udp_in.sin_len = sizeof(udp_in); |
---|
397 | udp_in.sin_family = AF_INET; |
---|
398 | udp_in.sin_port = uh->uh_sport; |
---|
399 | udp_in.sin_addr = ip->ip_src; |
---|
400 | |
---|
401 | /* |
---|
402 | * Make mbuf data length reflect UDP length. If not enough data to |
---|
403 | * reflect UDP length, drop. |
---|
404 | */ |
---|
405 | len = ntohs((u_short)uh->uh_ulen); |
---|
406 | if (ip->ip_len != len) { |
---|
407 | if (len > ip->ip_len || len < sizeof(struct udphdr)) { |
---|
408 | UDPSTAT_INC(udps_badlen); |
---|
409 | goto badunlocked; |
---|
410 | } |
---|
411 | m_adj(m, len - ip->ip_len); |
---|
412 | /* ip->ip_len = len; */ |
---|
413 | } |
---|
414 | |
---|
415 | /* |
---|
416 | * Save a copy of the IP header in case we want restore it for |
---|
417 | * sending an ICMP error message in response. |
---|
418 | */ |
---|
419 | if (!V_udp_blackhole) |
---|
420 | save_ip = *ip; |
---|
421 | else |
---|
422 | memset(&save_ip, 0, sizeof(save_ip)); |
---|
423 | |
---|
424 | /* |
---|
425 | * Checksum extended UDP header and data. |
---|
426 | */ |
---|
427 | if (uh->uh_sum) { |
---|
428 | u_short uh_sum; |
---|
429 | |
---|
430 | if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { |
---|
431 | if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) |
---|
432 | uh_sum = m->m_pkthdr.csum_data; |
---|
433 | else |
---|
434 | uh_sum = in_pseudo(ip->ip_src.s_addr, |
---|
435 | ip->ip_dst.s_addr, htonl((u_short)len + |
---|
436 | m->m_pkthdr.csum_data + IPPROTO_UDP)); |
---|
437 | uh_sum ^= 0xffff; |
---|
438 | } else { |
---|
439 | char b[9]; |
---|
440 | |
---|
441 | bcopy(((struct ipovly *)ip)->ih_x1, b, 9); |
---|
442 | bzero(((struct ipovly *)ip)->ih_x1, 9); |
---|
443 | ((struct ipovly *)ip)->ih_len = uh->uh_ulen; |
---|
444 | uh_sum = in_cksum(m, len + sizeof (struct ip)); |
---|
445 | bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); |
---|
446 | } |
---|
447 | if (uh_sum) { |
---|
448 | UDPSTAT_INC(udps_badsum); |
---|
449 | m_freem(m); |
---|
450 | return; |
---|
451 | } |
---|
452 | } else |
---|
453 | UDPSTAT_INC(udps_nosum); |
---|
454 | |
---|
455 | #ifdef IPFIREWALL_FORWARD |
---|
456 | /* |
---|
457 | * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. |
---|
458 | */ |
---|
459 | fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); |
---|
460 | if (fwd_tag != NULL) { |
---|
461 | struct sockaddr_in *next_hop; |
---|
462 | |
---|
463 | /* |
---|
464 | * Do the hack. |
---|
465 | */ |
---|
466 | next_hop = (struct sockaddr_in *)(fwd_tag + 1); |
---|
467 | ip->ip_dst = next_hop->sin_addr; |
---|
468 | uh->uh_dport = ntohs(next_hop->sin_port); |
---|
469 | |
---|
470 | /* |
---|
471 | * Remove the tag from the packet. We don't need it anymore. |
---|
472 | */ |
---|
473 | m_tag_delete(m, fwd_tag); |
---|
474 | } |
---|
475 | #endif |
---|
476 | |
---|
477 | INP_INFO_RLOCK(&V_udbinfo); |
---|
478 | if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || |
---|
479 | in_broadcast(ip->ip_dst, ifp)) { |
---|
480 | struct inpcb *last; |
---|
481 | struct ip_moptions *imo; |
---|
482 | |
---|
483 | last = NULL; |
---|
484 | LIST_FOREACH(inp, &V_udb, inp_list) { |
---|
485 | if (inp->inp_lport != uh->uh_dport) |
---|
486 | continue; |
---|
487 | #ifdef INET6 |
---|
488 | if ((inp->inp_vflag & INP_IPV4) == 0) |
---|
489 | continue; |
---|
490 | #endif |
---|
491 | if (inp->inp_laddr.s_addr != INADDR_ANY && |
---|
492 | inp->inp_laddr.s_addr != ip->ip_dst.s_addr) |
---|
493 | continue; |
---|
494 | if (inp->inp_faddr.s_addr != INADDR_ANY && |
---|
495 | inp->inp_faddr.s_addr != ip->ip_src.s_addr) |
---|
496 | continue; |
---|
497 | if (inp->inp_fport != 0 && |
---|
498 | inp->inp_fport != uh->uh_sport) |
---|
499 | continue; |
---|
500 | |
---|
501 | INP_RLOCK(inp); |
---|
502 | |
---|
503 | /* |
---|
504 | * Handle socket delivery policy for any-source |
---|
505 | * and source-specific multicast. [RFC3678] |
---|
506 | */ |
---|
507 | imo = inp->inp_moptions; |
---|
508 | if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && |
---|
509 | imo != NULL) { |
---|
510 | struct sockaddr_in group; |
---|
511 | int blocked; |
---|
512 | |
---|
513 | bzero(&group, sizeof(struct sockaddr_in)); |
---|
514 | group.sin_len = sizeof(struct sockaddr_in); |
---|
515 | group.sin_family = AF_INET; |
---|
516 | group.sin_addr = ip->ip_dst; |
---|
517 | |
---|
518 | blocked = imo_multi_filter(imo, ifp, |
---|
519 | (struct sockaddr *)&group, |
---|
520 | (struct sockaddr *)&udp_in); |
---|
521 | if (blocked != MCAST_PASS) { |
---|
522 | if (blocked == MCAST_NOTGMEMBER) |
---|
523 | IPSTAT_INC(ips_notmember); |
---|
524 | if (blocked == MCAST_NOTSMEMBER || |
---|
525 | blocked == MCAST_MUTED) |
---|
526 | UDPSTAT_INC(udps_filtermcast); |
---|
527 | INP_RUNLOCK(inp); |
---|
528 | continue; |
---|
529 | } |
---|
530 | } |
---|
531 | if (last != NULL) { |
---|
532 | struct mbuf *n; |
---|
533 | |
---|
534 | n = m_copy(m, 0, M_COPYALL); |
---|
535 | up = intoudpcb(last); |
---|
536 | if (up->u_tun_func == NULL) { |
---|
537 | if (n != NULL) |
---|
538 | udp_append(last, |
---|
539 | ip, n, |
---|
540 | iphlen + |
---|
541 | sizeof(struct udphdr), |
---|
542 | &udp_in); |
---|
543 | } else { |
---|
544 | /* |
---|
545 | * Engage the tunneling protocol we |
---|
546 | * will have to leave the info_lock |
---|
547 | * up, since we are hunting through |
---|
548 | * multiple UDP's. |
---|
549 | */ |
---|
550 | |
---|
551 | (*up->u_tun_func)(n, iphlen, last); |
---|
552 | } |
---|
553 | INP_RUNLOCK(last); |
---|
554 | } |
---|
555 | last = inp; |
---|
556 | /* |
---|
557 | * Don't look for additional matches if this one does |
---|
558 | * not have either the SO_REUSEPORT or SO_REUSEADDR |
---|
559 | * socket options set. This heuristic avoids |
---|
560 | * searching through all pcbs in the common case of a |
---|
561 | * non-shared port. It assumes that an application |
---|
562 | * will never clear these options after setting them. |
---|
563 | */ |
---|
564 | if ((last->inp_socket->so_options & |
---|
565 | (SO_REUSEPORT|SO_REUSEADDR)) == 0) |
---|
566 | break; |
---|
567 | } |
---|
568 | |
---|
569 | if (last == NULL) { |
---|
570 | /* |
---|
571 | * No matching pcb found; discard datagram. (No need |
---|
572 | * to send an ICMP Port Unreachable for a broadcast |
---|
573 | * or multicast datgram.) |
---|
574 | */ |
---|
575 | UDPSTAT_INC(udps_noportbcast); |
---|
576 | goto badheadlocked; |
---|
577 | } |
---|
578 | up = intoudpcb(last); |
---|
579 | if (up->u_tun_func == NULL) { |
---|
580 | udp_append(last, ip, m, iphlen + sizeof(struct udphdr), |
---|
581 | &udp_in); |
---|
582 | } else { |
---|
583 | /* |
---|
584 | * Engage the tunneling protocol. |
---|
585 | */ |
---|
586 | (*up->u_tun_func)(m, iphlen, last); |
---|
587 | } |
---|
588 | INP_RUNLOCK(last); |
---|
589 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
590 | return; |
---|
591 | } |
---|
592 | |
---|
593 | /* |
---|
594 | * Locate pcb for datagram. |
---|
595 | */ |
---|
596 | inp = in_pcblookup_hash(&V_udbinfo, ip->ip_src, uh->uh_sport, |
---|
597 | ip->ip_dst, uh->uh_dport, 1, ifp); |
---|
598 | if (inp == NULL) { |
---|
599 | if (udp_log_in_vain) { |
---|
600 | char buf[4*sizeof "123"]; |
---|
601 | |
---|
602 | strcpy(buf, inet_ntoa(ip->ip_dst)); |
---|
603 | log(LOG_INFO, |
---|
604 | "Connection attempt to UDP %s:%d from %s:%d\n", |
---|
605 | buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), |
---|
606 | ntohs(uh->uh_sport)); |
---|
607 | } |
---|
608 | UDPSTAT_INC(udps_noport); |
---|
609 | if (m->m_flags & (M_BCAST | M_MCAST)) { |
---|
610 | UDPSTAT_INC(udps_noportbcast); |
---|
611 | goto badheadlocked; |
---|
612 | } |
---|
613 | if (V_udp_blackhole) |
---|
614 | goto badheadlocked; |
---|
615 | if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0) |
---|
616 | goto badheadlocked; |
---|
617 | *ip = save_ip; |
---|
618 | ip->ip_len += iphlen; |
---|
619 | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); |
---|
620 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
621 | return; |
---|
622 | } |
---|
623 | |
---|
624 | /* |
---|
625 | * Check the minimum TTL for socket. |
---|
626 | */ |
---|
627 | INP_RLOCK(inp); |
---|
628 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
629 | if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) { |
---|
630 | INP_RUNLOCK(inp); |
---|
631 | goto badunlocked; |
---|
632 | } |
---|
633 | up = intoudpcb(inp); |
---|
634 | if (up->u_tun_func == NULL) { |
---|
635 | udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in); |
---|
636 | } else { |
---|
637 | /* |
---|
638 | * Engage the tunneling protocol. |
---|
639 | */ |
---|
640 | |
---|
641 | (*up->u_tun_func)(m, iphlen, inp); |
---|
642 | } |
---|
643 | INP_RUNLOCK(inp); |
---|
644 | return; |
---|
645 | |
---|
646 | badheadlocked: |
---|
647 | if (inp) |
---|
648 | INP_RUNLOCK(inp); |
---|
649 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
650 | badunlocked: |
---|
651 | m_freem(m); |
---|
652 | } |
---|
653 | |
---|
654 | /* |
---|
655 | * Notify a udp user of an asynchronous error; just wake up so that they can |
---|
656 | * collect error status. |
---|
657 | */ |
---|
658 | struct inpcb * |
---|
659 | udp_notify(struct inpcb *inp, int errno) |
---|
660 | { |
---|
661 | |
---|
662 | /* |
---|
663 | * While udp_ctlinput() always calls udp_notify() with a read lock |
---|
664 | * when invoking it directly, in_pcbnotifyall() currently uses write |
---|
665 | * locks due to sharing code with TCP. For now, accept either a read |
---|
666 | * or a write lock, but a read lock is sufficient. |
---|
667 | */ |
---|
668 | INP_LOCK_ASSERT(inp); |
---|
669 | |
---|
670 | inp->inp_socket->so_error = errno; |
---|
671 | sorwakeup(inp->inp_socket); |
---|
672 | sowwakeup(inp->inp_socket); |
---|
673 | return (inp); |
---|
674 | } |
---|
675 | |
---|
676 | void |
---|
677 | udp_ctlinput(int cmd, struct sockaddr *sa, void *vip) |
---|
678 | { |
---|
679 | struct ip *ip = vip; |
---|
680 | struct udphdr *uh; |
---|
681 | struct in_addr faddr; |
---|
682 | struct inpcb *inp; |
---|
683 | |
---|
684 | faddr = ((struct sockaddr_in *)sa)->sin_addr; |
---|
685 | if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) |
---|
686 | return; |
---|
687 | |
---|
688 | /* |
---|
689 | * Redirects don't need to be handled up here. |
---|
690 | */ |
---|
691 | if (PRC_IS_REDIRECT(cmd)) |
---|
692 | return; |
---|
693 | |
---|
694 | /* |
---|
695 | * Hostdead is ugly because it goes linearly through all PCBs. |
---|
696 | * |
---|
697 | * XXX: We never get this from ICMP, otherwise it makes an excellent |
---|
698 | * DoS attack on machines with many connections. |
---|
699 | */ |
---|
700 | if (cmd == PRC_HOSTDEAD) |
---|
701 | ip = NULL; |
---|
702 | else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) |
---|
703 | return; |
---|
704 | if (ip != NULL) { |
---|
705 | uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); |
---|
706 | INP_INFO_RLOCK(&V_udbinfo); |
---|
707 | inp = in_pcblookup_hash(&V_udbinfo, faddr, uh->uh_dport, |
---|
708 | ip->ip_src, uh->uh_sport, 0, NULL); |
---|
709 | if (inp != NULL) { |
---|
710 | INP_RLOCK(inp); |
---|
711 | if (inp->inp_socket != NULL) { |
---|
712 | udp_notify(inp, inetctlerrmap[cmd]); |
---|
713 | } |
---|
714 | INP_RUNLOCK(inp); |
---|
715 | } |
---|
716 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
717 | } else |
---|
718 | in_pcbnotifyall(&V_udbinfo, faddr, inetctlerrmap[cmd], |
---|
719 | udp_notify); |
---|
720 | } |
---|
721 | |
---|
722 | static int |
---|
723 | udp_pcblist(SYSCTL_HANDLER_ARGS) |
---|
724 | { |
---|
725 | int error, i, n; |
---|
726 | struct inpcb *inp, **inp_list; |
---|
727 | inp_gen_t gencnt; |
---|
728 | struct xinpgen xig; |
---|
729 | |
---|
730 | /* |
---|
731 | * The process of preparing the PCB list is too time-consuming and |
---|
732 | * resource-intensive to repeat twice on every request. |
---|
733 | */ |
---|
734 | if (req->oldptr == 0) { |
---|
735 | n = V_udbinfo.ipi_count; |
---|
736 | n += imax(n / 8, 10); |
---|
737 | req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb); |
---|
738 | return (0); |
---|
739 | } |
---|
740 | |
---|
741 | if (req->newptr != 0) |
---|
742 | return (EPERM); |
---|
743 | |
---|
744 | /* |
---|
745 | * OK, now we're committed to doing something. |
---|
746 | */ |
---|
747 | INP_INFO_RLOCK(&V_udbinfo); |
---|
748 | gencnt = V_udbinfo.ipi_gencnt; |
---|
749 | n = V_udbinfo.ipi_count; |
---|
750 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
751 | |
---|
752 | error = sysctl_wire_old_buffer(req, 2 * (sizeof xig) |
---|
753 | + n * sizeof(struct xinpcb)); |
---|
754 | if (error != 0) |
---|
755 | return (error); |
---|
756 | |
---|
757 | xig.xig_len = sizeof xig; |
---|
758 | xig.xig_count = n; |
---|
759 | xig.xig_gen = gencnt; |
---|
760 | xig.xig_sogen = so_gencnt; |
---|
761 | error = SYSCTL_OUT(req, &xig, sizeof xig); |
---|
762 | if (error) |
---|
763 | return (error); |
---|
764 | |
---|
765 | inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); |
---|
766 | if (inp_list == 0) |
---|
767 | return (ENOMEM); |
---|
768 | |
---|
769 | INP_INFO_RLOCK(&V_udbinfo); |
---|
770 | for (inp = LIST_FIRST(V_udbinfo.ipi_listhead), i = 0; inp && i < n; |
---|
771 | inp = LIST_NEXT(inp, inp_list)) { |
---|
772 | INP_WLOCK(inp); |
---|
773 | if (inp->inp_gencnt <= gencnt && |
---|
774 | cr_canseeinpcb(req->td->td_ucred, inp) == 0) { |
---|
775 | in_pcbref(inp); |
---|
776 | inp_list[i++] = inp; |
---|
777 | } |
---|
778 | INP_WUNLOCK(inp); |
---|
779 | } |
---|
780 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
781 | n = i; |
---|
782 | |
---|
783 | error = 0; |
---|
784 | for (i = 0; i < n; i++) { |
---|
785 | inp = inp_list[i]; |
---|
786 | INP_RLOCK(inp); |
---|
787 | if (inp->inp_gencnt <= gencnt) { |
---|
788 | struct xinpcb xi; |
---|
789 | |
---|
790 | bzero(&xi, sizeof(xi)); |
---|
791 | xi.xi_len = sizeof xi; |
---|
792 | /* XXX should avoid extra copy */ |
---|
793 | bcopy(inp, &xi.xi_inp, sizeof *inp); |
---|
794 | if (inp->inp_socket) |
---|
795 | sotoxsocket(inp->inp_socket, &xi.xi_socket); |
---|
796 | xi.xi_inp.inp_gencnt = inp->inp_gencnt; |
---|
797 | INP_RUNLOCK(inp); |
---|
798 | error = SYSCTL_OUT(req, &xi, sizeof xi); |
---|
799 | } else |
---|
800 | INP_RUNLOCK(inp); |
---|
801 | } |
---|
802 | INP_INFO_WLOCK(&V_udbinfo); |
---|
803 | for (i = 0; i < n; i++) { |
---|
804 | inp = inp_list[i]; |
---|
805 | INP_WLOCK(inp); |
---|
806 | if (!in_pcbrele(inp)) |
---|
807 | INP_WUNLOCK(inp); |
---|
808 | } |
---|
809 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
810 | |
---|
811 | if (!error) { |
---|
812 | /* |
---|
813 | * Give the user an updated idea of our state. If the |
---|
814 | * generation differs from what we told her before, she knows |
---|
815 | * that something happened while we were processing this |
---|
816 | * request, and it might be necessary to retry. |
---|
817 | */ |
---|
818 | INP_INFO_RLOCK(&V_udbinfo); |
---|
819 | xig.xig_gen = V_udbinfo.ipi_gencnt; |
---|
820 | xig.xig_sogen = so_gencnt; |
---|
821 | xig.xig_count = V_udbinfo.ipi_count; |
---|
822 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
823 | error = SYSCTL_OUT(req, &xig, sizeof xig); |
---|
824 | } |
---|
825 | free(inp_list, M_TEMP); |
---|
826 | return (error); |
---|
827 | } |
---|
828 | |
---|
829 | SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, |
---|
830 | udp_pcblist, "S,xinpcb", "List of active UDP sockets"); |
---|
831 | |
---|
832 | static int |
---|
833 | udp_getcred(SYSCTL_HANDLER_ARGS) |
---|
834 | { |
---|
835 | struct xucred xuc; |
---|
836 | struct sockaddr_in addrs[2]; |
---|
837 | struct inpcb *inp; |
---|
838 | int error; |
---|
839 | |
---|
840 | error = priv_check(req->td, PRIV_NETINET_GETCRED); |
---|
841 | if (error) |
---|
842 | return (error); |
---|
843 | error = SYSCTL_IN(req, addrs, sizeof(addrs)); |
---|
844 | if (error) |
---|
845 | return (error); |
---|
846 | INP_INFO_RLOCK(&V_udbinfo); |
---|
847 | inp = in_pcblookup_hash(&V_udbinfo, addrs[1].sin_addr, addrs[1].sin_port, |
---|
848 | addrs[0].sin_addr, addrs[0].sin_port, 1, NULL); |
---|
849 | if (inp != NULL) { |
---|
850 | INP_RLOCK(inp); |
---|
851 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
852 | if (inp->inp_socket == NULL) |
---|
853 | error = ENOENT; |
---|
854 | if (error == 0) |
---|
855 | error = cr_canseeinpcb(req->td->td_ucred, inp); |
---|
856 | if (error == 0) |
---|
857 | cru2x(inp->inp_cred, &xuc); |
---|
858 | INP_RUNLOCK(inp); |
---|
859 | } else { |
---|
860 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
861 | error = ENOENT; |
---|
862 | } |
---|
863 | if (error == 0) |
---|
864 | error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); |
---|
865 | return (error); |
---|
866 | } |
---|
867 | |
---|
868 | SYSCTL_PROC(_net_inet_udp, OID_AUTO, getcred, |
---|
869 | CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, |
---|
870 | udp_getcred, "S,xucred", "Get the xucred of a UDP connection"); |
---|
871 | |
---|
872 | int |
---|
873 | udp_ctloutput(struct socket *so, struct sockopt *sopt) |
---|
874 | { |
---|
875 | int error = 0, optval; |
---|
876 | struct inpcb *inp; |
---|
877 | #ifdef IPSEC_NAT_T |
---|
878 | struct udpcb *up; |
---|
879 | #endif |
---|
880 | |
---|
881 | inp = sotoinpcb(so); |
---|
882 | KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); |
---|
883 | INP_WLOCK(inp); |
---|
884 | if (sopt->sopt_level != IPPROTO_UDP) { |
---|
885 | #ifdef INET6 |
---|
886 | if (INP_CHECK_SOCKAF(so, AF_INET6)) { |
---|
887 | INP_WUNLOCK(inp); |
---|
888 | error = ip6_ctloutput(so, sopt); |
---|
889 | } else { |
---|
890 | #endif |
---|
891 | INP_WUNLOCK(inp); |
---|
892 | error = ip_ctloutput(so, sopt); |
---|
893 | #ifdef INET6 |
---|
894 | } |
---|
895 | #endif |
---|
896 | return (error); |
---|
897 | } |
---|
898 | |
---|
899 | switch (sopt->sopt_dir) { |
---|
900 | case SOPT_SET: |
---|
901 | switch (sopt->sopt_name) { |
---|
902 | case UDP_ENCAP: |
---|
903 | INP_WUNLOCK(inp); |
---|
904 | error = sooptcopyin(sopt, &optval, sizeof optval, |
---|
905 | sizeof optval); |
---|
906 | if (error) |
---|
907 | break; |
---|
908 | inp = sotoinpcb(so); |
---|
909 | KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); |
---|
910 | INP_WLOCK(inp); |
---|
911 | #ifdef IPSEC_NAT_T |
---|
912 | up = intoudpcb(inp); |
---|
913 | KASSERT(up != NULL, ("%s: up == NULL", __func__)); |
---|
914 | #endif |
---|
915 | switch (optval) { |
---|
916 | case 0: |
---|
917 | /* Clear all UDP encap. */ |
---|
918 | #ifdef IPSEC_NAT_T |
---|
919 | up->u_flags &= ~UF_ESPINUDP_ALL; |
---|
920 | #endif |
---|
921 | break; |
---|
922 | #ifdef IPSEC_NAT_T |
---|
923 | case UDP_ENCAP_ESPINUDP: |
---|
924 | case UDP_ENCAP_ESPINUDP_NON_IKE: |
---|
925 | up->u_flags &= ~UF_ESPINUDP_ALL; |
---|
926 | if (optval == UDP_ENCAP_ESPINUDP) |
---|
927 | up->u_flags |= UF_ESPINUDP; |
---|
928 | else if (optval == UDP_ENCAP_ESPINUDP_NON_IKE) |
---|
929 | up->u_flags |= UF_ESPINUDP_NON_IKE; |
---|
930 | break; |
---|
931 | #endif |
---|
932 | default: |
---|
933 | error = EINVAL; |
---|
934 | break; |
---|
935 | } |
---|
936 | INP_WUNLOCK(inp); |
---|
937 | break; |
---|
938 | default: |
---|
939 | INP_WUNLOCK(inp); |
---|
940 | error = ENOPROTOOPT; |
---|
941 | break; |
---|
942 | } |
---|
943 | break; |
---|
944 | case SOPT_GET: |
---|
945 | switch (sopt->sopt_name) { |
---|
946 | #ifdef IPSEC_NAT_T |
---|
947 | case UDP_ENCAP: |
---|
948 | up = intoudpcb(inp); |
---|
949 | KASSERT(up != NULL, ("%s: up == NULL", __func__)); |
---|
950 | optval = up->u_flags & UF_ESPINUDP_ALL; |
---|
951 | INP_WUNLOCK(inp); |
---|
952 | error = sooptcopyout(sopt, &optval, sizeof optval); |
---|
953 | break; |
---|
954 | #endif |
---|
955 | default: |
---|
956 | INP_WUNLOCK(inp); |
---|
957 | error = ENOPROTOOPT; |
---|
958 | break; |
---|
959 | } |
---|
960 | break; |
---|
961 | } |
---|
962 | return (error); |
---|
963 | } |
---|
964 | |
---|
965 | static int |
---|
966 | udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, |
---|
967 | struct mbuf *control, struct thread *td) |
---|
968 | { |
---|
969 | struct udpiphdr *ui; |
---|
970 | int len = m->m_pkthdr.len; |
---|
971 | struct in_addr faddr, laddr; |
---|
972 | struct cmsghdr *cm; |
---|
973 | struct sockaddr_in *sin, src; |
---|
974 | int error = 0; |
---|
975 | int ipflags; |
---|
976 | u_short fport, lport; |
---|
977 | int unlock_udbinfo; |
---|
978 | |
---|
979 | /* |
---|
980 | * udp_output() may need to temporarily bind or connect the current |
---|
981 | * inpcb. As such, we don't know up front whether we will need the |
---|
982 | * pcbinfo lock or not. Do any work to decide what is needed up |
---|
983 | * front before acquiring any locks. |
---|
984 | */ |
---|
985 | if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { |
---|
986 | if (control) |
---|
987 | m_freem(control); |
---|
988 | m_freem(m); |
---|
989 | return (EMSGSIZE); |
---|
990 | } |
---|
991 | |
---|
992 | src.sin_family = 0; |
---|
993 | if (control != NULL) { |
---|
994 | /* |
---|
995 | * XXX: Currently, we assume all the optional information is |
---|
996 | * stored in a single mbuf. |
---|
997 | */ |
---|
998 | if (control->m_next) { |
---|
999 | m_freem(control); |
---|
1000 | m_freem(m); |
---|
1001 | return (EINVAL); |
---|
1002 | } |
---|
1003 | for (; control->m_len > 0; |
---|
1004 | control->m_data += CMSG_ALIGN(cm->cmsg_len), |
---|
1005 | control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { |
---|
1006 | cm = mtod(control, struct cmsghdr *); |
---|
1007 | if (control->m_len < sizeof(*cm) || cm->cmsg_len == 0 |
---|
1008 | || cm->cmsg_len > control->m_len) { |
---|
1009 | error = EINVAL; |
---|
1010 | break; |
---|
1011 | } |
---|
1012 | if (cm->cmsg_level != IPPROTO_IP) |
---|
1013 | continue; |
---|
1014 | |
---|
1015 | switch (cm->cmsg_type) { |
---|
1016 | case IP_SENDSRCADDR: |
---|
1017 | if (cm->cmsg_len != |
---|
1018 | CMSG_LEN(sizeof(struct in_addr))) { |
---|
1019 | error = EINVAL; |
---|
1020 | break; |
---|
1021 | } |
---|
1022 | bzero(&src, sizeof(src)); |
---|
1023 | src.sin_family = AF_INET; |
---|
1024 | src.sin_len = sizeof(src); |
---|
1025 | src.sin_port = inp->inp_lport; |
---|
1026 | src.sin_addr = |
---|
1027 | *(struct in_addr *)CMSG_DATA(cm); |
---|
1028 | break; |
---|
1029 | |
---|
1030 | default: |
---|
1031 | error = ENOPROTOOPT; |
---|
1032 | break; |
---|
1033 | } |
---|
1034 | if (error) |
---|
1035 | break; |
---|
1036 | } |
---|
1037 | m_freem(control); |
---|
1038 | } |
---|
1039 | if (error) { |
---|
1040 | m_freem(m); |
---|
1041 | return (error); |
---|
1042 | } |
---|
1043 | |
---|
1044 | /* |
---|
1045 | * Depending on whether or not the application has bound or connected |
---|
1046 | * the socket, we may have to do varying levels of work. The optimal |
---|
1047 | * case is for a connected UDP socket, as a global lock isn't |
---|
1048 | * required at all. |
---|
1049 | * |
---|
1050 | * In order to decide which we need, we require stability of the |
---|
1051 | * inpcb binding, which we ensure by acquiring a read lock on the |
---|
1052 | * inpcb. This doesn't strictly follow the lock order, so we play |
---|
1053 | * the trylock and retry game; note that we may end up with more |
---|
1054 | * conservative locks than required the second time around, so later |
---|
1055 | * assertions have to accept that. Further analysis of the number of |
---|
1056 | * misses under contention is required. |
---|
1057 | */ |
---|
1058 | sin = (struct sockaddr_in *)addr; |
---|
1059 | INP_RLOCK(inp); |
---|
1060 | if (sin != NULL && |
---|
1061 | (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0)) { |
---|
1062 | INP_RUNLOCK(inp); |
---|
1063 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1064 | INP_WLOCK(inp); |
---|
1065 | unlock_udbinfo = 2; |
---|
1066 | } else if ((sin != NULL && ( |
---|
1067 | (sin->sin_addr.s_addr == INADDR_ANY) || |
---|
1068 | (sin->sin_addr.s_addr == INADDR_BROADCAST) || |
---|
1069 | (inp->inp_laddr.s_addr == INADDR_ANY) || |
---|
1070 | (inp->inp_lport == 0))) || |
---|
1071 | (src.sin_family == AF_INET)) { |
---|
1072 | if (!INP_INFO_TRY_RLOCK(&V_udbinfo)) { |
---|
1073 | INP_RUNLOCK(inp); |
---|
1074 | INP_INFO_RLOCK(&V_udbinfo); |
---|
1075 | INP_RLOCK(inp); |
---|
1076 | } |
---|
1077 | unlock_udbinfo = 1; |
---|
1078 | } else |
---|
1079 | unlock_udbinfo = 0; |
---|
1080 | |
---|
1081 | /* |
---|
1082 | * If the IP_SENDSRCADDR control message was specified, override the |
---|
1083 | * source address for this datagram. Its use is invalidated if the |
---|
1084 | * address thus specified is incomplete or clobbers other inpcbs. |
---|
1085 | */ |
---|
1086 | laddr = inp->inp_laddr; |
---|
1087 | lport = inp->inp_lport; |
---|
1088 | if (src.sin_family == AF_INET) { |
---|
1089 | INP_INFO_LOCK_ASSERT(&V_udbinfo); |
---|
1090 | if ((lport == 0) || |
---|
1091 | (laddr.s_addr == INADDR_ANY && |
---|
1092 | src.sin_addr.s_addr == INADDR_ANY)) { |
---|
1093 | error = EINVAL; |
---|
1094 | goto release; |
---|
1095 | } |
---|
1096 | error = in_pcbbind_setup(inp, (struct sockaddr *)&src, |
---|
1097 | &laddr.s_addr, &lport, td->td_ucred); |
---|
1098 | if (error) |
---|
1099 | goto release; |
---|
1100 | } |
---|
1101 | |
---|
1102 | /* |
---|
1103 | * If a UDP socket has been connected, then a local address/port will |
---|
1104 | * have been selected and bound. |
---|
1105 | * |
---|
1106 | * If a UDP socket has not been connected to, then an explicit |
---|
1107 | * destination address must be used, in which case a local |
---|
1108 | * address/port may not have been selected and bound. |
---|
1109 | */ |
---|
1110 | if (sin != NULL) { |
---|
1111 | INP_LOCK_ASSERT(inp); |
---|
1112 | if (inp->inp_faddr.s_addr != INADDR_ANY) { |
---|
1113 | error = EISCONN; |
---|
1114 | goto release; |
---|
1115 | } |
---|
1116 | |
---|
1117 | /* |
---|
1118 | * Jail may rewrite the destination address, so let it do |
---|
1119 | * that before we use it. |
---|
1120 | */ |
---|
1121 | error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); |
---|
1122 | if (error) |
---|
1123 | goto release; |
---|
1124 | |
---|
1125 | /* |
---|
1126 | * If a local address or port hasn't yet been selected, or if |
---|
1127 | * the destination address needs to be rewritten due to using |
---|
1128 | * a special INADDR_ constant, invoke in_pcbconnect_setup() |
---|
1129 | * to do the heavy lifting. Once a port is selected, we |
---|
1130 | * commit the binding back to the socket; we also commit the |
---|
1131 | * binding of the address if in jail. |
---|
1132 | * |
---|
1133 | * If we already have a valid binding and we're not |
---|
1134 | * requesting a destination address rewrite, use a fast path. |
---|
1135 | */ |
---|
1136 | if (inp->inp_laddr.s_addr == INADDR_ANY || |
---|
1137 | inp->inp_lport == 0 || |
---|
1138 | sin->sin_addr.s_addr == INADDR_ANY || |
---|
1139 | sin->sin_addr.s_addr == INADDR_BROADCAST) { |
---|
1140 | INP_INFO_LOCK_ASSERT(&V_udbinfo); |
---|
1141 | error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, |
---|
1142 | &lport, &faddr.s_addr, &fport, NULL, |
---|
1143 | td->td_ucred); |
---|
1144 | if (error) |
---|
1145 | goto release; |
---|
1146 | |
---|
1147 | /* |
---|
1148 | * XXXRW: Why not commit the port if the address is |
---|
1149 | * !INADDR_ANY? |
---|
1150 | */ |
---|
1151 | /* Commit the local port if newly assigned. */ |
---|
1152 | if (inp->inp_laddr.s_addr == INADDR_ANY && |
---|
1153 | inp->inp_lport == 0) { |
---|
1154 | INP_INFO_WLOCK_ASSERT(&V_udbinfo); |
---|
1155 | INP_WLOCK_ASSERT(inp); |
---|
1156 | /* |
---|
1157 | * Remember addr if jailed, to prevent |
---|
1158 | * rebinding. |
---|
1159 | */ |
---|
1160 | if (prison_flag(td->td_ucred, PR_IP4)) |
---|
1161 | inp->inp_laddr = laddr; |
---|
1162 | inp->inp_lport = lport; |
---|
1163 | if (in_pcbinshash(inp) != 0) { |
---|
1164 | inp->inp_lport = 0; |
---|
1165 | error = EAGAIN; |
---|
1166 | goto release; |
---|
1167 | } |
---|
1168 | inp->inp_flags |= INP_ANONPORT; |
---|
1169 | } |
---|
1170 | } else { |
---|
1171 | faddr = sin->sin_addr; |
---|
1172 | fport = sin->sin_port; |
---|
1173 | } |
---|
1174 | } else { |
---|
1175 | INP_LOCK_ASSERT(inp); |
---|
1176 | faddr = inp->inp_faddr; |
---|
1177 | fport = inp->inp_fport; |
---|
1178 | if (faddr.s_addr == INADDR_ANY) { |
---|
1179 | error = ENOTCONN; |
---|
1180 | goto release; |
---|
1181 | } |
---|
1182 | } |
---|
1183 | |
---|
1184 | /* |
---|
1185 | * Calculate data length and get a mbuf for UDP, IP, and possible |
---|
1186 | * link-layer headers. Immediate slide the data pointer back forward |
---|
1187 | * since we won't use that space at this layer. |
---|
1188 | */ |
---|
1189 | M_PREPEND(m, sizeof(struct udpiphdr) + max_linkhdr, M_DONTWAIT); |
---|
1190 | if (m == NULL) { |
---|
1191 | error = ENOBUFS; |
---|
1192 | goto release; |
---|
1193 | } |
---|
1194 | m->m_data += max_linkhdr; |
---|
1195 | m->m_len -= max_linkhdr; |
---|
1196 | m->m_pkthdr.len -= max_linkhdr; |
---|
1197 | |
---|
1198 | /* |
---|
1199 | * Fill in mbuf with extended UDP header and addresses and length put |
---|
1200 | * into network format. |
---|
1201 | */ |
---|
1202 | ui = mtod(m, struct udpiphdr *); |
---|
1203 | bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */ |
---|
1204 | ui->ui_pr = IPPROTO_UDP; |
---|
1205 | ui->ui_src = laddr; |
---|
1206 | ui->ui_dst = faddr; |
---|
1207 | ui->ui_sport = lport; |
---|
1208 | ui->ui_dport = fport; |
---|
1209 | ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr)); |
---|
1210 | |
---|
1211 | /* |
---|
1212 | * Set the Don't Fragment bit in the IP header. |
---|
1213 | */ |
---|
1214 | if (inp->inp_flags & INP_DONTFRAG) { |
---|
1215 | struct ip *ip; |
---|
1216 | |
---|
1217 | ip = (struct ip *)&ui->ui_i; |
---|
1218 | ip->ip_off |= IP_DF; |
---|
1219 | } |
---|
1220 | |
---|
1221 | ipflags = 0; |
---|
1222 | if (inp->inp_socket->so_options & SO_DONTROUTE) |
---|
1223 | ipflags |= IP_ROUTETOIF; |
---|
1224 | if (inp->inp_socket->so_options & SO_BROADCAST) |
---|
1225 | ipflags |= IP_ALLOWBROADCAST; |
---|
1226 | if (inp->inp_flags & INP_ONESBCAST) |
---|
1227 | ipflags |= IP_SENDONES; |
---|
1228 | |
---|
1229 | #ifdef MAC |
---|
1230 | mac_inpcb_create_mbuf(inp, m); |
---|
1231 | #endif |
---|
1232 | |
---|
1233 | /* |
---|
1234 | * Set up checksum and output datagram. |
---|
1235 | */ |
---|
1236 | if (udp_cksum) { |
---|
1237 | if (inp->inp_flags & INP_ONESBCAST) |
---|
1238 | faddr.s_addr = INADDR_BROADCAST; |
---|
1239 | ui->ui_sum = in_pseudo(ui->ui_src.s_addr, faddr.s_addr, |
---|
1240 | htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP)); |
---|
1241 | m->m_pkthdr.csum_flags = CSUM_UDP; |
---|
1242 | m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); |
---|
1243 | } else |
---|
1244 | ui->ui_sum = 0; |
---|
1245 | ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; |
---|
1246 | ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ |
---|
1247 | ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ |
---|
1248 | UDPSTAT_INC(udps_opackets); |
---|
1249 | |
---|
1250 | if (unlock_udbinfo == 2) |
---|
1251 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1252 | else if (unlock_udbinfo == 1) |
---|
1253 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
1254 | error = ip_output(m, inp->inp_options, NULL, ipflags, |
---|
1255 | inp->inp_moptions, inp); |
---|
1256 | if (unlock_udbinfo == 2) |
---|
1257 | INP_WUNLOCK(inp); |
---|
1258 | else |
---|
1259 | INP_RUNLOCK(inp); |
---|
1260 | return (error); |
---|
1261 | |
---|
1262 | release: |
---|
1263 | if (unlock_udbinfo == 2) { |
---|
1264 | INP_WUNLOCK(inp); |
---|
1265 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1266 | } else if (unlock_udbinfo == 1) { |
---|
1267 | INP_RUNLOCK(inp); |
---|
1268 | INP_INFO_RUNLOCK(&V_udbinfo); |
---|
1269 | } else |
---|
1270 | INP_RUNLOCK(inp); |
---|
1271 | m_freem(m); |
---|
1272 | return (error); |
---|
1273 | } |
---|
1274 | |
---|
1275 | |
---|
1276 | #if defined(IPSEC) && defined(IPSEC_NAT_T) |
---|
1277 | #ifdef INET |
---|
1278 | /* |
---|
1279 | * Potentially decap ESP in UDP frame. Check for an ESP header |
---|
1280 | * and optional marker; if present, strip the UDP header and |
---|
1281 | * push the result through IPSec. |
---|
1282 | * |
---|
1283 | * Returns mbuf to be processed (potentially re-allocated) or |
---|
1284 | * NULL if consumed and/or processed. |
---|
1285 | */ |
---|
1286 | static struct mbuf * |
---|
1287 | udp4_espdecap(struct inpcb *inp, struct mbuf *m, int off) |
---|
1288 | { |
---|
1289 | size_t minlen, payload, skip, iphlen; |
---|
1290 | caddr_t data; |
---|
1291 | struct udpcb *up; |
---|
1292 | struct m_tag *tag; |
---|
1293 | struct udphdr *udphdr; |
---|
1294 | struct ip *ip; |
---|
1295 | |
---|
1296 | INP_RLOCK_ASSERT(inp); |
---|
1297 | |
---|
1298 | /* |
---|
1299 | * Pull up data so the longest case is contiguous: |
---|
1300 | * IP/UDP hdr + non ESP marker + ESP hdr. |
---|
1301 | */ |
---|
1302 | minlen = off + sizeof(uint64_t) + sizeof(struct esp); |
---|
1303 | if (minlen > m->m_pkthdr.len) |
---|
1304 | minlen = m->m_pkthdr.len; |
---|
1305 | if ((m = m_pullup(m, minlen)) == NULL) { |
---|
1306 | V_ipsec4stat.in_inval++; |
---|
1307 | return (NULL); /* Bypass caller processing. */ |
---|
1308 | } |
---|
1309 | data = mtod(m, caddr_t); /* Points to ip header. */ |
---|
1310 | payload = m->m_len - off; /* Size of payload. */ |
---|
1311 | |
---|
1312 | if (payload == 1 && data[off] == '\xff') |
---|
1313 | return (m); /* NB: keepalive packet, no decap. */ |
---|
1314 | |
---|
1315 | up = intoudpcb(inp); |
---|
1316 | KASSERT(up != NULL, ("%s: udpcb NULL", __func__)); |
---|
1317 | KASSERT((up->u_flags & UF_ESPINUDP_ALL) != 0, |
---|
1318 | ("u_flags 0x%x", up->u_flags)); |
---|
1319 | |
---|
1320 | /* |
---|
1321 | * Check that the payload is large enough to hold an |
---|
1322 | * ESP header and compute the amount of data to remove. |
---|
1323 | * |
---|
1324 | * NB: the caller has already done a pullup for us. |
---|
1325 | * XXX can we assume alignment and eliminate bcopys? |
---|
1326 | */ |
---|
1327 | if (up->u_flags & UF_ESPINUDP_NON_IKE) { |
---|
1328 | /* |
---|
1329 | * draft-ietf-ipsec-nat-t-ike-0[01].txt and |
---|
1330 | * draft-ietf-ipsec-udp-encaps-(00/)01.txt, ignoring |
---|
1331 | * possible AH mode non-IKE marker+non-ESP marker |
---|
1332 | * from draft-ietf-ipsec-udp-encaps-00.txt. |
---|
1333 | */ |
---|
1334 | uint64_t marker; |
---|
1335 | |
---|
1336 | if (payload <= sizeof(uint64_t) + sizeof(struct esp)) |
---|
1337 | return (m); /* NB: no decap. */ |
---|
1338 | bcopy(data + off, &marker, sizeof(uint64_t)); |
---|
1339 | if (marker != 0) /* Non-IKE marker. */ |
---|
1340 | return (m); /* NB: no decap. */ |
---|
1341 | skip = sizeof(uint64_t) + sizeof(struct udphdr); |
---|
1342 | } else { |
---|
1343 | uint32_t spi; |
---|
1344 | |
---|
1345 | if (payload <= sizeof(struct esp)) { |
---|
1346 | V_ipsec4stat.in_inval++; |
---|
1347 | m_freem(m); |
---|
1348 | return (NULL); /* Discard. */ |
---|
1349 | } |
---|
1350 | bcopy(data + off, &spi, sizeof(uint32_t)); |
---|
1351 | if (spi == 0) /* Non-ESP marker. */ |
---|
1352 | return (m); /* NB: no decap. */ |
---|
1353 | skip = sizeof(struct udphdr); |
---|
1354 | } |
---|
1355 | |
---|
1356 | /* |
---|
1357 | * Setup a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember |
---|
1358 | * the UDP ports. This is required if we want to select |
---|
1359 | * the right SPD for multiple hosts behind same NAT. |
---|
1360 | * |
---|
1361 | * NB: ports are maintained in network byte order everywhere |
---|
1362 | * in the NAT-T code. |
---|
1363 | */ |
---|
1364 | tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS, |
---|
1365 | 2 * sizeof(uint16_t), M_NOWAIT); |
---|
1366 | if (tag == NULL) { |
---|
1367 | V_ipsec4stat.in_nomem++; |
---|
1368 | m_freem(m); |
---|
1369 | return (NULL); /* Discard. */ |
---|
1370 | } |
---|
1371 | iphlen = off - sizeof(struct udphdr); |
---|
1372 | udphdr = (struct udphdr *)(data + iphlen); |
---|
1373 | ((uint16_t *)(tag + 1))[0] = udphdr->uh_sport; |
---|
1374 | ((uint16_t *)(tag + 1))[1] = udphdr->uh_dport; |
---|
1375 | m_tag_prepend(m, tag); |
---|
1376 | |
---|
1377 | /* |
---|
1378 | * Remove the UDP header (and possibly the non ESP marker) |
---|
1379 | * IP header length is iphlen |
---|
1380 | * Before: |
---|
1381 | * <--- off ---> |
---|
1382 | * +----+------+-----+ |
---|
1383 | * | IP | UDP | ESP | |
---|
1384 | * +----+------+-----+ |
---|
1385 | * <-skip-> |
---|
1386 | * After: |
---|
1387 | * +----+-----+ |
---|
1388 | * | IP | ESP | |
---|
1389 | * +----+-----+ |
---|
1390 | * <-skip-> |
---|
1391 | */ |
---|
1392 | ovbcopy(data, data + skip, iphlen); |
---|
1393 | m_adj(m, skip); |
---|
1394 | |
---|
1395 | ip = mtod(m, struct ip *); |
---|
1396 | ip->ip_len -= skip; |
---|
1397 | ip->ip_p = IPPROTO_ESP; |
---|
1398 | |
---|
1399 | /* |
---|
1400 | * We cannot yet update the cksums so clear any |
---|
1401 | * h/w cksum flags as they are no longer valid. |
---|
1402 | */ |
---|
1403 | if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) |
---|
1404 | m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID|CSUM_PSEUDO_HDR); |
---|
1405 | |
---|
1406 | (void) ipsec4_common_input(m, iphlen, ip->ip_p); |
---|
1407 | return (NULL); /* NB: consumed, bypass processing. */ |
---|
1408 | } |
---|
1409 | #endif /* INET */ |
---|
1410 | #endif /* defined(IPSEC) && defined(IPSEC_NAT_T) */ |
---|
1411 | |
---|
1412 | static void |
---|
1413 | udp_abort(struct socket *so) |
---|
1414 | { |
---|
1415 | struct inpcb *inp; |
---|
1416 | |
---|
1417 | inp = sotoinpcb(so); |
---|
1418 | KASSERT(inp != NULL, ("udp_abort: inp == NULL")); |
---|
1419 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1420 | INP_WLOCK(inp); |
---|
1421 | if (inp->inp_faddr.s_addr != INADDR_ANY) { |
---|
1422 | in_pcbdisconnect(inp); |
---|
1423 | inp->inp_laddr.s_addr = INADDR_ANY; |
---|
1424 | soisdisconnected(so); |
---|
1425 | } |
---|
1426 | INP_WUNLOCK(inp); |
---|
1427 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1428 | } |
---|
1429 | |
---|
1430 | static int |
---|
1431 | udp_attach(struct socket *so, int proto, struct thread *td) |
---|
1432 | { |
---|
1433 | struct inpcb *inp; |
---|
1434 | int error; |
---|
1435 | |
---|
1436 | inp = sotoinpcb(so); |
---|
1437 | KASSERT(inp == NULL, ("udp_attach: inp != NULL")); |
---|
1438 | error = soreserve(so, udp_sendspace, udp_recvspace); |
---|
1439 | if (error) |
---|
1440 | return (error); |
---|
1441 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1442 | error = in_pcballoc(so, &V_udbinfo); |
---|
1443 | if (error) { |
---|
1444 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1445 | return (error); |
---|
1446 | } |
---|
1447 | |
---|
1448 | inp = sotoinpcb(so); |
---|
1449 | inp->inp_vflag |= INP_IPV4; |
---|
1450 | inp->inp_ip_ttl = V_ip_defttl; |
---|
1451 | |
---|
1452 | error = udp_newudpcb(inp); |
---|
1453 | if (error) { |
---|
1454 | in_pcbdetach(inp); |
---|
1455 | in_pcbfree(inp); |
---|
1456 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1457 | return (error); |
---|
1458 | } |
---|
1459 | |
---|
1460 | INP_WUNLOCK(inp); |
---|
1461 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1462 | return (0); |
---|
1463 | } |
---|
1464 | |
---|
1465 | int |
---|
1466 | udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f) |
---|
1467 | { |
---|
1468 | struct inpcb *inp; |
---|
1469 | struct udpcb *up; |
---|
1470 | |
---|
1471 | KASSERT(so->so_type == SOCK_DGRAM, |
---|
1472 | ("udp_set_kernel_tunneling: !dgram")); |
---|
1473 | inp = sotoinpcb(so); |
---|
1474 | KASSERT(inp != NULL, ("udp_set_kernel_tunneling: inp == NULL")); |
---|
1475 | INP_WLOCK(inp); |
---|
1476 | up = intoudpcb(inp); |
---|
1477 | if (up->u_tun_func != NULL) { |
---|
1478 | INP_WUNLOCK(inp); |
---|
1479 | return (EBUSY); |
---|
1480 | } |
---|
1481 | up->u_tun_func = f; |
---|
1482 | INP_WUNLOCK(inp); |
---|
1483 | return (0); |
---|
1484 | } |
---|
1485 | |
---|
1486 | static int |
---|
1487 | udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) |
---|
1488 | { |
---|
1489 | struct inpcb *inp; |
---|
1490 | int error; |
---|
1491 | |
---|
1492 | inp = sotoinpcb(so); |
---|
1493 | KASSERT(inp != NULL, ("udp_bind: inp == NULL")); |
---|
1494 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1495 | INP_WLOCK(inp); |
---|
1496 | error = in_pcbbind(inp, nam, td->td_ucred); |
---|
1497 | INP_WUNLOCK(inp); |
---|
1498 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1499 | return (error); |
---|
1500 | } |
---|
1501 | |
---|
1502 | static void |
---|
1503 | udp_close(struct socket *so) |
---|
1504 | { |
---|
1505 | struct inpcb *inp; |
---|
1506 | |
---|
1507 | inp = sotoinpcb(so); |
---|
1508 | KASSERT(inp != NULL, ("udp_close: inp == NULL")); |
---|
1509 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1510 | INP_WLOCK(inp); |
---|
1511 | if (inp->inp_faddr.s_addr != INADDR_ANY) { |
---|
1512 | in_pcbdisconnect(inp); |
---|
1513 | inp->inp_laddr.s_addr = INADDR_ANY; |
---|
1514 | soisdisconnected(so); |
---|
1515 | } |
---|
1516 | INP_WUNLOCK(inp); |
---|
1517 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1518 | } |
---|
1519 | |
---|
1520 | static int |
---|
1521 | udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) |
---|
1522 | { |
---|
1523 | struct inpcb *inp; |
---|
1524 | int error; |
---|
1525 | struct sockaddr_in *sin; |
---|
1526 | |
---|
1527 | inp = sotoinpcb(so); |
---|
1528 | KASSERT(inp != NULL, ("udp_connect: inp == NULL")); |
---|
1529 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1530 | INP_WLOCK(inp); |
---|
1531 | if (inp->inp_faddr.s_addr != INADDR_ANY) { |
---|
1532 | INP_WUNLOCK(inp); |
---|
1533 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1534 | return (EISCONN); |
---|
1535 | } |
---|
1536 | sin = (struct sockaddr_in *)nam; |
---|
1537 | error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); |
---|
1538 | if (error != 0) { |
---|
1539 | INP_WUNLOCK(inp); |
---|
1540 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1541 | return (error); |
---|
1542 | } |
---|
1543 | error = in_pcbconnect(inp, nam, td->td_ucred); |
---|
1544 | if (error == 0) |
---|
1545 | soisconnected(so); |
---|
1546 | INP_WUNLOCK(inp); |
---|
1547 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1548 | return (error); |
---|
1549 | } |
---|
1550 | |
---|
1551 | static void |
---|
1552 | udp_detach(struct socket *so) |
---|
1553 | { |
---|
1554 | struct inpcb *inp; |
---|
1555 | struct udpcb *up; |
---|
1556 | |
---|
1557 | inp = sotoinpcb(so); |
---|
1558 | KASSERT(inp != NULL, ("udp_detach: inp == NULL")); |
---|
1559 | KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, |
---|
1560 | ("udp_detach: not disconnected")); |
---|
1561 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1562 | INP_WLOCK(inp); |
---|
1563 | up = intoudpcb(inp); |
---|
1564 | KASSERT(up != NULL, ("%s: up == NULL", __func__)); |
---|
1565 | inp->inp_ppcb = NULL; |
---|
1566 | in_pcbdetach(inp); |
---|
1567 | in_pcbfree(inp); |
---|
1568 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1569 | udp_discardcb(up); |
---|
1570 | } |
---|
1571 | |
---|
1572 | static int |
---|
1573 | udp_disconnect(struct socket *so) |
---|
1574 | { |
---|
1575 | struct inpcb *inp; |
---|
1576 | |
---|
1577 | inp = sotoinpcb(so); |
---|
1578 | KASSERT(inp != NULL, ("udp_disconnect: inp == NULL")); |
---|
1579 | INP_INFO_WLOCK(&V_udbinfo); |
---|
1580 | INP_WLOCK(inp); |
---|
1581 | if (inp->inp_faddr.s_addr == INADDR_ANY) { |
---|
1582 | INP_WUNLOCK(inp); |
---|
1583 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1584 | return (ENOTCONN); |
---|
1585 | } |
---|
1586 | |
---|
1587 | in_pcbdisconnect(inp); |
---|
1588 | inp->inp_laddr.s_addr = INADDR_ANY; |
---|
1589 | SOCK_LOCK(so); |
---|
1590 | so->so_state &= ~SS_ISCONNECTED; /* XXX */ |
---|
1591 | SOCK_UNLOCK(so); |
---|
1592 | INP_WUNLOCK(inp); |
---|
1593 | INP_INFO_WUNLOCK(&V_udbinfo); |
---|
1594 | return (0); |
---|
1595 | } |
---|
1596 | |
---|
1597 | static int |
---|
1598 | udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, |
---|
1599 | struct mbuf *control, struct thread *td) |
---|
1600 | { |
---|
1601 | struct inpcb *inp; |
---|
1602 | |
---|
1603 | inp = sotoinpcb(so); |
---|
1604 | KASSERT(inp != NULL, ("udp_send: inp == NULL")); |
---|
1605 | return (udp_output(inp, m, addr, control, td)); |
---|
1606 | } |
---|
1607 | |
---|
1608 | int |
---|
1609 | udp_shutdown(struct socket *so) |
---|
1610 | { |
---|
1611 | struct inpcb *inp; |
---|
1612 | |
---|
1613 | inp = sotoinpcb(so); |
---|
1614 | KASSERT(inp != NULL, ("udp_shutdown: inp == NULL")); |
---|
1615 | INP_WLOCK(inp); |
---|
1616 | socantsendmore(so); |
---|
1617 | INP_WUNLOCK(inp); |
---|
1618 | return (0); |
---|
1619 | } |
---|
1620 | |
---|
1621 | struct pr_usrreqs udp_usrreqs = { |
---|
1622 | .pru_abort = udp_abort, |
---|
1623 | .pru_attach = udp_attach, |
---|
1624 | .pru_bind = udp_bind, |
---|
1625 | .pru_connect = udp_connect, |
---|
1626 | .pru_control = in_control, |
---|
1627 | .pru_detach = udp_detach, |
---|
1628 | .pru_disconnect = udp_disconnect, |
---|
1629 | .pru_peeraddr = in_getpeeraddr, |
---|
1630 | .pru_send = udp_send, |
---|
1631 | .pru_soreceive = soreceive_dgram, |
---|
1632 | .pru_sosend = sosend_dgram, |
---|
1633 | .pru_shutdown = udp_shutdown, |
---|
1634 | .pru_sockaddr = in_getsockaddr, |
---|
1635 | .pru_sosetlabel = in_pcbsosetlabel, |
---|
1636 | .pru_close = udp_close, |
---|
1637 | }; |
---|