xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 40688)
123199Smckusick /*
235794Skarels  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
332789Sbostic  * All rights reserved.
423199Smckusick  *
532789Sbostic  * Redistribution and use in source and binary forms are permitted
634855Sbostic  * provided that the above copyright notice and this paragraph are
734855Sbostic  * duplicated in all such forms and that any documentation,
834855Sbostic  * advertising materials, and other materials related to such
934855Sbostic  * distribution and use acknowledge that the software was developed
1034855Sbostic  * by the University of California, Berkeley.  The name of the
1134855Sbostic  * University may not be used to endorse or promote products derived
1234855Sbostic  * from this software without specific prior written permission.
1334855Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434855Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534855Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1632789Sbostic  *
17*40688Skarels  *	@(#)udp_usrreq.c	7.13 (Berkeley) 04/03/90
1823199Smckusick  */
194784Swnj 
2017065Sbloom #include "param.h"
2117065Sbloom #include "user.h"
2235794Skarels #include "malloc.h"
2317065Sbloom #include "mbuf.h"
2417065Sbloom #include "protosw.h"
2517065Sbloom #include "socket.h"
2617065Sbloom #include "socketvar.h"
2717065Sbloom #include "errno.h"
2817065Sbloom #include "stat.h"
2910897Ssam 
306584Ssam #include "../net/if.h"
316354Ssam #include "../net/route.h"
3210897Ssam 
3317065Sbloom #include "in.h"
3417065Sbloom #include "in_systm.h"
3517065Sbloom #include "ip.h"
36*40688Skarels #include "in_pcb.h"
3717065Sbloom #include "ip_var.h"
3817065Sbloom #include "ip_icmp.h"
3917065Sbloom #include "udp.h"
4017065Sbloom #include "udp_var.h"
414784Swnj 
424926Swnj /*
434926Swnj  * UDP protocol implementation.
444926Swnj  * Per RFC 768, August, 1980.
454926Swnj  */
464805Swnj udp_init()
474805Swnj {
484805Swnj 
494901Swnj 	udb.inp_next = udb.inp_prev = &udb;
504805Swnj }
514805Swnj 
5226118Skarels #ifndef	COMPAT_42
5319519Skarels int	udpcksum = 1;
5426118Skarels #else
5526118Skarels int	udpcksum = 0;		/* XXX */
5626118Skarels #endif
5731398Skarels int	udp_ttl = UDP_TTL;
5826118Skarels 
5937324Skarels struct	sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
604901Swnj 
6135794Skarels udp_input(m, iphlen)
6235794Skarels 	register struct mbuf *m;
6335794Skarels 	int iphlen;
644784Swnj {
65*40688Skarels 	register struct ip *ip;
66*40688Skarels 	register struct udphdr *uh;
674887Swnj 	register struct inpcb *inp;
687844Sroot 	int len;
69*40688Skarels 	struct ip save_ip;
704784Swnj 
71*40688Skarels #ifndef notyet
72*40688Skarels 	if (iphlen > sizeof (struct ip))
73*40688Skarels 		ip_stripoptions(m, (struct mbuf *)0);
74*40688Skarels #endif
754926Swnj 	/*
765246Sroot 	 * Get IP and UDP header together in first mbuf.
774926Swnj 	 */
78*40688Skarels 	ip = mtod(m, struct ip *);
79*40688Skarels 	if (m->m_len < iphlen + sizeof(struct udphdr)) {
80*40688Skarels 		if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
8135288Skarels 			udpstat.udps_hdrops++;
8235288Skarels 			return;
8335288Skarels 		}
84*40688Skarels 		ip = mtod(m, struct ip *);
8535288Skarels 	}
86*40688Skarels 	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 	 */
92*40688Skarels 	len = ntohs((u_short)uh->uh_ulen);
93*40688Skarels 	if (ip->ip_len != len) {
94*40688Skarels 		if (len > ip->ip_len) {
954926Swnj 			udpstat.udps_badlen++;
964926Swnj 			goto bad;
974926Swnj 		}
98*40688Skarels 		m_adj(m, len - ip->ip_len);
99*40688Skarels 		/* ip->ip_len = len; */
1004926Swnj 	}
10124823Skarels 	/*
102*40688Skarels 	 * Save a copy of the IP header in case we want restore it
103*40688Skarels 	 * for sending an ICMP error message in response.
10424823Skarels 	 */
105*40688Skarels 	save_ip = *ip;
1064926Swnj 
1074926Swnj 	/*
1085246Sroot 	 * Checksum extended UDP header and data.
1094926Swnj 	 */
110*40688Skarels 	if (udpcksum && uh->uh_sum) {
111*40688Skarels 		((struct ipovly *)ip)->ih_next = 0;
112*40688Skarels 		((struct ipovly *)ip)->ih_prev = 0;
113*40688Skarels 		((struct ipovly *)ip)->ih_x1 = 0;
114*40688Skarels 		((struct ipovly *)ip)->ih_len = uh->uh_ulen;
115*40688Skarels 		if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
1164926Swnj 			udpstat.udps_badsum++;
1174901Swnj 			m_freem(m);
1184901Swnj 			return;
1194901Swnj 		}
1204901Swnj 	}
1214926Swnj 
1224926Swnj 	/*
1237844Sroot 	 * Locate pcb for datagram.
1244926Swnj 	 */
1254926Swnj 	inp = in_pcblookup(&udb,
126*40688Skarels 	    ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport,
127*40688Skarels 	    INPLOOKUP_WILDCARD);
1286584Ssam 	if (inp == 0) {
12910144Ssam 		/* don't send ICMP response for broadcast packet */
130*40688Skarels 		udpstat.udps_noport++;
13135794Skarels 		if (m->m_flags & M_BCAST)
1326584Ssam 			goto bad;
133*40688Skarels 		*ip = save_ip;
13435794Skarels 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
1356584Ssam 		return;
1366584Ssam 	}
1376584Ssam 
1384926Swnj 	/*
1394926Swnj 	 * Construct sockaddr format source address.
1404926Swnj 	 * Stuff source address and datagram in user buffer.
1414926Swnj 	 */
142*40688Skarels 	udp_in.sin_port = uh->uh_sport;
143*40688Skarels 	udp_in.sin_addr = ip->ip_src;
144*40688Skarels iphlen = sizeof(struct ip);
145*40688Skarels 	iphlen += sizeof(struct udphdr);
146*40688Skarels 	m->m_len -= iphlen;
147*40688Skarels 	m->m_pkthdr.len -= iphlen;
148*40688Skarels 	m->m_data += iphlen;
14912767Ssam 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
15012767Ssam 	    m, (struct mbuf *)0) == 0)
1514926Swnj 		goto bad;
152*40688Skarels 	udpstat.udps_ipackets++;
1535050Swnj 	sorwakeup(inp->inp_socket);
1544887Swnj 	return;
1554926Swnj bad:
1564887Swnj 	m_freem(m);
1574784Swnj }
1584784Swnj 
15926426Skarels /*
16026426Skarels  * Notify a udp user of an asynchronous error;
16126426Skarels  * just wake up so that he can collect error status.
16226426Skarels  */
16326426Skarels udp_notify(inp)
16426426Skarels 	register struct inpcb *inp;
16526426Skarels {
16626426Skarels 
16726426Skarels 	sorwakeup(inp->inp_socket);
16826426Skarels 	sowwakeup(inp->inp_socket);
16926426Skarels }
17026426Skarels 
171*40688Skarels udp_ctlinput(cmd, sa, ip)
1726591Ssam 	int cmd;
17324823Skarels 	struct sockaddr *sa;
174*40688Skarels 	register struct ip *ip;
1756591Ssam {
176*40688Skarels 	register struct udphdr *uh;
177*40688Skarels 	extern struct in_addr zeroin_addr;
1786591Ssam 	extern u_char inetctlerrmap[];
1796591Ssam 
180*40688Skarels 	if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
1816591Ssam 		return;
182*40688Skarels 	if (ip) {
183*40688Skarels 		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
184*40688Skarels 		in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
185*40688Skarels 			cmd, udp_notify);
186*40688Skarels 	} else
187*40688Skarels 		in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
1886591Ssam }
1896591Ssam 
19035794Skarels udp_output(inp, m)
19126060Skarels 	register struct inpcb *inp;
19235794Skarels 	register struct mbuf *m;
1934784Swnj {
1944926Swnj 	register struct udpiphdr *ui;
19535794Skarels 	register int len = m->m_pkthdr.len;
1964784Swnj 
1974926Swnj 	/*
1984926Swnj 	 * Calculate data length and get a mbuf
1995246Sroot 	 * for UDP and IP headers.
2004926Swnj 	 */
20135794Skarels 	M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
2024784Swnj 
2034926Swnj 	/*
2045246Sroot 	 * Fill in mbuf with extended UDP header
2054926Swnj 	 * and addresses and length put into network format.
2064926Swnj 	 */
2074926Swnj 	ui = mtod(m, struct udpiphdr *);
2084926Swnj 	ui->ui_next = ui->ui_prev = 0;
2094926Swnj 	ui->ui_x1 = 0;
2104926Swnj 	ui->ui_pr = IPPROTO_UDP;
21115226Ssam 	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
2125050Swnj 	ui->ui_src = inp->inp_laddr;
2135050Swnj 	ui->ui_dst = inp->inp_faddr;
2145050Swnj 	ui->ui_sport = inp->inp_lport;
2155050Swnj 	ui->ui_dport = inp->inp_fport;
21615226Ssam 	ui->ui_ulen = ui->ui_len;
2174784Swnj 
2184926Swnj 	/*
2194926Swnj 	 * Stuff checksum and output datagram.
2204926Swnj 	 */
2214926Swnj 	ui->ui_sum = 0;
22219519Skarels 	if (udpcksum) {
22319519Skarels 	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
22433715Skarels 		ui->ui_sum = 0xffff;
22521112Skarels 	}
2265050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
22731398Skarels 	((struct ip *)ui)->ip_ttl = udp_ttl;
228*40688Skarels 	udpstat.udps_opackets++;
22926060Skarels 	return (ip_output(m, inp->inp_options, &inp->inp_route,
23026060Skarels 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
2314784Swnj }
2324784Swnj 
23338354Smckusick u_long	udp_sendspace = 9216;		/* really max datagram size */
23438354Smckusick u_long	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
23538354Smckusick 					/* 40 1K datagrams */
23618368Skarels 
2378602Sroot /*ARGSUSED*/
238*40688Skarels udp_usrreq(so, req, m, nam, control)
2394887Swnj 	struct socket *so;
2404784Swnj 	int req;
241*40688Skarels 	struct mbuf *m, *nam, *control;
2424784Swnj {
2434887Swnj 	struct inpcb *inp = sotoinpcb(so);
2446507Ssam 	int error = 0;
2454784Swnj 
24618368Skarels 	if (req == PRU_CONTROL)
24718368Skarels 		return (in_control(so, (int)m, (caddr_t)nam,
248*40688Skarels 			(struct ifnet *)control));
24911080Ssam 	if (inp == NULL && req != PRU_ATTACH) {
25011080Ssam 		error = EINVAL;
25111080Ssam 		goto release;
25211080Ssam 	}
2534784Swnj 	switch (req) {
2544784Swnj 
2554784Swnj 	case PRU_ATTACH:
25611080Ssam 		if (inp != NULL) {
25711080Ssam 			error = EINVAL;
25811080Ssam 			break;
25911080Ssam 		}
2608273Sroot 		error = in_pcballoc(so, &udb);
2618273Sroot 		if (error)
2628273Sroot 			break;
26318368Skarels 		error = soreserve(so, udp_sendspace, udp_recvspace);
2648273Sroot 		if (error)
2658273Sroot 			break;
2664887Swnj 		break;
2674784Swnj 
2684784Swnj 	case PRU_DETACH:
2695166Swnj 		in_pcbdetach(inp);
2704887Swnj 		break;
2714784Swnj 
2728273Sroot 	case PRU_BIND:
2738273Sroot 		error = in_pcbbind(inp, nam);
2748273Sroot 		break;
2758273Sroot 
2768273Sroot 	case PRU_LISTEN:
2778273Sroot 		error = EOPNOTSUPP;
2788273Sroot 		break;
2798273Sroot 
2804784Swnj 	case PRU_CONNECT:
28111080Ssam 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
28211080Ssam 			error = EISCONN;
28311080Ssam 			break;
28411080Ssam 		}
2858273Sroot 		error = in_pcbconnect(inp, nam);
2866507Ssam 		if (error == 0)
2876507Ssam 			soisconnected(so);
2884887Swnj 		break;
2894784Swnj 
29013118Ssam 	case PRU_CONNECT2:
29113118Ssam 		error = EOPNOTSUPP;
29213118Ssam 		break;
29313118Ssam 
2944926Swnj 	case PRU_ACCEPT:
29511080Ssam 		error = EOPNOTSUPP;
29611080Ssam 		break;
2974926Swnj 
2984784Swnj 	case PRU_DISCONNECT:
29911080Ssam 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
30011080Ssam 			error = ENOTCONN;
30111080Ssam 			break;
30211080Ssam 		}
3035166Swnj 		in_pcbdisconnect(inp);
304*40688Skarels 		inp->inp_laddr.s_addr = INADDR_ANY;
30526404Skarels 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
3064784Swnj 		break;
3074784Swnj 
3084912Swnj 	case PRU_SHUTDOWN:
3094912Swnj 		socantsendmore(so);
3104912Swnj 		break;
3114912Swnj 
3125996Swnj 	case PRU_SEND: {
3135996Swnj 		struct in_addr laddr;
31416799Skarels 		int s;
3155996Swnj 
3168273Sroot 		if (nam) {
3175996Swnj 			laddr = inp->inp_laddr;
31811080Ssam 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
31911080Ssam 				error = EISCONN;
32011080Ssam 				break;
32111080Ssam 			}
32216799Skarels 			/*
32316799Skarels 			 * Must block input while temporarily connected.
32416799Skarels 			 */
32516799Skarels 			s = splnet();
3268273Sroot 			error = in_pcbconnect(inp, nam);
32716799Skarels 			if (error) {
32816799Skarels 				splx(s);
3296507Ssam 				break;
33016799Skarels 			}
3314955Swnj 		} else {
33211080Ssam 			if (inp->inp_faddr.s_addr == INADDR_ANY) {
33311080Ssam 				error = ENOTCONN;
33411080Ssam 				break;
33511080Ssam 			}
3364955Swnj 		}
3376507Ssam 		error = udp_output(inp, m);
33811080Ssam 		m = NULL;
3398273Sroot 		if (nam) {
3405166Swnj 			in_pcbdisconnect(inp);
34118368Skarels 			inp->inp_laddr = laddr;
34216799Skarels 			splx(s);
3435996Swnj 		}
3445996Swnj 		}
3454784Swnj 		break;
3464784Swnj 
3474784Swnj 	case PRU_ABORT:
34831750Skarels 		soisdisconnected(so);
3495166Swnj 		in_pcbdetach(inp);
3504784Swnj 		break;
3514784Swnj 
3526511Ssam 	case PRU_SOCKADDR:
3538273Sroot 		in_setsockaddr(inp, nam);
3546511Ssam 		break;
3556511Ssam 
35614124Ssam 	case PRU_PEERADDR:
35714124Ssam 		in_setpeeraddr(inp, nam);
35814124Ssam 		break;
35914124Ssam 
36016988Skarels 	case PRU_SENSE:
36116988Skarels 		/*
36216988Skarels 		 * stat: don't bother with a blocksize.
36316988Skarels 		 */
36416988Skarels 		return (0);
36516988Skarels 
36612205Ssam 	case PRU_SENDOOB:
36712205Ssam 	case PRU_FASTTIMO:
36812205Ssam 	case PRU_SLOWTIMO:
36912205Ssam 	case PRU_PROTORCV:
37012205Ssam 	case PRU_PROTOSEND:
37112205Ssam 		error =  EOPNOTSUPP;
37212205Ssam 		break;
37313118Ssam 
37416799Skarels 	case PRU_RCVD:
37516799Skarels 	case PRU_RCVOOB:
37616799Skarels 		return (EOPNOTSUPP);	/* do not free mbuf's */
37716799Skarels 
37813118Ssam 	default:
37913118Ssam 		panic("udp_usrreq");
3804805Swnj 	}
38111080Ssam release:
38211080Ssam 	if (m != NULL)
38311080Ssam 		m_freem(m);
3846507Ssam 	return (error);
3854784Swnj }
386