xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 57433)
123199Smckusick /*
244596Skarels  * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
332789Sbostic  * All rights reserved.
423199Smckusick  *
544642Sbostic  * %sccs.include.redist.c%
632789Sbostic  *
7*57433Sandrew  *	@(#)udp_usrreq.c	7.27 (Berkeley) 01/08/93
823199Smckusick  */
94784Swnj 
1056531Sbostic #include <sys/param.h>
1156531Sbostic #include <sys/malloc.h>
1256531Sbostic #include <sys/mbuf.h>
1356531Sbostic #include <sys/protosw.h>
1456531Sbostic #include <sys/socket.h>
1556531Sbostic #include <sys/socketvar.h>
1656531Sbostic #include <sys/errno.h>
1756531Sbostic #include <sys/stat.h>
1810897Ssam 
1956531Sbostic #include <net/if.h>
2056531Sbostic #include <net/route.h>
2110897Ssam 
2256531Sbostic #include <netinet/in.h>
2356531Sbostic #include <netinet/in_systm.h>
2456531Sbostic #include <netinet/ip.h>
2556531Sbostic #include <netinet/in_pcb.h>
2656531Sbostic #include <netinet/ip_var.h>
2756531Sbostic #include <netinet/ip_icmp.h>
2856531Sbostic #include <netinet/udp.h>
2956531Sbostic #include <netinet/udp_var.h>
304784Swnj 
3144596Skarels struct	inpcb *udp_last_inpcb = &udb;
3244596Skarels 
334926Swnj /*
344926Swnj  * UDP protocol implementation.
354926Swnj  * Per RFC 768, August, 1980.
364926Swnj  */
374805Swnj udp_init()
384805Swnj {
394901Swnj 	udb.inp_next = udb.inp_prev = &udb;
404805Swnj }
414805Swnj 
4226118Skarels #ifndef	COMPAT_42
4319519Skarels int	udpcksum = 1;
4426118Skarels #else
4526118Skarels int	udpcksum = 0;		/* XXX */
4626118Skarels #endif
4731398Skarels int	udp_ttl = UDP_TTL;
4826118Skarels 
4937324Skarels struct	sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
504901Swnj 
5135794Skarels udp_input(m, iphlen)
5235794Skarels 	register struct mbuf *m;
5335794Skarels 	int iphlen;
544784Swnj {
5540688Skarels 	register struct ip *ip;
5640688Skarels 	register struct udphdr *uh;
574887Swnj 	register struct inpcb *inp;
5844596Skarels 	struct mbuf *opts = 0;
597844Sroot 	int len;
6040688Skarels 	struct ip save_ip;
614784Swnj 
6244596Skarels 	udpstat.udps_ipackets++;
6344828Skarels 
6444828Skarels 	/*
6544828Skarels 	 * Strip IP options, if any; should skip this,
6644828Skarels 	 * make available to user, and use on returned packets,
6744828Skarels 	 * but we don't yet have a way to check the checksum
6844828Skarels 	 * with options still present.
6944828Skarels 	 */
7044828Skarels 	if (iphlen > sizeof (struct ip)) {
7140688Skarels 		ip_stripoptions(m, (struct mbuf *)0);
7244828Skarels 		iphlen = sizeof(struct ip);
7344828Skarels 	}
7444828Skarels 
754926Swnj 	/*
765246Sroot 	 * Get IP and UDP header together in first mbuf.
774926Swnj 	 */
7840688Skarels 	ip = mtod(m, struct ip *);
7940688Skarels 	if (m->m_len < iphlen + sizeof(struct udphdr)) {
8040688Skarels 		if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
8135288Skarels 			udpstat.udps_hdrops++;
8235288Skarels 			return;
8335288Skarels 		}
8440688Skarels 		ip = mtod(m, struct ip *);
8535288Skarels 	}
8640688Skarels 	uh = (struct udphdr *)((caddr_t)ip + iphlen);
874926Swnj 
884926Swnj 	/*
895246Sroot 	 * Make mbuf data length reflect UDP length.
905246Sroot 	 * If not enough data to reflect UDP length, drop.
914926Swnj 	 */
9240688Skarels 	len = ntohs((u_short)uh->uh_ulen);
9340688Skarels 	if (ip->ip_len != len) {
9440688Skarels 		if (len > ip->ip_len) {
954926Swnj 			udpstat.udps_badlen++;
964926Swnj 			goto bad;
974926Swnj 		}
9840688Skarels 		m_adj(m, len - ip->ip_len);
9940688Skarels 		/* ip->ip_len = len; */
1004926Swnj 	}
10124823Skarels 	/*
10240688Skarels 	 * Save a copy of the IP header in case we want restore it
10340688Skarels 	 * for sending an ICMP error message in response.
10424823Skarels 	 */
10540688Skarels 	save_ip = *ip;
1064926Swnj 
1074926Swnj 	/*
1085246Sroot 	 * Checksum extended UDP header and data.
1094926Swnj 	 */
11040688Skarels 	if (udpcksum && uh->uh_sum) {
11140688Skarels 		((struct ipovly *)ip)->ih_next = 0;
11240688Skarels 		((struct ipovly *)ip)->ih_prev = 0;
11340688Skarels 		((struct ipovly *)ip)->ih_x1 = 0;
11440688Skarels 		((struct ipovly *)ip)->ih_len = uh->uh_ulen;
11540688Skarels 		if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
1164926Swnj 			udpstat.udps_badsum++;
1174901Swnj 			m_freem(m);
1184901Swnj 			return;
1194901Swnj 		}
1204901Swnj 	}
1214926Swnj 
12254716Ssklower 	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
12354716Ssklower 	    in_broadcast(ip->ip_dst)) {
12454716Ssklower 		struct socket *last;
12554716Ssklower 		/*
12654716Ssklower 		 * Deliver a multicast or broadcast datagram to *all* sockets
12754716Ssklower 		 * for which the local and remote addresses and ports match
12854716Ssklower 		 * those of the incoming datagram.  This allows more than
12954716Ssklower 		 * one process to receive multi/broadcasts on the same port.
13054716Ssklower 		 * (This really ought to be done for unicast datagrams as
13154716Ssklower 		 * well, but that would cause problems with existing
13254716Ssklower 		 * applications that open both address-specific sockets and
13354716Ssklower 		 * a wildcard socket listening to the same port -- they would
13454716Ssklower 		 * end up receiving duplicates of every unicast datagram.
13554716Ssklower 		 * Those applications open the multiple sockets to overcome an
13654716Ssklower 		 * inadequacy of the UDP socket interface, but for backwards
13754716Ssklower 		 * compatibility we avoid the problem here rather than
138*57433Sandrew 		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
13954716Ssklower 		 */
14054716Ssklower 
14154716Ssklower 		/*
14254716Ssklower 		 * Construct sockaddr format source address.
14354716Ssklower 		 */
14454716Ssklower 		udp_in.sin_port = uh->uh_sport;
14554716Ssklower 		udp_in.sin_addr = ip->ip_src;
14654716Ssklower 		m->m_len -= sizeof (struct udpiphdr);
14754716Ssklower 		m->m_data += sizeof (struct udpiphdr);
14854716Ssklower 		/*
14954716Ssklower 		 * Locate pcb(s) for datagram.
15054716Ssklower 		 * (Algorithm copied from raw_intr().)
15154716Ssklower 		 */
15254716Ssklower 		last = NULL;
15354716Ssklower 		for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) {
15454716Ssklower 			if (inp->inp_lport != uh->uh_dport)
15554716Ssklower 				continue;
15654716Ssklower 			if (inp->inp_laddr.s_addr != INADDR_ANY) {
15754716Ssklower 				if (inp->inp_laddr.s_addr !=
15854716Ssklower 				    ip->ip_dst.s_addr)
15954716Ssklower 					continue;
16054716Ssklower 			}
16154716Ssklower 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
16254716Ssklower 				if (inp->inp_faddr.s_addr !=
16354716Ssklower 				    ip->ip_src.s_addr ||
16454716Ssklower 				    inp->inp_fport != uh->uh_sport)
16554716Ssklower 					continue;
16654716Ssklower 			}
16754716Ssklower 
16854716Ssklower 			if (last != NULL) {
16954716Ssklower 				struct mbuf *n;
17054716Ssklower 
17154716Ssklower 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
17254716Ssklower 					if (sbappendaddr(&last->so_rcv,
17354716Ssklower 						(struct sockaddr *)&udp_in,
174*57433Sandrew 						n, (struct mbuf *)0) == 0) {
17554716Ssklower 						m_freem(n);
176*57433Sandrew 						udpstat.udps_fullsock++;
177*57433Sandrew 					} else
17854716Ssklower 						sorwakeup(last);
17954716Ssklower 				}
18054716Ssklower 			}
18154716Ssklower 			last = inp->inp_socket;
18254716Ssklower 			/*
18354716Ssklower 			 * Don't look for additional matches if this one
18455348Ssklower 			 * does not have the SO_REUSEPORT socket option set.
18554716Ssklower 			 * This heuristic avoids searching through all pcbs
18654716Ssklower 			 * in the common case of a non-shared port.  It
18754716Ssklower 			 * assumes that an application will never clear
18855348Ssklower 			 * the SO_REUSEPORT option after setting it.
18954716Ssklower 			 */
19055348Ssklower 			if ((last->so_options & SO_REUSEPORT) == 0)
19154716Ssklower 				break;
19254716Ssklower 		}
19354716Ssklower 
19454716Ssklower 		if (last == NULL) {
19554716Ssklower 			/*
19654716Ssklower 			 * No matching pcb found; discard datagram.
19754716Ssklower 			 * (No need to send an ICMP Port Unreachable
19854716Ssklower 			 * for a broadcast or multicast datgram.)
19954716Ssklower 			 */
200*57433Sandrew 			udpstat.udps_noportbcast++;
20154716Ssklower 			goto bad;
20254716Ssklower 		}
20354716Ssklower 		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
204*57433Sandrew 		     m, (struct mbuf *)0) == 0) {
205*57433Sandrew 			udpstat.udps_fullsock++;
20654716Ssklower 			goto bad;
207*57433Sandrew 		}
20854716Ssklower 		sorwakeup(last);
20954716Ssklower 		return;
21054716Ssklower 	}
2114926Swnj 	/*
2127844Sroot 	 * Locate pcb for datagram.
2134926Swnj 	 */
21444596Skarels 	inp = udp_last_inpcb;
21544596Skarels 	if (inp->inp_lport != uh->uh_dport ||
21644596Skarels 	    inp->inp_fport != uh->uh_sport ||
21744596Skarels 	    inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
21844596Skarels 	    inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
21944596Skarels 		inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
22044596Skarels 		    ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
22144596Skarels 		if (inp)
22244596Skarels 			udp_last_inpcb = inp;
22344596Skarels 		udpstat.udpps_pcbcachemiss++;
22444596Skarels 	}
2256584Ssam 	if (inp == 0) {
22640688Skarels 		udpstat.udps_noport++;
22740688Skarels 		*ip = save_ip;
22844828Skarels 		ip->ip_len += iphlen;
22935794Skarels 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
2306584Ssam 		return;
2316584Ssam 	}
2326584Ssam 
2334926Swnj 	/*
2344926Swnj 	 * Construct sockaddr format source address.
2354926Swnj 	 * Stuff source address and datagram in user buffer.
2364926Swnj 	 */
23740688Skarels 	udp_in.sin_port = uh->uh_sport;
23840688Skarels 	udp_in.sin_addr = ip->ip_src;
23944596Skarels 	if (inp->inp_flags & INP_CONTROLOPTS) {
24044596Skarels 		struct mbuf **mp = &opts;
24144596Skarels 		struct mbuf *udp_saveopt();
24244596Skarels 
24344596Skarels 		if (inp->inp_flags & INP_RECVDSTADDR) {
24444596Skarels 			*mp = udp_saveopt((caddr_t) &ip->ip_dst,
24544596Skarels 			    sizeof(struct in_addr), IP_RECVDSTADDR);
24644596Skarels 			if (*mp)
24744596Skarels 				mp = &(*mp)->m_next;
24844596Skarels 		}
24944596Skarels #ifdef notyet
25044596Skarels 		/* options were tossed above */
25144596Skarels 		if (inp->inp_flags & INP_RECVOPTS) {
25244596Skarels 			*mp = udp_saveopt((caddr_t) opts_deleted_above,
25344596Skarels 			    sizeof(struct in_addr), IP_RECVOPTS);
25444596Skarels 			if (*mp)
25544596Skarels 				mp = &(*mp)->m_next;
25644596Skarels 		}
25744596Skarels 		/* ip_srcroute doesn't do what we want here, need to fix */
25844596Skarels 		if (inp->inp_flags & INP_RECVRETOPTS) {
25944596Skarels 			*mp = udp_saveopt((caddr_t) ip_srcroute(),
26044596Skarels 			    sizeof(struct in_addr), IP_RECVRETOPTS);
26144596Skarels 			if (*mp)
26244596Skarels 				mp = &(*mp)->m_next;
26344596Skarels 		}
26444596Skarels #endif
26544596Skarels 	}
26640688Skarels 	iphlen += sizeof(struct udphdr);
26740688Skarels 	m->m_len -= iphlen;
26840688Skarels 	m->m_pkthdr.len -= iphlen;
26940688Skarels 	m->m_data += iphlen;
27012767Ssam 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
27144596Skarels 	    m, opts) == 0) {
27244596Skarels 		udpstat.udps_fullsock++;
2734926Swnj 		goto bad;
27444596Skarels 	}
2755050Swnj 	sorwakeup(inp->inp_socket);
2764887Swnj 	return;
2774926Swnj bad:
2784887Swnj 	m_freem(m);
27944596Skarels 	if (opts)
28044596Skarels 		m_freem(opts);
2814784Swnj }
2824784Swnj 
28326426Skarels /*
28444596Skarels  * Create a "control" mbuf containing the specified data
28544596Skarels  * with the specified type for presentation with a datagram.
28644596Skarels  */
28744596Skarels struct mbuf *
28844596Skarels udp_saveopt(p, size, type)
28944596Skarels 	caddr_t p;
29044596Skarels 	register int size;
29144596Skarels 	int type;
29244596Skarels {
29344596Skarels 	register struct cmsghdr *cp;
29444596Skarels 	struct mbuf *m;
29544596Skarels 
29644596Skarels 	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
29744596Skarels 		return ((struct mbuf *) NULL);
29844596Skarels 	cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
29945645Ssklower 	bcopy(p, (caddr_t)(cp + 1), size);
30044596Skarels 	size += sizeof(*cp);
30144596Skarels 	m->m_len = size;
30244596Skarels 	cp->cmsg_len = size;
30344596Skarels 	cp->cmsg_level = IPPROTO_IP;
30444596Skarels 	cp->cmsg_type = type;
30544596Skarels 	return (m);
30644596Skarels }
30744596Skarels 
30844596Skarels /*
30926426Skarels  * Notify a udp user of an asynchronous error;
31026426Skarels  * just wake up so that he can collect error status.
31126426Skarels  */
31244596Skarels udp_notify(inp, errno)
31326426Skarels 	register struct inpcb *inp;
31452949Storek 	int errno;
31526426Skarels {
31644596Skarels 	inp->inp_socket->so_error = errno;
31726426Skarels 	sorwakeup(inp->inp_socket);
31826426Skarels 	sowwakeup(inp->inp_socket);
31926426Skarels }
32026426Skarels 
32140688Skarels udp_ctlinput(cmd, sa, ip)
3226591Ssam 	int cmd;
32324823Skarels 	struct sockaddr *sa;
32440688Skarels 	register struct ip *ip;
3256591Ssam {
32640688Skarels 	register struct udphdr *uh;
32740688Skarels 	extern struct in_addr zeroin_addr;
3286591Ssam 	extern u_char inetctlerrmap[];
3296591Ssam 
330*57433Sandrew 	if (!PRC_IS_REDIRECT(cmd) &&
331*57433Sandrew 	    ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
3326591Ssam 		return;
33340688Skarels 	if (ip) {
33440688Skarels 		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
33540688Skarels 		in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
33640688Skarels 			cmd, udp_notify);
33740688Skarels 	} else
33840688Skarels 		in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
3396591Ssam }
3406591Ssam 
34142184Skarels udp_output(inp, m, addr, control)
34226060Skarels 	register struct inpcb *inp;
34335794Skarels 	register struct mbuf *m;
34442184Skarels 	struct mbuf *addr, *control;
3454784Swnj {
3464926Swnj 	register struct udpiphdr *ui;
34735794Skarels 	register int len = m->m_pkthdr.len;
34842184Skarels 	struct in_addr laddr;
34942184Skarels 	int s, error = 0;
3504784Swnj 
35142184Skarels 	if (control)
35242184Skarels 		m_freem(control);		/* XXX */
35342184Skarels 
35442184Skarels 	if (addr) {
35542184Skarels 		laddr = inp->inp_laddr;
35642184Skarels 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
35742184Skarels 			error = EISCONN;
35842184Skarels 			goto release;
35942184Skarels 		}
36042184Skarels 		/*
36142184Skarels 		 * Must block input while temporarily connected.
36242184Skarels 		 */
36342184Skarels 		s = splnet();
36442184Skarels 		error = in_pcbconnect(inp, addr);
36542184Skarels 		if (error) {
36642184Skarels 			splx(s);
36742184Skarels 			goto release;
36842184Skarels 		}
36942184Skarels 	} else {
37042184Skarels 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
37142184Skarels 			error = ENOTCONN;
37242184Skarels 			goto release;
37342184Skarels 		}
37442184Skarels 	}
3754926Swnj 	/*
3764926Swnj 	 * Calculate data length and get a mbuf
3775246Sroot 	 * for UDP and IP headers.
3784926Swnj 	 */
37950715Smckusick 	M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
38050715Smckusick 	if (m == 0) {
38150715Smckusick 		error = ENOBUFS;
38250715Smckusick 		goto release;
38350715Smckusick 	}
3844784Swnj 
3854926Swnj 	/*
3865246Sroot 	 * Fill in mbuf with extended UDP header
3874926Swnj 	 * and addresses and length put into network format.
3884926Swnj 	 */
3894926Swnj 	ui = mtod(m, struct udpiphdr *);
3904926Swnj 	ui->ui_next = ui->ui_prev = 0;
3914926Swnj 	ui->ui_x1 = 0;
3924926Swnj 	ui->ui_pr = IPPROTO_UDP;
39315226Ssam 	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
3945050Swnj 	ui->ui_src = inp->inp_laddr;
3955050Swnj 	ui->ui_dst = inp->inp_faddr;
3965050Swnj 	ui->ui_sport = inp->inp_lport;
3975050Swnj 	ui->ui_dport = inp->inp_fport;
39815226Ssam 	ui->ui_ulen = ui->ui_len;
3994784Swnj 
4004926Swnj 	/*
4014926Swnj 	 * Stuff checksum and output datagram.
4024926Swnj 	 */
4034926Swnj 	ui->ui_sum = 0;
40419519Skarels 	if (udpcksum) {
40519519Skarels 	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
40633715Skarels 		ui->ui_sum = 0xffff;
40721112Skarels 	}
4085050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
40944596Skarels 	((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;	/* XXX */
41044596Skarels 	((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;	/* XXX */
41140688Skarels 	udpstat.udps_opackets++;
41242184Skarels 	error = ip_output(m, inp->inp_options, &inp->inp_route,
413*57433Sandrew 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
414*57433Sandrew 	    inp->inp_moptions);
41542184Skarels 
41642184Skarels 	if (addr) {
41742184Skarels 		in_pcbdisconnect(inp);
41842184Skarels 		inp->inp_laddr = laddr;
41942184Skarels 		splx(s);
42042184Skarels 	}
42142184Skarels 	return (error);
42242184Skarels 
42342184Skarels release:
42442184Skarels 	m_freem(m);
42542184Skarels 	return (error);
4264784Swnj }
4274784Swnj 
42838354Smckusick u_long	udp_sendspace = 9216;		/* really max datagram size */
42938354Smckusick u_long	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
43038354Smckusick 					/* 40 1K datagrams */
43118368Skarels 
4328602Sroot /*ARGSUSED*/
43342184Skarels udp_usrreq(so, req, m, addr, control)
4344887Swnj 	struct socket *so;
4354784Swnj 	int req;
43642184Skarels 	struct mbuf *m, *addr, *control;
4374784Swnj {
4384887Swnj 	struct inpcb *inp = sotoinpcb(so);
4396507Ssam 	int error = 0;
44044596Skarels 	int s;
4414784Swnj 
44218368Skarels 	if (req == PRU_CONTROL)
44342184Skarels 		return (in_control(so, (int)m, (caddr_t)addr,
44440688Skarels 			(struct ifnet *)control));
44511080Ssam 	if (inp == NULL && req != PRU_ATTACH) {
44611080Ssam 		error = EINVAL;
44711080Ssam 		goto release;
44811080Ssam 	}
44944596Skarels 	/*
45044968Skarels 	 * Note: need to block udp_input while changing
45144968Skarels 	 * the udp pcb queue and/or pcb addresses.
45244596Skarels 	 */
4534784Swnj 	switch (req) {
4544784Swnj 
4554784Swnj 	case PRU_ATTACH:
45611080Ssam 		if (inp != NULL) {
45711080Ssam 			error = EINVAL;
45811080Ssam 			break;
45911080Ssam 		}
46044596Skarels 		s = splnet();
4618273Sroot 		error = in_pcballoc(so, &udb);
46244596Skarels 		splx(s);
4638273Sroot 		if (error)
4648273Sroot 			break;
46518368Skarels 		error = soreserve(so, udp_sendspace, udp_recvspace);
4668273Sroot 		if (error)
4678273Sroot 			break;
46844596Skarels 		((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl;
4694887Swnj 		break;
4704784Swnj 
4714784Swnj 	case PRU_DETACH:
47244968Skarels 		udp_detach(inp);
4734887Swnj 		break;
4744784Swnj 
4758273Sroot 	case PRU_BIND:
47644968Skarels 		s = splnet();
47742184Skarels 		error = in_pcbbind(inp, addr);
47844968Skarels 		splx(s);
4798273Sroot 		break;
4808273Sroot 
4818273Sroot 	case PRU_LISTEN:
4828273Sroot 		error = EOPNOTSUPP;
4838273Sroot 		break;
4848273Sroot 
4854784Swnj 	case PRU_CONNECT:
48611080Ssam 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
48711080Ssam 			error = EISCONN;
48811080Ssam 			break;
48911080Ssam 		}
49044968Skarels 		s = splnet();
49142184Skarels 		error = in_pcbconnect(inp, addr);
49244968Skarels 		splx(s);
4936507Ssam 		if (error == 0)
4946507Ssam 			soisconnected(so);
4954887Swnj 		break;
4964784Swnj 
49713118Ssam 	case PRU_CONNECT2:
49813118Ssam 		error = EOPNOTSUPP;
49913118Ssam 		break;
50013118Ssam 
5014926Swnj 	case PRU_ACCEPT:
50211080Ssam 		error = EOPNOTSUPP;
50311080Ssam 		break;
5044926Swnj 
5054784Swnj 	case PRU_DISCONNECT:
50611080Ssam 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
50711080Ssam 			error = ENOTCONN;
50811080Ssam 			break;
50911080Ssam 		}
51044968Skarels 		s = splnet();
5115166Swnj 		in_pcbdisconnect(inp);
51240688Skarels 		inp->inp_laddr.s_addr = INADDR_ANY;
51344968Skarels 		splx(s);
51426404Skarels 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
5154784Swnj 		break;
5164784Swnj 
5174912Swnj 	case PRU_SHUTDOWN:
5184912Swnj 		socantsendmore(so);
5194912Swnj 		break;
5204912Swnj 
52142184Skarels 	case PRU_SEND:
52244596Skarels 		return (udp_output(inp, m, addr, control));
5234784Swnj 
5244784Swnj 	case PRU_ABORT:
52531750Skarels 		soisdisconnected(so);
52644968Skarels 		udp_detach(inp);
5274784Swnj 		break;
5284784Swnj 
5296511Ssam 	case PRU_SOCKADDR:
53042184Skarels 		in_setsockaddr(inp, addr);
5316511Ssam 		break;
5326511Ssam 
53314124Ssam 	case PRU_PEERADDR:
53442184Skarels 		in_setpeeraddr(inp, addr);
53514124Ssam 		break;
53614124Ssam 
53716988Skarels 	case PRU_SENSE:
53816988Skarels 		/*
53916988Skarels 		 * stat: don't bother with a blocksize.
54016988Skarels 		 */
54116988Skarels 		return (0);
54216988Skarels 
54312205Ssam 	case PRU_SENDOOB:
54412205Ssam 	case PRU_FASTTIMO:
54512205Ssam 	case PRU_SLOWTIMO:
54612205Ssam 	case PRU_PROTORCV:
54712205Ssam 	case PRU_PROTOSEND:
54812205Ssam 		error =  EOPNOTSUPP;
54912205Ssam 		break;
55013118Ssam 
55116799Skarels 	case PRU_RCVD:
55216799Skarels 	case PRU_RCVOOB:
55316799Skarels 		return (EOPNOTSUPP);	/* do not free mbuf's */
55416799Skarels 
55513118Ssam 	default:
55613118Ssam 		panic("udp_usrreq");
5574805Swnj 	}
55844596Skarels 
55911080Ssam release:
56042184Skarels 	if (control) {
56142184Skarels 		printf("udp control data unexpectedly retained\n");
56242184Skarels 		m_freem(control);
56342184Skarels 	}
56442184Skarels 	if (m)
56511080Ssam 		m_freem(m);
5666507Ssam 	return (error);
5674784Swnj }
56844968Skarels 
56944968Skarels udp_detach(inp)
57044968Skarels 	struct inpcb *inp;
57144968Skarels {
57244968Skarels 	int s = splnet();
57344968Skarels 
57444968Skarels 	if (inp == udp_last_inpcb)
57544968Skarels 		udp_last_inpcb = &udb;
57644968Skarels 	in_pcbdetach(inp);
57744968Skarels 	splx(s);
57844968Skarels }
579