]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/udp_usrreq.c
xnu-123.5.tar.gz
[apple/xnu.git] / bsd / netinet / udp_usrreq.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
55 */
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/kernel.h>
60 #include <sys/malloc.h>
61 #include <sys/mbuf.h>
62 #if INET6
63 #include <sys/domain.h>
64 #endif
65 #include <sys/protosw.h>
66 #include <sys/socket.h>
67 #include <sys/socketvar.h>
68 #include <sys/sysctl.h>
69 #include <sys/syslog.h>
70
71 #if ISFB31
72 #include <vm/vm_zone.h>
73 #endif
74
75
76 #include <net/if.h>
77 #include <net/route.h>
78
79 #include <netinet/in.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/ip.h>
82 #include <netinet/in_pcb.h>
83 #include <netinet/in_var.h>
84 #include <netinet/ip_var.h>
85 #include <netinet/ip_icmp.h>
86 #include <netinet/icmp_var.h>
87 #if INET6
88 #include <netinet/ip6.h>
89 #include <netinet6/ip6_var.h>
90 #endif
91 #include <netinet/udp.h>
92 #include <netinet/udp_var.h>
93 #include <sys/kdebug.h>
94
95 #if IPSEC
96 #include <netinet6/ipsec.h>
97 #endif /*IPSEC*/
98
99
100 #define DBG_LAYER_IN_BEG NETDBG_CODE(DBG_NETUDP, 0)
101 #define DBG_LAYER_IN_END NETDBG_CODE(DBG_NETUDP, 2)
102 #define DBG_LAYER_OUT_BEG NETDBG_CODE(DBG_NETUDP, 1)
103 #define DBG_LAYER_OUT_END NETDBG_CODE(DBG_NETUDP, 3)
104 #define DBG_FNC_UDP_INPUT NETDBG_CODE(DBG_NETUDP, (5 << 8))
105 #define DBG_FNC_UDP_OUTPUT NETDBG_CODE(DBG_NETUDP, (6 << 8) | 1)
106
107 #define __STDC__ 1
108 /*
109 * UDP protocol implementation.
110 * Per RFC 768, August, 1980.
111 */
112 #ifndef COMPAT_42
113 static int udpcksum = 1;
114 #else
115 static int udpcksum = 0; /* XXX */
116 #endif
117 SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
118 &udpcksum, 0, "");
119
120 int log_in_vain;
121 SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
122 &log_in_vain, 0, "");
123
124 struct inpcbhead udb; /* from udp_var.h */
125 #define udb6 udb /* for KAME src sync over BSD*'s */
126 struct inpcbinfo udbinfo;
127
128 #ifndef UDBHASHSIZE
129 #define UDBHASHSIZE 16
130 #endif
131
132 struct udpstat udpstat; /* from udp_var.h */
133 SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
134 &udpstat, udpstat, "");
135
136 static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
137 #if INET6
138 struct udp_in6 {
139 struct sockaddr_in6 uin6_sin;
140 u_char uin6_init_done : 1;
141 } udp_in6 = {
142 { sizeof(udp_in6.uin6_sin), AF_INET6 },
143 0
144 };
145 struct udp_ip6 {
146 struct ip6_hdr uip6_ip6;
147 u_char uip6_init_done : 1;
148 } udp_ip6;
149 #endif /* INET6 */
150
151 static void udp_append __P((struct inpcb *last, struct ip *ip,
152 struct mbuf *n, int off));
153 #if INET6
154 static void ip_2_ip6_hdr __P((struct ip6_hdr *ip6, struct ip *ip));
155 #endif
156
157 static int udp_detach __P((struct socket *so));
158 static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
159 struct mbuf *, struct proc *));
160
161 void
162 udp_init()
163 {
164 vm_size_t str_size;
165 int stat;
166 u_char fake_owner;
167 struct in_addr laddr;
168 struct in_addr faddr;
169 u_short lport;
170
171 LIST_INIT(&udb);
172 udbinfo.listhead = &udb;
173 udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
174 udbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB,
175 &udbinfo.porthashmask);
176 #if ISFB31
177 udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets,
178 ZONE_INTERRUPT, 0);
179 #else
180 str_size = (vm_size_t) sizeof(struct inpcb);
181 udbinfo.ipi_zone = (void *) zinit(str_size, 80000*str_size, 8192, "inpcb_zone");
182 #endif
183
184 udbinfo.last_pcb = 0;
185 in_pcb_nat_init(&udbinfo, AF_INET, IPPROTO_UDP, SOCK_DGRAM);
186
187 #if 0
188 stat = in_pcb_new_share_client(&udbinfo, &fake_owner);
189 kprintf("udp_init in_pcb_new_share_client - stat = %d\n", stat);
190
191 laddr.s_addr = 0x11646464;
192 faddr.s_addr = 0x11646465;
193
194 lport = 1500;
195 in_pcb_grab_port(&udbinfo, 0, laddr, &lport, faddr, 1600, 0, fake_owner);
196 kprintf("udp_init in_pcb_grab_port - stat = %d\n", stat);
197
198 stat = in_pcb_rem_share_client(&udbinfo, fake_owner);
199 kprintf("udp_init in_pcb_rem_share_client - stat = %d\n", stat);
200
201 stat = in_pcb_new_share_client(&udbinfo, &fake_owner);
202 kprintf("udp_init in_pcb_new_share_client(2) - stat = %d\n", stat);
203
204 laddr.s_addr = 0x11646464;
205 faddr.s_addr = 0x11646465;
206
207 lport = 1500;
208 stat = in_pcb_grab_port(&udbinfo, 0, laddr, &lport, faddr, 1600, 0, fake_owner);
209 kprintf("udp_init in_pcb_grab_port(2) - stat = %d\n", stat);
210 #endif
211 }
212
213 void
214 udp_input(m, iphlen)
215 register struct mbuf *m;
216 int iphlen;
217 {
218 register struct ip *ip;
219 register struct udphdr *uh;
220 register struct inpcb *inp;
221 struct mbuf *opts = 0;
222 #if INET6
223 struct ip6_recvpktopts opts6;
224 #endif
225 int len;
226 struct ip save_ip;
227 struct sockaddr *append_sa;
228
229 udpstat.udps_ipackets++;
230 #if INET6
231 bzero(&opts6, sizeof(opts6));
232 #endif
233
234
235 KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_START, 0,0,0,0,0);
236
237 /*
238 * Strip IP options, if any; should skip this,
239 * make available to user, and use on returned packets,
240 * but we don't yet have a way to check the checksum
241 * with options still present.
242 */
243 if (iphlen > sizeof (struct ip)) {
244 ip_stripoptions(m, (struct mbuf *)0);
245 iphlen = sizeof(struct ip);
246 }
247
248 /*
249 * Get IP and UDP header together in first mbuf.
250 */
251 ip = mtod(m, struct ip *);
252 if (m->m_len < iphlen + sizeof(struct udphdr)) {
253 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
254 udpstat.udps_hdrops++;
255 KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
256 return;
257 }
258 ip = mtod(m, struct ip *);
259 }
260 uh = (struct udphdr *)((caddr_t)ip + iphlen);
261
262 KERNEL_DEBUG(DBG_LAYER_IN_BEG, uh->uh_dport, uh->uh_sport,
263 ip->ip_src.s_addr, ip->ip_dst.s_addr, uh->uh_ulen);
264
265 /*
266 * Make mbuf data length reflect UDP length.
267 * If not enough data to reflect UDP length, drop.
268 */
269 len = ntohs((u_short)uh->uh_ulen);
270 if (ip->ip_len != len) {
271 if (len > ip->ip_len || len < sizeof(struct udphdr)) {
272 udpstat.udps_badlen++;
273 goto bad;
274 }
275 m_adj(m, len - ip->ip_len);
276 /* ip->ip_len = len; */
277 }
278 /*
279 * Save a copy of the IP header in case we want restore it
280 * for sending an ICMP error message in response.
281 */
282 save_ip = *ip;
283
284 /*
285 * Checksum extended UDP header and data.
286 */
287 if (uh->uh_sum) {
288 bzero(((struct ipovly *)ip)->ih_x1, 9);
289 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
290 uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
291 if (uh->uh_sum) {
292 udpstat.udps_badsum++;
293 m_freem(m);
294 KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
295 return;
296 }
297 }
298
299 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
300 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
301 struct inpcb *last;
302 /*
303 * Deliver a multicast or broadcast datagram to *all* sockets
304 * for which the local and remote addresses and ports match
305 * those of the incoming datagram. This allows more than
306 * one process to receive multi/broadcasts on the same port.
307 * (This really ought to be done for unicast datagrams as
308 * well, but that would cause problems with existing
309 * applications that open both address-specific sockets and
310 * a wildcard socket listening to the same port -- they would
311 * end up receiving duplicates of every unicast datagram.
312 * Those applications open the multiple sockets to overcome an
313 * inadequacy of the UDP socket interface, but for backwards
314 * compatibility we avoid the problem here rather than
315 * fixing the interface. Maybe 4.5BSD will remedy this?)
316 */
317
318 /*
319 * Construct sockaddr format source address.
320 */
321 udp_in.sin_port = uh->uh_sport;
322 udp_in.sin_addr = ip->ip_src;
323 /*
324 * Locate pcb(s) for datagram.
325 * (Algorithm copied from raw_intr().)
326 */
327 last = NULL;
328 #if INET6
329 udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0;
330 #endif
331 LIST_FOREACH(inp, &udb, inp_list) {
332 #if INET6
333 if ((inp->inp_vflag & INP_IPV4) == 0)
334 continue;
335 #endif
336 if (inp->inp_lport != uh->uh_dport)
337 continue;
338 if (inp->inp_laddr.s_addr != INADDR_ANY) {
339 if (inp->inp_laddr.s_addr !=
340 ip->ip_dst.s_addr)
341 continue;
342 }
343 if (inp->inp_faddr.s_addr != INADDR_ANY) {
344 if (inp->inp_faddr.s_addr !=
345 ip->ip_src.s_addr ||
346 inp->inp_fport != uh->uh_sport)
347 continue;
348 }
349
350 if (last != NULL) {
351 struct mbuf *n;
352
353 #if IPSEC
354 /* check AH/ESP integrity. */
355 if (ipsec4_in_reject_so(m, last->inp_socket)) {
356 ipsecstat.in_polvio++;
357 /* do not inject data to pcb */
358 } else
359 #endif /*IPSEC*/
360 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
361 udp_append(last, ip, n, iphlen +
362 sizeof (struct udphdr));
363 }
364 }
365 last = inp;
366 /*
367 * Don't look for additional matches if this one does
368 * not have either the SO_REUSEPORT or SO_REUSEADDR
369 * socket options set. This heuristic avoids searching
370 * through all pcbs in the common case of a non-shared
371 * port. It * assumes that an application will never
372 * clear these options after setting them.
373 */
374 if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
375 break;
376 }
377
378 if (last == NULL) {
379 /*
380 * No matching pcb found; discard datagram.
381 * (No need to send an ICMP Port Unreachable
382 * for a broadcast or multicast datgram.)
383 */
384 udpstat.udps_noportbcast++;
385 goto bad;
386 }
387 #if IPSEC
388 else
389 /* check AH/ESP integrity. */
390 if (m && ipsec4_in_reject_so(m, last->inp_socket)) {
391 ipsecstat.in_polvio++;
392 goto bad;
393 }
394 #endif /*IPSEC*/
395 udp_append(last, ip, m, iphlen + sizeof (struct udphdr));
396 return;
397 }
398 /*
399 * Locate pcb for datagram.
400 */
401 inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport,
402 ip->ip_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
403 if (inp == NULL) {
404 if (log_in_vain) {
405 char buf[4*sizeof "123"];
406
407 strcpy(buf, inet_ntoa(ip->ip_dst));
408 log(LOG_INFO,
409 "Connection attempt to UDP %s:%d from %s:%d\n",
410 buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src),
411 ntohs(uh->uh_sport));
412 }
413 udpstat.udps_noport++;
414 if (m->m_flags & (M_BCAST | M_MCAST)) {
415 udpstat.udps_noportbcast++;
416 goto bad;
417 }
418 *ip = save_ip;
419 #if ICMP_BANDLIM
420 if (badport_bandlim(0) < 0)
421 goto bad;
422 #endif
423 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
424 KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
425 return;
426 }
427 #if IPSEC
428 if (inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) {
429 ipsecstat.in_polvio++;
430 goto bad;
431 }
432 #endif /*IPSEC*/
433
434 /*
435 * Construct sockaddr format source address.
436 * Stuff source address and datagram in user buffer.
437 */
438 udp_in.sin_port = uh->uh_sport;
439 udp_in.sin_addr = ip->ip_src;
440 if (inp->inp_flags & INP_CONTROLOPTS
441 || inp->inp_socket->so_options & SO_TIMESTAMP) {
442 #if INET6
443 if (inp->inp_vflag & INP_IPV6) {
444 int savedflags;
445
446 ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
447 savedflags = inp->inp_flags;
448 inp->inp_flags &= ~INP_UNMAPPABLEOPTS;
449 ip6_savecontrol(inp, &udp_ip6.uip6_ip6, m,
450 &opts6, NULL);
451
452 inp->inp_flags = savedflags;
453 } else
454 #endif
455 ip_savecontrol(inp, &opts, ip, m);
456 }
457 m_adj(m, iphlen + sizeof(struct udphdr));
458
459 KERNEL_DEBUG(DBG_LAYER_IN_END, uh->uh_dport, uh->uh_sport,
460 save_ip.ip_src.s_addr, save_ip.ip_dst.s_addr, uh->uh_ulen);
461
462 #if INET6
463 if (inp->inp_vflag & INP_IPV6) {
464 in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
465 append_sa = (struct sockaddr *)&udp_in6;
466 opts = opts6.head;
467 } else
468 #endif
469 append_sa = (struct sockaddr *)&udp_in;
470 if (sbappendaddr(&inp->inp_socket->so_rcv, append_sa, m, opts) == 0) {
471 udpstat.udps_fullsock++;
472 goto bad;
473 }
474 sorwakeup(inp->inp_socket);
475 KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
476 return;
477 bad:
478 m_freem(m);
479 if (opts)
480 m_freem(opts);
481 KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
482 }
483
484 #if INET6
485 static void
486 ip_2_ip6_hdr(ip6, ip)
487 struct ip6_hdr *ip6;
488 struct ip *ip;
489 {
490 bzero(ip6, sizeof(*ip6));
491
492 ip6->ip6_vfc = IPV6_VERSION;
493 ip6->ip6_plen = ip->ip_len;
494 ip6->ip6_nxt = ip->ip_p;
495 ip6->ip6_hlim = ip->ip_ttl;
496 ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] =
497 IPV6_ADDR_INT32_SMP;
498 ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr;
499 ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr;
500 }
501 #endif
502
503 /*
504 * subroutine of udp_input(), mainly for source code readability.
505 * caller must properly init udp_ip6 and udp_in6 beforehand.
506 */
507 static void
508 udp_append(last, ip, n, off)
509 struct inpcb *last;
510 struct ip *ip;
511 struct mbuf *n;
512 {
513 struct sockaddr *append_sa;
514 struct mbuf *opts = 0;
515 #if INET6
516 struct ip6_recvpktopts opts6;
517 bzero(&opts6, sizeof(opts6));
518 #endif
519
520
521 if (last->inp_flags & INP_CONTROLOPTS ||
522 last->inp_socket->so_options & SO_TIMESTAMP) {
523 #if INET6
524 if (last->inp_vflag & INP_IPV6) {
525 int savedflags;
526
527 if (udp_ip6.uip6_init_done == 0) {
528 ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
529 udp_ip6.uip6_init_done = 1;
530 }
531 savedflags = last->inp_flags;
532 last->inp_flags &= ~INP_UNMAPPABLEOPTS;
533 ip6_savecontrol(last, &udp_ip6.uip6_ip6, n,
534 &opts6, NULL);
535 last->inp_flags = savedflags;
536 } else
537 #endif
538 ip_savecontrol(last, &opts, ip, n);
539 }
540 #if INET6
541 if (last->inp_vflag & INP_IPV6) {
542 if (udp_in6.uin6_init_done == 0) {
543 in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
544 udp_in6.uin6_init_done = 1;
545 }
546 append_sa = (struct sockaddr *)&udp_in6.uin6_sin;
547 opts = opts6.head;
548 } else
549 #endif
550 append_sa = (struct sockaddr *)&udp_in;
551 m_adj(n, off);
552
553 if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) {
554 m_freem(n);
555 if (opts)
556 m_freem(opts);
557 udpstat.udps_fullsock++;
558 } else
559 sorwakeup(last->inp_socket);
560 }
561
562
563
564 /*
565 * Notify a udp user of an asynchronous error;
566 * just wake up so that he can collect error status.
567 */
568 void
569 udp_notify(inp, errno)
570 register struct inpcb *inp;
571 int errno;
572 {
573 inp->inp_socket->so_error = errno;
574 sorwakeup(inp->inp_socket);
575 sowwakeup(inp->inp_socket);
576 }
577
578 void
579 udp_ctlinput(cmd, sa, vip)
580 int cmd;
581 struct sockaddr *sa;
582 void *vip;
583 {
584 register struct ip *ip = vip;
585 register struct udphdr *uh;
586
587 if (!PRC_IS_REDIRECT(cmd) &&
588 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
589 return;
590 if (ip) {
591 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
592 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
593 cmd, udp_notify);
594 } else
595 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
596 }
597
598
599 static int
600 udp_pcblist SYSCTL_HANDLER_ARGS
601 {
602 int error, i, n, s;
603 struct inpcb *inp, **inp_list;
604 inp_gen_t gencnt;
605 struct xinpgen xig;
606
607 /*
608 * The process of preparing the TCB list is too time-consuming and
609 * resource-intensive to repeat twice on every request.
610 */
611 if (req->oldptr == 0) {
612 n = udbinfo.ipi_count;
613 req->oldidx = 2 * (sizeof xig)
614 + (n + n/8) * sizeof(struct xinpcb);
615 return 0;
616 }
617
618 if (req->newptr != 0)
619 return EPERM;
620
621 /*
622 * OK, now we're committed to doing something.
623 */
624 s = splnet();
625 gencnt = udbinfo.ipi_gencnt;
626 n = udbinfo.ipi_count;
627 splx(s);
628
629 xig.xig_len = sizeof xig;
630 xig.xig_count = n;
631 xig.xig_gen = gencnt;
632 xig.xig_sogen = so_gencnt;
633 error = SYSCTL_OUT(req, &xig, sizeof xig);
634 if (error)
635 return error;
636
637 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
638 if (inp_list == 0) {
639 return ENOMEM;
640 }
641 s = splnet();
642 for (inp = udbinfo.listhead->lh_first, i = 0; inp && i < n;
643 inp = inp->inp_list.le_next) {
644 if (inp->inp_gencnt <= gencnt)
645 inp_list[i++] = inp;
646 }
647 splx(s);
648 n = i;
649
650 error = 0;
651 for (i = 0; i < n; i++) {
652 inp = inp_list[i];
653 if (inp->inp_gencnt <= gencnt) {
654 struct xinpcb xi;
655 xi.xi_len = sizeof xi;
656 /* XXX should avoid extra copy */
657 bcopy(inp, &xi.xi_inp, sizeof *inp);
658 if (inp->inp_socket)
659 sotoxsocket(inp->inp_socket, &xi.xi_socket);
660 error = SYSCTL_OUT(req, &xi, sizeof xi);
661 }
662 }
663 if (!error) {
664 /*
665 * Give the user an updated idea of our state.
666 * If the generation differs from what we told
667 * her before, she knows that something happened
668 * while we were processing this request, and it
669 * might be necessary to retry.
670 */
671 s = splnet();
672 xig.xig_gen = udbinfo.ipi_gencnt;
673 xig.xig_sogen = so_gencnt;
674 xig.xig_count = udbinfo.ipi_count;
675 splx(s);
676 error = SYSCTL_OUT(req, &xig, sizeof xig);
677 }
678 FREE(inp_list, M_TEMP);
679 return error;
680 }
681
682 SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
683 udp_pcblist, "S,xinpcb", "List of active UDP sockets");
684
685
686
687 static int
688 udp_output(inp, m, addr, control, p)
689 register struct inpcb *inp;
690 register struct mbuf *m;
691 struct sockaddr *addr;
692 struct mbuf *control;
693 struct proc *p;
694 {
695 register struct udpiphdr *ui;
696 register int len = m->m_pkthdr.len;
697 struct in_addr laddr;
698 int s = 0, error = 0;
699
700 KERNEL_DEBUG(DBG_FNC_UDP_OUTPUT | DBG_FUNC_START, 0,0,0,0,0);
701
702 if (control)
703 m_freem(control); /* XXX */
704
705 KERNEL_DEBUG(DBG_LAYER_OUT_BEG, inp->inp_fport, inp->inp_lport,
706 inp->inp_laddr.s_addr, inp->inp_faddr.s_addr,
707 (htons((u_short)len + sizeof (struct udphdr))));
708
709 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
710 error = EMSGSIZE;
711 goto release;
712 }
713
714 if (addr) {
715 laddr = inp->inp_laddr;
716 if (inp->inp_faddr.s_addr != INADDR_ANY) {
717 error = EISCONN;
718 goto release;
719 }
720 /*
721 * Must block input while temporarily connected.
722 */
723 s = splnet();
724 error = in_pcbconnect(inp, addr, p);
725 if (error) {
726 splx(s);
727 goto release;
728 }
729 } else {
730 if (inp->inp_faddr.s_addr == INADDR_ANY) {
731 error = ENOTCONN;
732 goto release;
733 }
734 }
735 /*
736 * Calculate data length and get a mbuf
737 * for UDP and IP headers.
738 */
739 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
740 if (m == 0) {
741 error = ENOBUFS;
742 if (addr)
743 splx(s);
744 goto release;
745 }
746
747 /*
748 * Fill in mbuf with extended UDP header
749 * and addresses and length put into network format.
750 */
751 ui = mtod(m, struct udpiphdr *);
752 bzero(ui->ui_x1, sizeof(ui->ui_x1));
753 ui->ui_pr = IPPROTO_UDP;
754 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
755 ui->ui_src = inp->inp_laddr;
756 ui->ui_dst = inp->inp_faddr;
757 ui->ui_sport = inp->inp_lport;
758 ui->ui_dport = inp->inp_fport;
759 ui->ui_ulen = ui->ui_len;
760
761 /*
762 * Stuff checksum and output datagram.
763 */
764 ui->ui_sum = 0;
765 if (udpcksum) {
766 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
767 ui->ui_sum = 0xffff;
768 }
769 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
770 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
771 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
772 udpstat.udps_opackets++;
773
774 KERNEL_DEBUG(DBG_LAYER_OUT_END, ui->ui_dport, ui->ui_sport,
775 ui->ui_src.s_addr, ui->ui_dst.s_addr, ui->ui_ulen);
776
777
778 #if IPSEC
779 ipsec_setsocket(m, inp->inp_socket);
780 #endif /*IPSEC*/
781
782 error = ip_output(m, inp->inp_options, &inp->inp_route,
783 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
784 inp->inp_moptions);
785
786 if (addr) {
787 in_pcbdisconnect(inp);
788 inp->inp_laddr = laddr; /* XXX rehash? */
789 splx(s);
790 }
791 KERNEL_DEBUG(DBG_FNC_UDP_OUTPUT | DBG_FUNC_END, error, 0,0,0,0);
792 return (error);
793
794 release:
795 m_freem(m);
796 KERNEL_DEBUG(DBG_FNC_UDP_OUTPUT | DBG_FUNC_END, error, 0,0,0,0);
797 return (error);
798 }
799
800 u_long udp_sendspace = 9216; /* really max datagram size */
801 /* 40 1K datagrams */
802 SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
803 &udp_sendspace, 0, "");
804
805
806 u_long udp_recvspace = 40 * (1024 + /* 40 1K datagrams */
807 #if INET6
808 sizeof(struct sockaddr_in6)
809 #else /* INET6 */
810 sizeof(struct sockaddr_in)
811 #endif /* INET6 */
812 );
813 SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
814 &udp_recvspace, 0, "");
815
816 static int
817 udp_abort(struct socket *so)
818 {
819 struct inpcb *inp;
820 int s;
821
822 inp = sotoinpcb(so);
823 if (inp == 0)
824 return EINVAL; /* ??? possible? panic instead? */
825 soisdisconnected(so);
826 s = splnet();
827 in_pcbdetach(inp);
828 splx(s);
829 return 0;
830 }
831
832 static int
833 udp_attach(struct socket *so, int proto, struct proc *p)
834 {
835 struct inpcb *inp;
836 int error; long s;
837
838 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
839 error = soreserve(so, udp_sendspace, udp_recvspace);
840 if (error)
841 return error;
842 }
843 s = splnet();
844 error = in_pcballoc(so, &udbinfo, p);
845 splx(s);
846 if (error)
847 return error;
848 error = soreserve(so, udp_sendspace, udp_recvspace);
849 if (error)
850 return error;
851 inp = (struct inpcb *)so->so_pcb;
852 inp->inp_vflag |= INP_IPV4;
853 inp->inp_ip_ttl = ip_defttl;
854 #if IPSEC
855 error = ipsec_init_policy(so, &inp->inp_sp);
856 if (error != 0) {
857 in_pcbdetach(inp);
858 return error;
859 }
860 #endif /*IPSEC*/
861 return 0;
862 }
863
864 static int
865 udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
866 {
867 struct inpcb *inp;
868 int s, error;
869
870 inp = sotoinpcb(so);
871 if (inp == 0)
872 return EINVAL;
873 s = splnet();
874 error = in_pcbbind(inp, nam, p);
875 splx(s);
876 return error;
877 }
878
879 static int
880 udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
881 {
882 struct inpcb *inp;
883 int s, error;
884
885 inp = sotoinpcb(so);
886 if (inp == 0)
887 return EINVAL;
888 if (inp->inp_faddr.s_addr != INADDR_ANY)
889 return EISCONN;
890 s = splnet();
891 error = in_pcbconnect(inp, nam, p);
892 splx(s);
893 if (error == 0)
894 soisconnected(so);
895 return error;
896 }
897
898 static int
899 udp_detach(struct socket *so)
900 {
901 struct inpcb *inp;
902 int s;
903
904 inp = sotoinpcb(so);
905 if (inp == 0)
906 return EINVAL;
907 s = splnet();
908 in_pcbdetach(inp);
909 splx(s);
910 return 0;
911 }
912
913 static int
914 udp_disconnect(struct socket *so)
915 {
916 struct inpcb *inp;
917 int s;
918
919 inp = sotoinpcb(so);
920 if (inp == 0)
921 return EINVAL;
922 if (inp->inp_faddr.s_addr == INADDR_ANY)
923 return ENOTCONN;
924
925 s = splnet();
926 in_pcbdisconnect(inp);
927 inp->inp_laddr.s_addr = INADDR_ANY;
928 splx(s);
929 so->so_state &= ~SS_ISCONNECTED; /* XXX */
930 return 0;
931 }
932
933 static int
934 udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
935 struct mbuf *control, struct proc *p)
936 {
937 struct inpcb *inp;
938
939 inp = sotoinpcb(so);
940 if (inp == 0) {
941 m_freem(m);
942 return EINVAL;
943 }
944 return udp_output(inp, m, addr, control, p);
945 }
946
947 int
948 udp_shutdown(struct socket *so)
949 {
950 struct inpcb *inp;
951
952 inp = sotoinpcb(so);
953 if (inp == 0)
954 return EINVAL;
955 socantsendmore(so);
956 return 0;
957 }
958
959 struct pr_usrreqs udp_usrreqs = {
960 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
961 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
962 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
963 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
964 in_setsockaddr, sosend, soreceive, sopoll
965 };
966