udp_usrreq.c revision 1.48 1 /* $NetBSD: udp_usrreq.c,v 1.48 1999/07/01 08:12:52 itojun Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
65 */
66 #include "ipkdb.h"
67
68 /* XXX MAPPED_ADDR_ENABLED should be revisited */
69
70 #include <sys/param.h>
71 #include <sys/malloc.h>
72 #include <sys/mbuf.h>
73 #ifdef MAPPED_ADDR_ENABLED
74 #include <sys/domain.h>
75 #endif /* MAPPED_ADDR_ENABLED */
76 #include <sys/protosw.h>
77 #include <sys/socket.h>
78 #include <sys/socketvar.h>
79 #include <sys/errno.h>
80 #include <sys/stat.h>
81 #include <sys/systm.h>
82 #include <sys/proc.h>
83
84 #include <vm/vm.h>
85 #include <sys/sysctl.h>
86
87 #include <net/if.h>
88 #include <net/route.h>
89
90 #include <netinet/in.h>
91 #include <netinet/in_systm.h>
92 #include <netinet/in_var.h>
93 #include <netinet/ip.h>
94 #include <netinet/in_pcb.h>
95 #include <netinet/ip_var.h>
96 #include <netinet/ip_icmp.h>
97 #include <netinet/udp.h>
98 #include <netinet/udp_var.h>
99
100 #include <machine/stdarg.h>
101
102 #ifdef IPSEC
103 #include <netinet6/ipsec.h>
104 #include <netkey/key.h>
105 #include <netkey/key_debug.h>
106 #endif /*IPSEC*/
107
108 /*
109 * UDP protocol implementation.
110 * Per RFC 768, August, 1980.
111 */
112 #ifndef COMPAT_42
113 int udpcksum = 1;
114 #else
115 int udpcksum = 0; /* XXX */
116 #endif
117
118 static void udp_notify __P((struct inpcb *, int));
119
120 #ifndef UDBHASHSIZE
121 #define UDBHASHSIZE 128
122 #endif
123 int udbhashsize = UDBHASHSIZE;
124
125 void
126 udp_init()
127 {
128
129 in_pcbinit(&udbtable, udbhashsize, udbhashsize);
130 }
131
132 void
133 #if __STDC__
134 udp_input(struct mbuf *m, ...)
135 #else
136 udp_input(m, va_alist)
137 struct mbuf *m;
138 va_dcl
139 #endif
140 {
141 int proto;
142 register struct ip *ip;
143 register struct udphdr *uh;
144 register struct inpcb *inp;
145 struct mbuf *opts = 0;
146 int len;
147 struct ip save_ip;
148 int iphlen;
149 va_list ap;
150 struct sockaddr_in udpsrc;
151 #ifdef MAPPED_ADDR_ENABLED
152 struct sockaddr_in6 mapped;
153 #endif
154 struct sockaddr *sa;
155
156 va_start(ap, m);
157 iphlen = va_arg(ap, int);
158 proto = va_arg(ap, int);
159 va_end(ap);
160
161 udpstat.udps_ipackets++;
162
163 /*
164 * Strip IP options, if any; should skip this,
165 * make available to user, and use on returned packets,
166 * but we don't yet have a way to check the checksum
167 * with options still present.
168 */
169 if (iphlen > sizeof (struct ip)) {
170 ip_stripoptions(m, (struct mbuf *)0);
171 iphlen = sizeof(struct ip);
172 }
173
174 /*
175 * Get IP and UDP header together in first mbuf.
176 */
177 ip = mtod(m, struct ip *);
178 if (m->m_len < iphlen + sizeof(struct udphdr)) {
179 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
180 udpstat.udps_hdrops++;
181 return;
182 }
183 ip = mtod(m, struct ip *);
184 }
185 uh = (struct udphdr *)((caddr_t)ip + iphlen);
186
187 /*
188 * Make mbuf data length reflect UDP length.
189 * If not enough data to reflect UDP length, drop.
190 */
191 len = ntohs((u_int16_t)uh->uh_ulen);
192 if (ip->ip_len != iphlen + len) {
193 if (ip->ip_len < iphlen + len) {
194 udpstat.udps_badlen++;
195 goto bad;
196 }
197 m_adj(m, iphlen + len - ip->ip_len);
198 }
199 /*
200 * Save a copy of the IP header in case we want restore it
201 * for sending an ICMP error message in response.
202 */
203 save_ip = *ip;
204
205 /*
206 * Checksum extended UDP header and data.
207 */
208 if (uh->uh_sum) {
209 bzero(((struct ipovly *)ip)->ih_x1,
210 sizeof ((struct ipovly *)ip)->ih_x1);
211 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
212 if (in_cksum(m, len + sizeof (struct ip)) != 0) {
213 udpstat.udps_badsum++;
214 m_freem(m);
215 return;
216 }
217 }
218
219 /*
220 * Construct sockaddr format source address.
221 */
222 udpsrc.sin_family = AF_INET;
223 udpsrc.sin_len = sizeof(struct sockaddr_in);
224 udpsrc.sin_addr = ip->ip_src;
225 udpsrc.sin_port = uh->uh_sport;
226 bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero));
227
228 if (IN_MULTICAST(ip->ip_dst.s_addr) ||
229 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
230 struct inpcb *last;
231 /*
232 * Deliver a multicast or broadcast datagram to *all* sockets
233 * for which the local and remote addresses and ports match
234 * those of the incoming datagram. This allows more than
235 * one process to receive multi/broadcasts on the same port.
236 * (This really ought to be done for unicast datagrams as
237 * well, but that would cause problems with existing
238 * applications that open both address-specific sockets and
239 * a wildcard socket listening to the same port -- they would
240 * end up receiving duplicates of every unicast datagram.
241 * Those applications open the multiple sockets to overcome an
242 * inadequacy of the UDP socket interface, but for backwards
243 * compatibility we avoid the problem here rather than
244 * fixing the interface. Maybe 4.5BSD will remedy this?)
245 */
246
247 iphlen += sizeof(struct udphdr);
248 /*
249 * KAME note: usually we drop udpiphdr from mbuf here.
250 * we need udpiphdr for iPsec processing so we do that later.
251 */
252 /*
253 * Locate pcb(s) for datagram.
254 * (Algorithm copied from raw_intr().)
255 */
256 last = NULL;
257 for (inp = udbtable.inpt_queue.cqh_first;
258 inp != (struct inpcb *)&udbtable.inpt_queue;
259 inp = inp->inp_queue.cqe_next) {
260 if (inp->inp_lport != uh->uh_dport)
261 continue;
262 if (!in_nullhost(inp->inp_laddr)) {
263 if (!in_hosteq(inp->inp_laddr, ip->ip_dst))
264 continue;
265 }
266 if (!in_nullhost(inp->inp_faddr)) {
267 if (!in_hosteq(inp->inp_faddr, ip->ip_src) ||
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 (last != NULL && ipsec4_in_reject(m, last)) {
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 m_adj(m, iphlen);
284 if (last->inp_flags & INP_CONTROLOPTS
285 || last->inp_socket->so_options &
286 SO_TIMESTAMP) {
287 ip_savecontrol(last, &opts,
288 ip, n);
289 }
290 sa = (struct sockaddr *)&udpsrc;
291 #ifdef MAPPED_ADDR_ENABLED
292 if (last->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) {
293 in6_sin_2_v4mapsin6(&udpsrc,
294 &mapped);
295 sa = (struct sockaddr *)&mapped;
296 }
297 #endif /* MAPPED_ADDR_ENABLED */
298 if (sbappendaddr(
299 &last->inp_socket->so_rcv,
300 sa, n, opts) == 0) {
301 m_freem(n);
302 if (opts)
303 m_freem(opts);
304 } else
305 sorwakeup(last->inp_socket);
306 opts = 0;
307 }
308 }
309 last = inp;
310 /*
311 * Don't look for additional matches if this one does
312 * not have either the SO_REUSEPORT or SO_REUSEADDR
313 * socket options set. This heuristic avoids searching
314 * through all pcbs in the common case of a non-shared
315 * port. It * assumes that an application will never
316 * clear these options after setting them.
317 */
318 if ((last->inp_socket->so_options &
319 (SO_REUSEPORT|SO_REUSEADDR)) == 0)
320 break;
321 }
322
323 if (last == NULL) {
324 /*
325 * No matching pcb found; discard datagram.
326 * (No need to send an ICMP Port Unreachable
327 * for a broadcast or multicast datgram.)
328 */
329 udpstat.udps_noport++;
330 udpstat.udps_noportbcast++;
331 goto bad;
332 }
333 #ifdef IPSEC
334 /* check AH/ESP integrity. */
335 if (last != NULL && ipsec4_in_reject(m, last)) {
336 ipsecstat.in_polvio++;
337 goto bad;
338 }
339 #endif /*IPSEC*/
340 if (last->inp_flags & INP_CONTROLOPTS ||
341 last->inp_socket->so_options & SO_TIMESTAMP)
342 ip_savecontrol(last, &opts, ip, m);
343 sa = (struct sockaddr *)&udpsrc;
344 #ifdef MAPPED_ADDR_ENABLED
345 if (last->inp_socket->so_proto->pr_domain->dom_family ==
346 AF_INET6) {
347 in6_sin_2_v4mapsin6(&udpsrc, &mapped);
348 sa = (struct sockaddr *)&mapped;
349 }
350 #endif /* MAPPED_ADDR_ENABLED */
351 if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) {
352 udpstat.udps_fullsock++;
353 goto bad;
354 }
355 sorwakeup(last->inp_socket);
356 return;
357 }
358 /*
359 * Locate pcb for datagram.
360 */
361 inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport,
362 ip->ip_dst, uh->uh_dport);
363 if (inp == 0) {
364 ++udpstat.udps_pcbhashmiss;
365 inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport);
366 if (inp == 0) {
367 udpstat.udps_noport++;
368 if (m->m_flags & (M_BCAST | M_MCAST)) {
369 udpstat.udps_noportbcast++;
370 goto bad;
371 }
372 *ip = save_ip;
373 #if NIPKDB > 0
374 if (checkipkdb(&ip->ip_src,
375 uh->uh_sport,
376 uh->uh_dport,
377 m,
378 iphlen + sizeof(struct udphdr),
379 len - sizeof(struct udphdr)))
380 /* It was a debugger connect packet, just drop it now */
381 goto bad;
382 #endif
383 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
384 return;
385 }
386 }
387 #ifdef IPSEC
388 if (inp != NULL && ipsec4_in_reject(m, inp)) {
389 ipsecstat.in_polvio++;
390 goto bad;
391 }
392 #endif /*IPSEC*/
393
394 /*
395 * Stuff source address and datagram in user buffer.
396 */
397 if (inp->inp_flags & INP_CONTROLOPTS ||
398 inp->inp_socket->so_options & SO_TIMESTAMP)
399 ip_savecontrol(inp, &opts, ip, m);
400 iphlen += sizeof(struct udphdr);
401 m->m_len -= iphlen;
402 m->m_pkthdr.len -= iphlen;
403 m->m_data += iphlen;
404 sa = (struct sockaddr *)&udpsrc;
405 #ifdef MAPPED_ADDR_ENABLED
406 if (inp->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) {
407 in6_sin_2_v4mapsin6(&udpsrc, &mapped);
408 sa = (struct sockaddr *)&mapped;
409 }
410 #endif /* MAPPED_ADDR_ENABLED */
411 if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) {
412 udpstat.udps_fullsock++;
413 goto bad;
414 }
415 sorwakeup(inp->inp_socket);
416 return;
417 bad:
418 m_freem(m);
419 if (opts)
420 m_freem(opts);
421 }
422
423 /*
424 * Notify a udp user of an asynchronous error;
425 * just wake up so that he can collect error status.
426 */
427 static void
428 udp_notify(inp, errno)
429 register struct inpcb *inp;
430 int errno;
431 {
432
433 inp->inp_socket->so_error = errno;
434 sorwakeup(inp->inp_socket);
435 sowwakeup(inp->inp_socket);
436 }
437
438 void *
439 udp_ctlinput(cmd, sa, v)
440 int cmd;
441 struct sockaddr *sa;
442 void *v;
443 {
444 register struct ip *ip = v;
445 register struct udphdr *uh;
446 extern int inetctlerrmap[];
447 void (*notify) __P((struct inpcb *, int)) = udp_notify;
448 int errno;
449
450 if ((unsigned)cmd >= PRC_NCMDS)
451 return NULL;
452 errno = inetctlerrmap[cmd];
453 if (PRC_IS_REDIRECT(cmd))
454 notify = in_rtchange, ip = 0;
455 else if (cmd == PRC_HOSTDEAD)
456 ip = 0;
457 else if (errno == 0)
458 return NULL;
459 if (ip) {
460 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
461 in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
462 ip->ip_src, uh->uh_sport, errno, notify);
463 } else
464 in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno,
465 notify);
466 return NULL;
467 }
468
469 int
470 #if __STDC__
471 udp_output(struct mbuf *m, ...)
472 #else
473 udp_output(m, va_alist)
474 struct mbuf *m;
475 va_dcl
476 #endif
477 {
478 register struct inpcb *inp;
479 register struct udpiphdr *ui;
480 register int len = m->m_pkthdr.len;
481 int error = 0;
482 va_list ap;
483
484 va_start(ap, m);
485 inp = va_arg(ap, struct inpcb *);
486 va_end(ap);
487
488 /*
489 * Calculate data length and get a mbuf
490 * for UDP and IP headers.
491 */
492 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
493 if (m == 0) {
494 error = ENOBUFS;
495 goto release;
496 }
497
498 /*
499 * Compute the packet length of the IP header, and
500 * punt if the length looks bogus.
501 */
502 if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
503 error = EMSGSIZE;
504 goto release;
505 }
506
507 /*
508 * Fill in mbuf with extended UDP header
509 * and addresses and length put into network format.
510 */
511 ui = mtod(m, struct udpiphdr *);
512 bzero(ui->ui_x1, sizeof ui->ui_x1);
513 ui->ui_pr = IPPROTO_UDP;
514 ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
515 ui->ui_src = inp->inp_laddr;
516 ui->ui_dst = inp->inp_faddr;
517 ui->ui_sport = inp->inp_lport;
518 ui->ui_dport = inp->inp_fport;
519 ui->ui_ulen = ui->ui_len;
520
521 /*
522 * Stuff checksum and output datagram.
523 */
524 ui->ui_sum = 0;
525 if (udpcksum) {
526 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
527 ui->ui_sum = 0xffff;
528 }
529 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
530 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
531 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
532 udpstat.udps_opackets++;
533
534 #ifdef IPSEC
535 m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket;
536 #endif /*IPSEC*/
537
538 return (ip_output(m, inp->inp_options, &inp->inp_route,
539 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
540 inp->inp_moptions));
541
542 release:
543 m_freem(m);
544 return (error);
545 }
546
547 int udp_sendspace = 9216; /* really max datagram size */
548 int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
549 /* 40 1K datagrams */
550
551 /*ARGSUSED*/
552 int
553 udp_usrreq(so, req, m, nam, control, p)
554 struct socket *so;
555 int req;
556 struct mbuf *m, *nam, *control;
557 struct proc *p;
558 {
559 register struct inpcb *inp;
560 int s;
561 register int error = 0;
562
563 if (req == PRU_CONTROL)
564 return (in_control(so, (long)m, (caddr_t)nam,
565 (struct ifnet *)control, p));
566
567 s = splsoftnet();
568 inp = sotoinpcb(so);
569 #ifdef DIAGNOSTIC
570 if (req != PRU_SEND && req != PRU_SENDOOB && control)
571 panic("udp_usrreq: unexpected control mbuf");
572 #endif
573 if (inp == 0 && req != PRU_ATTACH) {
574 error = EINVAL;
575 goto release;
576 }
577
578 /*
579 * Note: need to block udp_input while changing
580 * the udp pcb queue and/or pcb addresses.
581 */
582 switch (req) {
583
584 case PRU_ATTACH:
585 if (inp != 0) {
586 error = EISCONN;
587 break;
588 }
589 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
590 error = soreserve(so, udp_sendspace, udp_recvspace);
591 if (error)
592 break;
593 }
594 error = in_pcballoc(so, &udbtable);
595 if (error)
596 break;
597 inp = sotoinpcb(so);
598 inp->inp_ip.ip_ttl = ip_defttl;
599 #ifdef IPSEC
600 inp = (struct inpcb *)so->so_pcb;
601 error = ipsec_init_policy(&inp->inp_sp);
602 #endif /*IPSEC*/
603 break;
604
605 case PRU_DETACH:
606 in_pcbdetach(inp);
607 break;
608
609 case PRU_BIND:
610 error = in_pcbbind(inp, nam, p);
611 break;
612
613 case PRU_LISTEN:
614 error = EOPNOTSUPP;
615 break;
616
617 case PRU_CONNECT:
618 error = in_pcbconnect(inp, nam);
619 if (error)
620 break;
621 soisconnected(so);
622 break;
623
624 case PRU_CONNECT2:
625 error = EOPNOTSUPP;
626 break;
627
628 case PRU_DISCONNECT:
629 /*soisdisconnected(so);*/
630 so->so_state &= ~SS_ISCONNECTED; /* XXX */
631 in_pcbdisconnect(inp);
632 inp->inp_laddr = zeroin_addr; /* XXX */
633 in_pcbstate(inp, INP_BOUND); /* XXX */
634 break;
635
636 case PRU_SHUTDOWN:
637 socantsendmore(so);
638 break;
639
640 case PRU_RCVD:
641 error = EOPNOTSUPP;
642 break;
643
644 case PRU_SEND:
645 if (control && control->m_len) {
646 m_freem(control);
647 m_freem(m);
648 error = EINVAL;
649 break;
650 }
651 {
652 struct in_addr laddr; /* XXX */
653
654 if (nam) {
655 laddr = inp->inp_laddr; /* XXX */
656 if ((so->so_state & SS_ISCONNECTED) != 0) {
657 error = EISCONN;
658 goto die;
659 }
660 error = in_pcbconnect(inp, nam);
661 if (error) {
662 die:
663 m_freem(m);
664 break;
665 }
666 } else {
667 if ((so->so_state & SS_ISCONNECTED) == 0) {
668 error = ENOTCONN;
669 goto die;
670 }
671 }
672 error = udp_output(m, inp);
673 if (nam) {
674 in_pcbdisconnect(inp);
675 inp->inp_laddr = laddr; /* XXX */
676 in_pcbstate(inp, INP_BOUND); /* XXX */
677 }
678 }
679 break;
680
681 case PRU_SENSE:
682 /*
683 * stat: don't bother with a blocksize.
684 */
685 splx(s);
686 return (0);
687
688 case PRU_RCVOOB:
689 error = EOPNOTSUPP;
690 break;
691
692 case PRU_SENDOOB:
693 m_freem(control);
694 m_freem(m);
695 error = EOPNOTSUPP;
696 break;
697
698 case PRU_SOCKADDR:
699 in_setsockaddr(inp, nam);
700 break;
701
702 case PRU_PEERADDR:
703 in_setpeeraddr(inp, nam);
704 break;
705
706 default:
707 panic("udp_usrreq");
708 }
709
710 release:
711 splx(s);
712 return (error);
713 }
714
715 /*
716 * Sysctl for udp variables.
717 */
718 int
719 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
720 int *name;
721 u_int namelen;
722 void *oldp;
723 size_t *oldlenp;
724 void *newp;
725 size_t newlen;
726 {
727 /* All sysctl names at this level are terminal. */
728 if (namelen != 1)
729 return (ENOTDIR);
730
731 switch (name[0]) {
732 case UDPCTL_CHECKSUM:
733 return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
734 case UDPCTL_SENDSPACE:
735 return (sysctl_int(oldp, oldlenp, newp, newlen,
736 &udp_sendspace));
737 case UDPCTL_RECVSPACE:
738 return (sysctl_int(oldp, oldlenp, newp, newlen,
739 &udp_recvspace));
740 default:
741 return (ENOPROTOOPT);
742 }
743 /* NOTREACHED */
744 }
745