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