xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 42184)
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*42184Skarels  *	@(#)udp_usrreq.c	7.14 (Berkeley) 05/17/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"
3640688Skarels #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 {
6540688Skarels 	register struct ip *ip;
6640688Skarels 	register struct udphdr *uh;
674887Swnj 	register struct inpcb *inp;
687844Sroot 	int len;
6940688Skarels 	struct ip save_ip;
704784Swnj 
7140688Skarels #ifndef notyet
7240688Skarels 	if (iphlen > sizeof (struct ip))
7340688Skarels 		ip_stripoptions(m, (struct mbuf *)0);
7440688Skarels #endif
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 
1224926Swnj 	/*
1237844Sroot 	 * Locate pcb for datagram.
1244926Swnj 	 */
1254926Swnj 	inp = in_pcblookup(&udb,
12640688Skarels 	    ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport,
12740688Skarels 	    INPLOOKUP_WILDCARD);
1286584Ssam 	if (inp == 0) {
12910144Ssam 		/* don't send ICMP response for broadcast packet */
13040688Skarels 		udpstat.udps_noport++;
13135794Skarels 		if (m->m_flags & M_BCAST)
1326584Ssam 			goto bad;
13340688Skarels 		*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 	 */
14240688Skarels 	udp_in.sin_port = uh->uh_sport;
14340688Skarels 	udp_in.sin_addr = ip->ip_src;
14440688Skarels iphlen = sizeof(struct ip);
14540688Skarels 	iphlen += sizeof(struct udphdr);
14640688Skarels 	m->m_len -= iphlen;
14740688Skarels 	m->m_pkthdr.len -= iphlen;
14840688Skarels 	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;
15240688Skarels 	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 
17140688Skarels udp_ctlinput(cmd, sa, ip)
1726591Ssam 	int cmd;
17324823Skarels 	struct sockaddr *sa;
17440688Skarels 	register struct ip *ip;
1756591Ssam {
17640688Skarels 	register struct udphdr *uh;
17740688Skarels 	extern struct in_addr zeroin_addr;
1786591Ssam 	extern u_char inetctlerrmap[];
1796591Ssam 
18040688Skarels 	if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
1816591Ssam 		return;
18240688Skarels 	if (ip) {
18340688Skarels 		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
18440688Skarels 		in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
18540688Skarels 			cmd, udp_notify);
18640688Skarels 	} else
18740688Skarels 		in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
1886591Ssam }
1896591Ssam 
190*42184Skarels udp_output(inp, m, addr, control)
19126060Skarels 	register struct inpcb *inp;
19235794Skarels 	register struct mbuf *m;
193*42184Skarels 	struct mbuf *addr, *control;
1944784Swnj {
1954926Swnj 	register struct udpiphdr *ui;
19635794Skarels 	register int len = m->m_pkthdr.len;
197*42184Skarels 	struct in_addr laddr;
198*42184Skarels 	int s, error = 0;
1994784Swnj 
200*42184Skarels 	if (control)
201*42184Skarels 		m_freem(control);		/* XXX */
202*42184Skarels 
203*42184Skarels 	if (addr) {
204*42184Skarels 		laddr = inp->inp_laddr;
205*42184Skarels 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
206*42184Skarels 			error = EISCONN;
207*42184Skarels 			goto release;
208*42184Skarels 		}
209*42184Skarels 		/*
210*42184Skarels 		 * Must block input while temporarily connected.
211*42184Skarels 		 */
212*42184Skarels 		s = splnet();
213*42184Skarels 		error = in_pcbconnect(inp, addr);
214*42184Skarels 		if (error) {
215*42184Skarels 			splx(s);
216*42184Skarels 			goto release;
217*42184Skarels 		}
218*42184Skarels 	} else {
219*42184Skarels 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
220*42184Skarels 			error = ENOTCONN;
221*42184Skarels 			goto release;
222*42184Skarels 		}
223*42184Skarels 	}
2244926Swnj 	/*
2254926Swnj 	 * Calculate data length and get a mbuf
2265246Sroot 	 * for UDP and IP headers.
2274926Swnj 	 */
22835794Skarels 	M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
2294784Swnj 
2304926Swnj 	/*
2315246Sroot 	 * Fill in mbuf with extended UDP header
2324926Swnj 	 * and addresses and length put into network format.
2334926Swnj 	 */
2344926Swnj 	ui = mtod(m, struct udpiphdr *);
2354926Swnj 	ui->ui_next = ui->ui_prev = 0;
2364926Swnj 	ui->ui_x1 = 0;
2374926Swnj 	ui->ui_pr = IPPROTO_UDP;
23815226Ssam 	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
2395050Swnj 	ui->ui_src = inp->inp_laddr;
2405050Swnj 	ui->ui_dst = inp->inp_faddr;
2415050Swnj 	ui->ui_sport = inp->inp_lport;
2425050Swnj 	ui->ui_dport = inp->inp_fport;
24315226Ssam 	ui->ui_ulen = ui->ui_len;
2444784Swnj 
2454926Swnj 	/*
2464926Swnj 	 * Stuff checksum and output datagram.
2474926Swnj 	 */
2484926Swnj 	ui->ui_sum = 0;
24919519Skarels 	if (udpcksum) {
25019519Skarels 	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
25133715Skarels 		ui->ui_sum = 0xffff;
25221112Skarels 	}
2535050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
25431398Skarels 	((struct ip *)ui)->ip_ttl = udp_ttl;
25540688Skarels 	udpstat.udps_opackets++;
256*42184Skarels 	error = ip_output(m, inp->inp_options, &inp->inp_route,
257*42184Skarels 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
258*42184Skarels 
259*42184Skarels 	if (addr) {
260*42184Skarels 		in_pcbdisconnect(inp);
261*42184Skarels 		inp->inp_laddr = laddr;
262*42184Skarels 		splx(s);
263*42184Skarels 	}
264*42184Skarels 	return (error);
265*42184Skarels 
266*42184Skarels release:
267*42184Skarels 	m_freem(m);
268*42184Skarels 	return (error);
2694784Swnj }
2704784Swnj 
27138354Smckusick u_long	udp_sendspace = 9216;		/* really max datagram size */
27238354Smckusick u_long	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
27338354Smckusick 					/* 40 1K datagrams */
27418368Skarels 
2758602Sroot /*ARGSUSED*/
276*42184Skarels udp_usrreq(so, req, m, addr, control)
2774887Swnj 	struct socket *so;
2784784Swnj 	int req;
279*42184Skarels 	struct mbuf *m, *addr, *control;
2804784Swnj {
2814887Swnj 	struct inpcb *inp = sotoinpcb(so);
2826507Ssam 	int error = 0;
2834784Swnj 
28418368Skarels 	if (req == PRU_CONTROL)
285*42184Skarels 		return (in_control(so, (int)m, (caddr_t)addr,
28640688Skarels 			(struct ifnet *)control));
28711080Ssam 	if (inp == NULL && req != PRU_ATTACH) {
28811080Ssam 		error = EINVAL;
28911080Ssam 		goto release;
29011080Ssam 	}
2914784Swnj 	switch (req) {
2924784Swnj 
2934784Swnj 	case PRU_ATTACH:
29411080Ssam 		if (inp != NULL) {
29511080Ssam 			error = EINVAL;
29611080Ssam 			break;
29711080Ssam 		}
2988273Sroot 		error = in_pcballoc(so, &udb);
2998273Sroot 		if (error)
3008273Sroot 			break;
30118368Skarels 		error = soreserve(so, udp_sendspace, udp_recvspace);
3028273Sroot 		if (error)
3038273Sroot 			break;
3044887Swnj 		break;
3054784Swnj 
3064784Swnj 	case PRU_DETACH:
3075166Swnj 		in_pcbdetach(inp);
3084887Swnj 		break;
3094784Swnj 
3108273Sroot 	case PRU_BIND:
311*42184Skarels 		error = in_pcbbind(inp, addr);
3128273Sroot 		break;
3138273Sroot 
3148273Sroot 	case PRU_LISTEN:
3158273Sroot 		error = EOPNOTSUPP;
3168273Sroot 		break;
3178273Sroot 
3184784Swnj 	case PRU_CONNECT:
31911080Ssam 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
32011080Ssam 			error = EISCONN;
32111080Ssam 			break;
32211080Ssam 		}
323*42184Skarels 		error = in_pcbconnect(inp, addr);
3246507Ssam 		if (error == 0)
3256507Ssam 			soisconnected(so);
3264887Swnj 		break;
3274784Swnj 
32813118Ssam 	case PRU_CONNECT2:
32913118Ssam 		error = EOPNOTSUPP;
33013118Ssam 		break;
33113118Ssam 
3324926Swnj 	case PRU_ACCEPT:
33311080Ssam 		error = EOPNOTSUPP;
33411080Ssam 		break;
3354926Swnj 
3364784Swnj 	case PRU_DISCONNECT:
33711080Ssam 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
33811080Ssam 			error = ENOTCONN;
33911080Ssam 			break;
34011080Ssam 		}
3415166Swnj 		in_pcbdisconnect(inp);
34240688Skarels 		inp->inp_laddr.s_addr = INADDR_ANY;
34326404Skarels 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
3444784Swnj 		break;
3454784Swnj 
3464912Swnj 	case PRU_SHUTDOWN:
3474912Swnj 		socantsendmore(so);
3484912Swnj 		break;
3494912Swnj 
350*42184Skarels 	case PRU_SEND:
351*42184Skarels 		error = udp_output(inp, m, addr, control);
35211080Ssam 		m = NULL;
353*42184Skarels 		control = NULL;
3544784Swnj 		break;
3554784Swnj 
3564784Swnj 	case PRU_ABORT:
35731750Skarels 		soisdisconnected(so);
3585166Swnj 		in_pcbdetach(inp);
3594784Swnj 		break;
3604784Swnj 
3616511Ssam 	case PRU_SOCKADDR:
362*42184Skarels 		in_setsockaddr(inp, addr);
3636511Ssam 		break;
3646511Ssam 
36514124Ssam 	case PRU_PEERADDR:
366*42184Skarels 		in_setpeeraddr(inp, addr);
36714124Ssam 		break;
36814124Ssam 
36916988Skarels 	case PRU_SENSE:
37016988Skarels 		/*
37116988Skarels 		 * stat: don't bother with a blocksize.
37216988Skarels 		 */
37316988Skarels 		return (0);
37416988Skarels 
37512205Ssam 	case PRU_SENDOOB:
37612205Ssam 	case PRU_FASTTIMO:
37712205Ssam 	case PRU_SLOWTIMO:
37812205Ssam 	case PRU_PROTORCV:
37912205Ssam 	case PRU_PROTOSEND:
38012205Ssam 		error =  EOPNOTSUPP;
38112205Ssam 		break;
38213118Ssam 
38316799Skarels 	case PRU_RCVD:
38416799Skarels 	case PRU_RCVOOB:
38516799Skarels 		return (EOPNOTSUPP);	/* do not free mbuf's */
38616799Skarels 
38713118Ssam 	default:
38813118Ssam 		panic("udp_usrreq");
3894805Swnj 	}
39011080Ssam release:
391*42184Skarels 	if (control) {
392*42184Skarels 		printf("udp control data unexpectedly retained\n");
393*42184Skarels 		m_freem(control);
394*42184Skarels 	}
395*42184Skarels 	if (m)
39611080Ssam 		m_freem(m);
3976507Ssam 	return (error);
3984784Swnj }
399