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