udp_usrreq.c revision 1.51 1 /* $NetBSD: udp_usrreq.c,v 1.51 1999/08/09 10:55:29 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
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 (sa->sa_family != AF_INET ||
458 sa->sa_len != sizeof(struct sockaddr_in))
459 return NULL;
460 if ((unsigned)cmd >= PRC_NCMDS)
461 return NULL;
462 errno = inetctlerrmap[cmd];
463 if (PRC_IS_REDIRECT(cmd))
464 notify = in_rtchange, ip = 0;
465 else if (cmd == PRC_HOSTDEAD)
466 ip = 0;
467 else if (errno == 0)
468 return NULL;
469 if (ip) {
470 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
471 in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
472 ip->ip_src, uh->uh_sport, errno, notify);
473 } else
474 in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno,
475 notify);
476 return NULL;
477 }
478
479 int
480 #if __STDC__
481 udp_output(struct mbuf *m, ...)
482 #else
483 udp_output(m, va_alist)
484 struct mbuf *m;
485 va_dcl
486 #endif
487 {
488 register struct inpcb *inp;
489 register struct udpiphdr *ui;
490 register int len = m->m_pkthdr.len;
491 int error = 0;
492 va_list ap;
493
494 va_start(ap, m);
495 inp = va_arg(ap, struct inpcb *);
496 va_end(ap);
497
498 /*
499 * Calculate data length and get a mbuf
500 * for UDP and IP headers.
501 */
502 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
503 if (m == 0) {
504 error = ENOBUFS;
505 goto release;
506 }
507
508 /*
509 * Compute the packet length of the IP header, and
510 * punt if the length looks bogus.
511 */
512 if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
513 error = EMSGSIZE;
514 goto release;
515 }
516
517 /*
518 * Fill in mbuf with extended UDP header
519 * and addresses and length put into network format.
520 */
521 ui = mtod(m, struct udpiphdr *);
522 bzero(ui->ui_x1, sizeof ui->ui_x1);
523 ui->ui_pr = IPPROTO_UDP;
524 ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
525 ui->ui_src = inp->inp_laddr;
526 ui->ui_dst = inp->inp_faddr;
527 ui->ui_sport = inp->inp_lport;
528 ui->ui_dport = inp->inp_fport;
529 ui->ui_ulen = ui->ui_len;
530
531 /*
532 * Stuff checksum and output datagram.
533 */
534 ui->ui_sum = 0;
535 if (udpcksum) {
536 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
537 ui->ui_sum = 0xffff;
538 }
539 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
540 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
541 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
542 udpstat.udps_opackets++;
543
544 #ifdef IPSEC
545 m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket;
546 #endif /*IPSEC*/
547
548 return (ip_output(m, inp->inp_options, &inp->inp_route,
549 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
550 inp->inp_moptions));
551
552 release:
553 m_freem(m);
554 return (error);
555 }
556
557 int udp_sendspace = 9216; /* really max datagram size */
558 int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
559 /* 40 1K datagrams */
560
561 /*ARGSUSED*/
562 int
563 udp_usrreq(so, req, m, nam, control, p)
564 struct socket *so;
565 int req;
566 struct mbuf *m, *nam, *control;
567 struct proc *p;
568 {
569 register struct inpcb *inp;
570 int s;
571 register int error = 0;
572
573 if (req == PRU_CONTROL)
574 return (in_control(so, (long)m, (caddr_t)nam,
575 (struct ifnet *)control, p));
576
577 s = splsoftnet();
578 inp = sotoinpcb(so);
579 #ifdef DIAGNOSTIC
580 if (req != PRU_SEND && req != PRU_SENDOOB && control)
581 panic("udp_usrreq: unexpected control mbuf");
582 #endif
583 if (inp == 0 && req != PRU_ATTACH) {
584 error = EINVAL;
585 goto release;
586 }
587
588 /*
589 * Note: need to block udp_input while changing
590 * the udp pcb queue and/or pcb addresses.
591 */
592 switch (req) {
593
594 case PRU_ATTACH:
595 if (inp != 0) {
596 error = EISCONN;
597 break;
598 }
599 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
600 error = soreserve(so, udp_sendspace, udp_recvspace);
601 if (error)
602 break;
603 }
604 error = in_pcballoc(so, &udbtable);
605 if (error)
606 break;
607 inp = sotoinpcb(so);
608 inp->inp_ip.ip_ttl = ip_defttl;
609 #ifdef IPSEC
610 inp = (struct inpcb *)so->so_pcb;
611 error = ipsec_init_policy(&inp->inp_sp);
612 #endif /*IPSEC*/
613 break;
614
615 case PRU_DETACH:
616 in_pcbdetach(inp);
617 break;
618
619 case PRU_BIND:
620 error = in_pcbbind(inp, nam, p);
621 break;
622
623 case PRU_LISTEN:
624 error = EOPNOTSUPP;
625 break;
626
627 case PRU_CONNECT:
628 error = in_pcbconnect(inp, nam);
629 if (error)
630 break;
631 soisconnected(so);
632 break;
633
634 case PRU_CONNECT2:
635 error = EOPNOTSUPP;
636 break;
637
638 case PRU_DISCONNECT:
639 /*soisdisconnected(so);*/
640 so->so_state &= ~SS_ISCONNECTED; /* XXX */
641 in_pcbdisconnect(inp);
642 inp->inp_laddr = zeroin_addr; /* XXX */
643 in_pcbstate(inp, INP_BOUND); /* XXX */
644 break;
645
646 case PRU_SHUTDOWN:
647 socantsendmore(so);
648 break;
649
650 case PRU_RCVD:
651 error = EOPNOTSUPP;
652 break;
653
654 case PRU_SEND:
655 if (control && control->m_len) {
656 m_freem(control);
657 m_freem(m);
658 error = EINVAL;
659 break;
660 }
661 {
662 struct in_addr laddr; /* XXX */
663
664 if (nam) {
665 laddr = inp->inp_laddr; /* XXX */
666 if ((so->so_state & SS_ISCONNECTED) != 0) {
667 error = EISCONN;
668 goto die;
669 }
670 error = in_pcbconnect(inp, nam);
671 if (error) {
672 die:
673 m_freem(m);
674 break;
675 }
676 } else {
677 if ((so->so_state & SS_ISCONNECTED) == 0) {
678 error = ENOTCONN;
679 goto die;
680 }
681 }
682 error = udp_output(m, inp);
683 if (nam) {
684 in_pcbdisconnect(inp);
685 inp->inp_laddr = laddr; /* XXX */
686 in_pcbstate(inp, INP_BOUND); /* XXX */
687 }
688 }
689 break;
690
691 case PRU_SENSE:
692 /*
693 * stat: don't bother with a blocksize.
694 */
695 splx(s);
696 return (0);
697
698 case PRU_RCVOOB:
699 error = EOPNOTSUPP;
700 break;
701
702 case PRU_SENDOOB:
703 m_freem(control);
704 m_freem(m);
705 error = EOPNOTSUPP;
706 break;
707
708 case PRU_SOCKADDR:
709 in_setsockaddr(inp, nam);
710 break;
711
712 case PRU_PEERADDR:
713 in_setpeeraddr(inp, nam);
714 break;
715
716 default:
717 panic("udp_usrreq");
718 }
719
720 release:
721 splx(s);
722 return (error);
723 }
724
725 /*
726 * Sysctl for udp variables.
727 */
728 int
729 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
730 int *name;
731 u_int namelen;
732 void *oldp;
733 size_t *oldlenp;
734 void *newp;
735 size_t newlen;
736 {
737 /* All sysctl names at this level are terminal. */
738 if (namelen != 1)
739 return (ENOTDIR);
740
741 switch (name[0]) {
742 case UDPCTL_CHECKSUM:
743 return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
744 case UDPCTL_SENDSPACE:
745 return (sysctl_int(oldp, oldlenp, newp, newlen,
746 &udp_sendspace));
747 case UDPCTL_RECVSPACE:
748 return (sysctl_int(oldp, oldlenp, newp, newlen,
749 &udp_recvspace));
750 default:
751 return (ENOPROTOOPT);
752 }
753 /* NOTREACHED */
754 }
755