xref: /freebsd/sys/netinet/udp_usrreq.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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  *	$Id: udp_usrreq.c,v 1.46 1998/03/28 10:18:26 bde Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/sysctl.h>
46 #include <sys/syslog.h>
47 
48 #include <vm/vm_zone.h>
49 
50 #include <net/if.h>
51 #include <net/route.h>
52 
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/in_var.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/ip_icmp.h>
60 #include <netinet/udp.h>
61 #include <netinet/udp_var.h>
62 
63 /*
64  * UDP protocol implementation.
65  * Per RFC 768, August, 1980.
66  */
67 #ifndef	COMPAT_42
68 static int	udpcksum = 1;
69 #else
70 static int	udpcksum = 0;		/* XXX */
71 #endif
72 SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
73 		&udpcksum, 0, "");
74 
75 static int log_in_vain = 0;
76 SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
77 	&log_in_vain, 0, "");
78 
79 static struct	inpcbhead udb;		/* from udp_var.h */
80 static struct	inpcbinfo udbinfo;
81 
82 #ifndef UDBHASHSIZE
83 #define UDBHASHSIZE 16
84 #endif
85 
86 static struct	udpstat udpstat;	/* from udp_var.h */
87 SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
88 	&udpstat, udpstat, "");
89 
90 static struct	sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
91 
92 static	int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
93 			    struct mbuf *, struct proc *));
94 static	void udp_notify __P((struct inpcb *, int));
95 
96 void
97 udp_init()
98 {
99 	LIST_INIT(&udb);
100 	udbinfo.listhead = &udb;
101 	udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
102 	udbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB,
103 					&udbinfo.porthashmask);
104 	udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets,
105 				 ZONE_INTERRUPT, 0);
106 }
107 
108 void
109 udp_input(m, iphlen)
110 	register struct mbuf *m;
111 	int iphlen;
112 {
113 	register struct ip *ip;
114 	register struct udphdr *uh;
115 	register struct inpcb *inp;
116 	struct mbuf *opts = 0;
117 	int len;
118 	struct ip save_ip;
119 
120 	udpstat.udps_ipackets++;
121 
122 	/*
123 	 * Strip IP options, if any; should skip this,
124 	 * make available to user, and use on returned packets,
125 	 * but we don't yet have a way to check the checksum
126 	 * with options still present.
127 	 */
128 	if (iphlen > sizeof (struct ip)) {
129 		ip_stripoptions(m, (struct mbuf *)0);
130 		iphlen = sizeof(struct ip);
131 	}
132 
133 	/*
134 	 * Get IP and UDP header together in first mbuf.
135 	 */
136 	ip = mtod(m, struct ip *);
137 	if (m->m_len < iphlen + sizeof(struct udphdr)) {
138 		if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
139 			udpstat.udps_hdrops++;
140 			return;
141 		}
142 		ip = mtod(m, struct ip *);
143 	}
144 	uh = (struct udphdr *)((caddr_t)ip + iphlen);
145 
146 	/*
147 	 * Make mbuf data length reflect UDP length.
148 	 * If not enough data to reflect UDP length, drop.
149 	 */
150 	len = ntohs((u_short)uh->uh_ulen);
151 	if (ip->ip_len != len) {
152 		if (len > ip->ip_len || len < sizeof(struct udphdr)) {
153 			udpstat.udps_badlen++;
154 			goto bad;
155 		}
156 		m_adj(m, len - ip->ip_len);
157 		/* ip->ip_len = len; */
158 	}
159 	/*
160 	 * Save a copy of the IP header in case we want restore it
161 	 * for sending an ICMP error message in response.
162 	 */
163 	save_ip = *ip;
164 
165 	/*
166 	 * Checksum extended UDP header and data.
167 	 */
168 	if (uh->uh_sum) {
169 		((struct ipovly *)ip)->ih_next = 0;
170 		((struct ipovly *)ip)->ih_prev = 0;
171 		((struct ipovly *)ip)->ih_x1 = 0;
172 		((struct ipovly *)ip)->ih_len = uh->uh_ulen;
173 		uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
174 		if (uh->uh_sum) {
175 			udpstat.udps_badsum++;
176 			m_freem(m);
177 			return;
178 		}
179 	}
180 
181 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
182 	    in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
183 		struct inpcb *last;
184 		/*
185 		 * Deliver a multicast or broadcast datagram to *all* sockets
186 		 * for which the local and remote addresses and ports match
187 		 * those of the incoming datagram.  This allows more than
188 		 * one process to receive multi/broadcasts on the same port.
189 		 * (This really ought to be done for unicast datagrams as
190 		 * well, but that would cause problems with existing
191 		 * applications that open both address-specific sockets and
192 		 * a wildcard socket listening to the same port -- they would
193 		 * end up receiving duplicates of every unicast datagram.
194 		 * Those applications open the multiple sockets to overcome an
195 		 * inadequacy of the UDP socket interface, but for backwards
196 		 * compatibility we avoid the problem here rather than
197 		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
198 		 */
199 
200 		/*
201 		 * Construct sockaddr format source address.
202 		 */
203 		udp_in.sin_port = uh->uh_sport;
204 		udp_in.sin_addr = ip->ip_src;
205 		m->m_len -= sizeof (struct udpiphdr);
206 		m->m_data += sizeof (struct udpiphdr);
207 		/*
208 		 * Locate pcb(s) for datagram.
209 		 * (Algorithm copied from raw_intr().)
210 		 */
211 		last = NULL;
212 		for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
213 			if (inp->inp_lport != uh->uh_dport)
214 				continue;
215 			if (inp->inp_laddr.s_addr != INADDR_ANY) {
216 				if (inp->inp_laddr.s_addr !=
217 				    ip->ip_dst.s_addr)
218 					continue;
219 			}
220 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
221 				if (inp->inp_faddr.s_addr !=
222 				    ip->ip_src.s_addr ||
223 				    inp->inp_fport != uh->uh_sport)
224 					continue;
225 			}
226 
227 			if (last != NULL) {
228 				struct mbuf *n;
229 
230 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
231 					if (last->inp_flags & INP_CONTROLOPTS
232 					    || last->inp_socket->so_options & SO_TIMESTAMP)
233 						ip_savecontrol(last, &opts, ip, n);
234 					if (sbappendaddr(&last->inp_socket->so_rcv,
235 						(struct sockaddr *)&udp_in,
236 						n, opts) == 0) {
237 						m_freem(n);
238 						if (opts)
239 						    m_freem(opts);
240 						udpstat.udps_fullsock++;
241 					} else
242 						sorwakeup(last->inp_socket);
243 					opts = 0;
244 				}
245 			}
246 			last = inp;
247 			/*
248 			 * Don't look for additional matches if this one does
249 			 * not have either the SO_REUSEPORT or SO_REUSEADDR
250 			 * socket options set.  This heuristic avoids searching
251 			 * through all pcbs in the common case of a non-shared
252 			 * port.  It * assumes that an application will never
253 			 * clear these options after setting them.
254 			 */
255 			if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
256 				break;
257 		}
258 
259 		if (last == NULL) {
260 			/*
261 			 * No matching pcb found; discard datagram.
262 			 * (No need to send an ICMP Port Unreachable
263 			 * for a broadcast or multicast datgram.)
264 			 */
265 			udpstat.udps_noportbcast++;
266 			goto bad;
267 		}
268 		if (last->inp_flags & INP_CONTROLOPTS
269 		    || last->inp_socket->so_options & SO_TIMESTAMP)
270 			ip_savecontrol(last, &opts, ip, m);
271 		if (sbappendaddr(&last->inp_socket->so_rcv,
272 		     (struct sockaddr *)&udp_in,
273 		     m, opts) == 0) {
274 			udpstat.udps_fullsock++;
275 			goto bad;
276 		}
277 		sorwakeup(last->inp_socket);
278 		return;
279 	}
280 	/*
281 	 * Locate pcb for datagram.
282 	 */
283 	inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport,
284 	    ip->ip_dst, uh->uh_dport, 1);
285 	if (inp == NULL) {
286 		if (log_in_vain) {
287 			char buf[4*sizeof "123"];
288 
289 			strcpy(buf, inet_ntoa(ip->ip_dst));
290 			log(LOG_INFO,
291 			    "Connection attempt to UDP %s:%d from %s:%d\n",
292 			    buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src),
293 			    ntohs(uh->uh_sport));
294 		}
295 		udpstat.udps_noport++;
296 		if (m->m_flags & (M_BCAST | M_MCAST)) {
297 			udpstat.udps_noportbcast++;
298 			goto bad;
299 		}
300 		*ip = save_ip;
301 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
302 		return;
303 	}
304 
305 	/*
306 	 * Construct sockaddr format source address.
307 	 * Stuff source address and datagram in user buffer.
308 	 */
309 	udp_in.sin_port = uh->uh_sport;
310 	udp_in.sin_addr = ip->ip_src;
311 	if (inp->inp_flags & INP_CONTROLOPTS
312 	    || inp->inp_socket->so_options & SO_TIMESTAMP)
313 		ip_savecontrol(inp, &opts, ip, m);
314 	iphlen += sizeof(struct udphdr);
315 	m->m_len -= iphlen;
316 	m->m_pkthdr.len -= iphlen;
317 	m->m_data += iphlen;
318 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
319 	    m, opts) == 0) {
320 		udpstat.udps_fullsock++;
321 		goto bad;
322 	}
323 	sorwakeup(inp->inp_socket);
324 	return;
325 bad:
326 	m_freem(m);
327 	if (opts)
328 		m_freem(opts);
329 }
330 
331 /*
332  * Notify a udp user of an asynchronous error;
333  * just wake up so that he can collect error status.
334  */
335 static void
336 udp_notify(inp, errno)
337 	register struct inpcb *inp;
338 	int errno;
339 {
340 	inp->inp_socket->so_error = errno;
341 	sorwakeup(inp->inp_socket);
342 	sowwakeup(inp->inp_socket);
343 }
344 
345 void
346 udp_ctlinput(cmd, sa, vip)
347 	int cmd;
348 	struct sockaddr *sa;
349 	void *vip;
350 {
351 	register struct ip *ip = vip;
352 	register struct udphdr *uh;
353 
354 	if (!PRC_IS_REDIRECT(cmd) &&
355 	    ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
356 		return;
357 	if (ip) {
358 		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
359 		in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
360 			cmd, udp_notify);
361 	} else
362 		in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
363 }
364 
365 static int
366 udp_pcblist SYSCTL_HANDLER_ARGS
367 {
368 	int error, i, n, s;
369 	struct inpcb *inp, **inp_list;
370 	inp_gen_t gencnt;
371 	struct xinpgen xig;
372 
373 	/*
374 	 * The process of preparing the TCB list is too time-consuming and
375 	 * resource-intensive to repeat twice on every request.
376 	 */
377 	if (req->oldptr == 0) {
378 		n = udbinfo.ipi_count;
379 		req->oldidx = 2 * (sizeof xig)
380 			+ (n + n/8) * sizeof(struct xinpcb);
381 		return 0;
382 	}
383 
384 	if (req->newptr != 0)
385 		return EPERM;
386 
387 	/*
388 	 * OK, now we're committed to doing something.
389 	 */
390 	s = splnet();
391 	gencnt = udbinfo.ipi_gencnt;
392 	n = udbinfo.ipi_count;
393 	splx(s);
394 
395 	xig.xig_len = sizeof xig;
396 	xig.xig_count = n;
397 	xig.xig_gen = gencnt;
398 	xig.xig_sogen = so_gencnt;
399 	error = SYSCTL_OUT(req, &xig, sizeof xig);
400 	if (error)
401 		return error;
402 
403 	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
404 	if (inp_list == 0)
405 		return ENOMEM;
406 
407 	s = splnet();
408 	for (inp = udbinfo.listhead->lh_first, i = 0; inp && i < n;
409 	     inp = inp->inp_list.le_next) {
410 		if (inp->inp_gencnt <= gencnt)
411 			inp_list[i++] = inp;
412 	}
413 	splx(s);
414 	n = i;
415 
416 	error = 0;
417 	for (i = 0; i < n; i++) {
418 		inp = inp_list[i];
419 		if (inp->inp_gencnt <= gencnt) {
420 			struct xinpcb xi;
421 			xi.xi_len = sizeof xi;
422 			/* XXX should avoid extra copy */
423 			bcopy(inp, &xi.xi_inp, sizeof *inp);
424 			if (inp->inp_socket)
425 				sotoxsocket(inp->inp_socket, &xi.xi_socket);
426 			error = SYSCTL_OUT(req, &xi, sizeof xi);
427 		}
428 	}
429 	if (!error) {
430 		/*
431 		 * Give the user an updated idea of our state.
432 		 * If the generation differs from what we told
433 		 * her before, she knows that something happened
434 		 * while we were processing this request, and it
435 		 * might be necessary to retry.
436 		 */
437 		s = splnet();
438 		xig.xig_gen = udbinfo.ipi_gencnt;
439 		xig.xig_sogen = so_gencnt;
440 		xig.xig_count = udbinfo.ipi_count;
441 		splx(s);
442 		error = SYSCTL_OUT(req, &xig, sizeof xig);
443 	}
444 	free(inp_list, M_TEMP);
445 	return error;
446 }
447 
448 SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
449 	    udp_pcblist, "S,xinpcb", "List of active UDP sockets");
450 
451 static int
452 udp_output(inp, m, addr, control, p)
453 	register struct inpcb *inp;
454 	register struct mbuf *m;
455 	struct sockaddr *addr;
456 	struct mbuf *control;
457 	struct proc *p;
458 {
459 	register struct udpiphdr *ui;
460 	register int len = m->m_pkthdr.len;
461 	struct in_addr laddr;
462 	int s = 0, error = 0;
463 
464 	if (control)
465 		m_freem(control);		/* XXX */
466 
467 	if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
468 		error = EMSGSIZE;
469 		goto release;
470 	}
471 
472 	if (addr) {
473 		laddr = inp->inp_laddr;
474 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
475 			error = EISCONN;
476 			goto release;
477 		}
478 		/*
479 		 * Must block input while temporarily connected.
480 		 */
481 		s = splnet();
482 		error = in_pcbconnect(inp, addr, p);
483 		if (error) {
484 			splx(s);
485 			goto release;
486 		}
487 	} else {
488 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
489 			error = ENOTCONN;
490 			goto release;
491 		}
492 	}
493 	/*
494 	 * Calculate data length and get a mbuf
495 	 * for UDP and IP headers.
496 	 */
497 	M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
498 	if (m == 0) {
499 		error = ENOBUFS;
500 		if (addr)
501 			splx(s);
502 		goto release;
503 	}
504 
505 	/*
506 	 * Fill in mbuf with extended UDP header
507 	 * and addresses and length put into network format.
508 	 */
509 	ui = mtod(m, struct udpiphdr *);
510 	ui->ui_next = ui->ui_prev = 0;
511 	ui->ui_x1 = 0;
512 	ui->ui_pr = IPPROTO_UDP;
513 	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
514 	ui->ui_src = inp->inp_laddr;
515 	ui->ui_dst = inp->inp_faddr;
516 	ui->ui_sport = inp->inp_lport;
517 	ui->ui_dport = inp->inp_fport;
518 	ui->ui_ulen = ui->ui_len;
519 
520 	/*
521 	 * Stuff checksum and output datagram.
522 	 */
523 	ui->ui_sum = 0;
524 	if (udpcksum) {
525 	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
526 		ui->ui_sum = 0xffff;
527 	}
528 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
529 	((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl;	/* XXX */
530 	((struct ip *)ui)->ip_tos = inp->inp_ip_tos;	/* XXX */
531 	udpstat.udps_opackets++;
532 	error = ip_output(m, inp->inp_options, &inp->inp_route,
533 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
534 	    inp->inp_moptions);
535 
536 	if (addr) {
537 		in_pcbdisconnect(inp);
538 		inp->inp_laddr = laddr;	/* XXX rehash? */
539 		splx(s);
540 	}
541 	return (error);
542 
543 release:
544 	m_freem(m);
545 	return (error);
546 }
547 
548 static u_long	udp_sendspace = 9216;		/* really max datagram size */
549 					/* 40 1K datagrams */
550 SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
551 	&udp_sendspace, 0, "");
552 
553 static u_long	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
554 SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
555 	&udp_recvspace, 0, "");
556 
557 static int
558 udp_abort(struct socket *so)
559 {
560 	struct inpcb *inp;
561 	int s;
562 
563 	inp = sotoinpcb(so);
564 	if (inp == 0)
565 		return EINVAL;	/* ??? possible? panic instead? */
566 	soisdisconnected(so);
567 	s = splnet();
568 	in_pcbdetach(inp);
569 	splx(s);
570 	return 0;
571 }
572 
573 static int
574 udp_attach(struct socket *so, int proto, struct proc *p)
575 {
576 	struct inpcb *inp;
577 	int s, error;
578 
579 	inp = sotoinpcb(so);
580 	if (inp != 0)
581 		return EINVAL;
582 
583 	s = splnet();
584 	error = in_pcballoc(so, &udbinfo, p);
585 	splx(s);
586 	if (error)
587 		return error;
588 	error = soreserve(so, udp_sendspace, udp_recvspace);
589 	if (error)
590 		return error;
591 	((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
592 	return 0;
593 }
594 
595 static int
596 udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
597 {
598 	struct inpcb *inp;
599 	int s, error;
600 
601 	inp = sotoinpcb(so);
602 	if (inp == 0)
603 		return EINVAL;
604 	s = splnet();
605 	error = in_pcbbind(inp, nam, p);
606 	splx(s);
607 	return error;
608 }
609 
610 static int
611 udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
612 {
613 	struct inpcb *inp;
614 	int s, error;
615 
616 	inp = sotoinpcb(so);
617 	if (inp == 0)
618 		return EINVAL;
619 	if (inp->inp_faddr.s_addr != INADDR_ANY)
620 		return EISCONN;
621 	s = splnet();
622 	error = in_pcbconnect(inp, nam, p);
623 	splx(s);
624 	if (error == 0)
625 		soisconnected(so);
626 	return error;
627 }
628 
629 static int
630 udp_detach(struct socket *so)
631 {
632 	struct inpcb *inp;
633 	int s;
634 
635 	inp = sotoinpcb(so);
636 	if (inp == 0)
637 		return EINVAL;
638 	s = splnet();
639 	in_pcbdetach(inp);
640 	splx(s);
641 	return 0;
642 }
643 
644 static int
645 udp_disconnect(struct socket *so)
646 {
647 	struct inpcb *inp;
648 	int s;
649 
650 	inp = sotoinpcb(so);
651 	if (inp == 0)
652 		return EINVAL;
653 	if (inp->inp_faddr.s_addr == INADDR_ANY)
654 		return ENOTCONN;
655 
656 	s = splnet();
657 	in_pcbdisconnect(inp);
658 	inp->inp_laddr.s_addr = INADDR_ANY;
659 	splx(s);
660 	so->so_state &= ~SS_ISCONNECTED;		/* XXX */
661 	return 0;
662 }
663 
664 static int
665 udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
666 	    struct mbuf *control, struct proc *p)
667 {
668 	struct inpcb *inp;
669 
670 	inp = sotoinpcb(so);
671 	if (inp == 0) {
672 		m_freem(m);
673 		return EINVAL;
674 	}
675 	return udp_output(inp, m, addr, control, p);
676 }
677 
678 static int
679 udp_shutdown(struct socket *so)
680 {
681 	struct inpcb *inp;
682 
683 	inp = sotoinpcb(so);
684 	if (inp == 0)
685 		return EINVAL;
686 	socantsendmore(so);
687 	return 0;
688 }
689 
690 struct pr_usrreqs udp_usrreqs = {
691 	udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
692 	pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
693 	pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
694 	pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
695 	in_setsockaddr, sosend, soreceive, sopoll
696 };
697