xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 37324)
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*37324Skarels  *	@(#)udp_usrreq.c	7.10 (Berkeley) 04/08/89
1823199Smckusick  */
194784Swnj 
2017065Sbloom #include "param.h"
2117065Sbloom #include "dir.h"
2217065Sbloom #include "user.h"
2335794Skarels #include "malloc.h"
2417065Sbloom #include "mbuf.h"
2517065Sbloom #include "protosw.h"
2617065Sbloom #include "socket.h"
2717065Sbloom #include "socketvar.h"
2817065Sbloom #include "errno.h"
2917065Sbloom #include "stat.h"
3010897Ssam 
316584Ssam #include "../net/if.h"
326354Ssam #include "../net/route.h"
3310897Ssam 
3417065Sbloom #include "in.h"
3517065Sbloom #include "in_pcb.h"
3617065Sbloom #include "in_systm.h"
3717065Sbloom #include "ip.h"
3817065Sbloom #include "ip_var.h"
3917065Sbloom #include "ip_icmp.h"
4017065Sbloom #include "udp.h"
4117065Sbloom #include "udp_var.h"
424784Swnj 
434926Swnj /*
444926Swnj  * UDP protocol implementation.
454926Swnj  * Per RFC 768, August, 1980.
464926Swnj  */
474805Swnj udp_init()
484805Swnj {
494805Swnj 
504901Swnj 	udb.inp_next = udb.inp_prev = &udb;
514805Swnj }
524805Swnj 
5326118Skarels #ifndef	COMPAT_42
5419519Skarels int	udpcksum = 1;
5526118Skarels #else
5626118Skarels int	udpcksum = 0;		/* XXX */
5726118Skarels #endif
5831398Skarels int	udp_ttl = UDP_TTL;
5926118Skarels 
60*37324Skarels struct	sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
614901Swnj 
6235794Skarels udp_input(m, iphlen)
6335794Skarels 	register struct mbuf *m;
6435794Skarels 	int iphlen;
654784Swnj {
664901Swnj 	register struct udpiphdr *ui;
674887Swnj 	register struct inpcb *inp;
687844Sroot 	int len;
6924823Skarels 	struct ip ip;
704784Swnj 
714926Swnj 	/*
725246Sroot 	 * Get IP and UDP header together in first mbuf.
7335288Skarels 	 * Note: IP leaves IP header in first mbuf.
744926Swnj 	 */
755050Swnj 	ui = mtod(m, struct udpiphdr *);
7635794Skarels 	if (iphlen > sizeof (struct ip))
7735794Skarels 		ip_stripoptions(m, (struct mbuf *)0);
7835794Skarels 	if (m->m_len < sizeof (struct udpiphdr)) {
7935288Skarels 		if ((m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
8035288Skarels 			udpstat.udps_hdrops++;
8135288Skarels 			return;
8235288Skarels 		}
8335288Skarels 		ui = mtod(m, struct udpiphdr *);
8435288Skarels 	}
854926Swnj 
864926Swnj 	/*
875246Sroot 	 * Make mbuf data length reflect UDP length.
885246Sroot 	 * If not enough data to reflect UDP length, drop.
894926Swnj 	 */
907844Sroot 	len = ntohs((u_short)ui->ui_ulen);
914926Swnj 	if (((struct ip *)ui)->ip_len != len) {
924926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
934926Swnj 			udpstat.udps_badlen++;
944926Swnj 			goto bad;
954926Swnj 		}
9615539Skarels 		m_adj(m, len - ((struct ip *)ui)->ip_len);
9724823Skarels 		/* ((struct ip *)ui)->ip_len = len; */
984926Swnj 	}
9924823Skarels 	/*
10024823Skarels 	 * Save a copy of the IP header in case we want restore it for ICMP.
10124823Skarels 	 */
10235794Skarels 	ip = *(struct ip *)ui;
1034926Swnj 
1044926Swnj 	/*
1055246Sroot 	 * Checksum extended UDP header and data.
1064926Swnj 	 */
10715539Skarels 	if (udpcksum && ui->ui_sum) {
1084926Swnj 		ui->ui_next = ui->ui_prev = 0;
1094926Swnj 		ui->ui_x1 = 0;
11021112Skarels 		ui->ui_len = ui->ui_ulen;
1117844Sroot 		if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
1124926Swnj 			udpstat.udps_badsum++;
1134901Swnj 			m_freem(m);
1144901Swnj 			return;
1154901Swnj 		}
1164901Swnj 	}
1174926Swnj 
1184926Swnj 	/*
1197844Sroot 	 * Locate pcb for datagram.
1204926Swnj 	 */
1214926Swnj 	inp = in_pcblookup(&udb,
1226029Sroot 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
1236029Sroot 		INPLOOKUP_WILDCARD);
1246584Ssam 	if (inp == 0) {
12510144Ssam 		/* don't send ICMP response for broadcast packet */
12635794Skarels 		if (m->m_flags & M_BCAST)
1276584Ssam 			goto bad;
12824823Skarels 		*(struct ip *)ui = ip;
12935794Skarels 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
1306584Ssam 		return;
1316584Ssam 	}
1326584Ssam 
1334926Swnj 	/*
1344926Swnj 	 * Construct sockaddr format source address.
1354926Swnj 	 * Stuff source address and datagram in user buffer.
1364926Swnj 	 */
1374926Swnj 	udp_in.sin_port = ui->ui_sport;
1384926Swnj 	udp_in.sin_addr = ui->ui_src;
1395050Swnj 	m->m_len -= sizeof (struct udpiphdr);
14035794Skarels 	m->m_pkthdr.len -= sizeof (struct udpiphdr);
14135794Skarels 	m->m_data += sizeof (struct udpiphdr);
14212767Ssam 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
14312767Ssam 	    m, (struct mbuf *)0) == 0)
1444926Swnj 		goto bad;
1455050Swnj 	sorwakeup(inp->inp_socket);
1464887Swnj 	return;
1474926Swnj bad:
1484887Swnj 	m_freem(m);
1494784Swnj }
1504784Swnj 
15126426Skarels /*
15226426Skarels  * Notify a udp user of an asynchronous error;
15326426Skarels  * just wake up so that he can collect error status.
15426426Skarels  */
15526426Skarels udp_notify(inp)
15626426Skarels 	register struct inpcb *inp;
15726426Skarels {
15826426Skarels 
15926426Skarels 	sorwakeup(inp->inp_socket);
16026426Skarels 	sowwakeup(inp->inp_socket);
16126426Skarels }
16226426Skarels 
16324823Skarels udp_ctlinput(cmd, sa)
1646591Ssam 	int cmd;
16524823Skarels 	struct sockaddr *sa;
1666591Ssam {
1676591Ssam 	extern u_char inetctlerrmap[];
16824823Skarels 	struct sockaddr_in *sin;
16921121Skarels 	int in_rtchange();
1706591Ssam 
17124823Skarels 	if ((unsigned)cmd > PRC_NCMDS)
1726591Ssam 		return;
17324823Skarels 	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
17424823Skarels 		return;
17524823Skarels 	sin = (struct sockaddr_in *)sa;
17624823Skarels 	if (sin->sin_addr.s_addr == INADDR_ANY)
17724823Skarels 		return;
17824823Skarels 
1796591Ssam 	switch (cmd) {
1806591Ssam 
18124823Skarels 	case PRC_QUENCH:
1826591Ssam 		break;
1836591Ssam 
18424823Skarels 	case PRC_ROUTEDEAD:
18521121Skarels 	case PRC_REDIRECT_NET:
18621121Skarels 	case PRC_REDIRECT_HOST:
18724823Skarels 	case PRC_REDIRECT_TOSNET:
18824823Skarels 	case PRC_REDIRECT_TOSHOST:
18924823Skarels 		in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange);
1906591Ssam 		break;
1916591Ssam 
1926591Ssam 	default:
19321121Skarels 		if (inetctlerrmap[cmd] == 0)
19421121Skarels 			return;		/* XXX */
19524823Skarels 		in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd],
19626426Skarels 			udp_notify);
1976591Ssam 	}
1986591Ssam }
1996591Ssam 
20035794Skarels udp_output(inp, m)
20126060Skarels 	register struct inpcb *inp;
20235794Skarels 	register struct mbuf *m;
2034784Swnj {
2044926Swnj 	register struct udpiphdr *ui;
20535794Skarels 	register int len = m->m_pkthdr.len;
2064784Swnj 
2074926Swnj 	/*
2084926Swnj 	 * Calculate data length and get a mbuf
2095246Sroot 	 * for UDP and IP headers.
2104926Swnj 	 */
21135794Skarels 	M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
2124784Swnj 
2134926Swnj 	/*
2145246Sroot 	 * Fill in mbuf with extended UDP header
2154926Swnj 	 * and addresses and length put into network format.
2164926Swnj 	 */
2174926Swnj 	ui = mtod(m, struct udpiphdr *);
2184926Swnj 	ui->ui_next = ui->ui_prev = 0;
2194926Swnj 	ui->ui_x1 = 0;
2204926Swnj 	ui->ui_pr = IPPROTO_UDP;
22115226Ssam 	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
2225050Swnj 	ui->ui_src = inp->inp_laddr;
2235050Swnj 	ui->ui_dst = inp->inp_faddr;
2245050Swnj 	ui->ui_sport = inp->inp_lport;
2255050Swnj 	ui->ui_dport = inp->inp_fport;
22615226Ssam 	ui->ui_ulen = ui->ui_len;
2274784Swnj 
2284926Swnj 	/*
2294926Swnj 	 * Stuff checksum and output datagram.
2304926Swnj 	 */
2314926Swnj 	ui->ui_sum = 0;
23219519Skarels 	if (udpcksum) {
23319519Skarels 	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
23433715Skarels 		ui->ui_sum = 0xffff;
23521112Skarels 	}
2365050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
23731398Skarels 	((struct ip *)ui)->ip_ttl = udp_ttl;
23826060Skarels 	return (ip_output(m, inp->inp_options, &inp->inp_route,
23926060Skarels 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
2404784Swnj }
2414784Swnj 
24234500Skarels u_long	udp_sendspace = 2048;		/* really max datagram size */
24334500Skarels u_long	udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */
24418368Skarels 
2458602Sroot /*ARGSUSED*/
24635794Skarels udp_usrreq(so, req, m, nam, rights, control)
2474887Swnj 	struct socket *so;
2484784Swnj 	int req;
24935794Skarels 	struct mbuf *m, *nam, *rights, *control;
2504784Swnj {
2514887Swnj 	struct inpcb *inp = sotoinpcb(so);
2526507Ssam 	int error = 0;
2534784Swnj 
25418368Skarels 	if (req == PRU_CONTROL)
25518368Skarels 		return (in_control(so, (int)m, (caddr_t)nam,
25618368Skarels 			(struct ifnet *)rights));
25712767Ssam 	if (rights && rights->m_len) {
25812767Ssam 		error = EINVAL;
25912767Ssam 		goto release;
26012767Ssam 	}
26111080Ssam 	if (inp == NULL && req != PRU_ATTACH) {
26211080Ssam 		error = EINVAL;
26311080Ssam 		goto release;
26411080Ssam 	}
2654784Swnj 	switch (req) {
2664784Swnj 
2674784Swnj 	case PRU_ATTACH:
26811080Ssam 		if (inp != NULL) {
26911080Ssam 			error = EINVAL;
27011080Ssam 			break;
27111080Ssam 		}
2728273Sroot 		error = in_pcballoc(so, &udb);
2738273Sroot 		if (error)
2748273Sroot 			break;
27518368Skarels 		error = soreserve(so, udp_sendspace, udp_recvspace);
2768273Sroot 		if (error)
2778273Sroot 			break;
2784887Swnj 		break;
2794784Swnj 
2804784Swnj 	case PRU_DETACH:
2815166Swnj 		in_pcbdetach(inp);
2824887Swnj 		break;
2834784Swnj 
2848273Sroot 	case PRU_BIND:
2858273Sroot 		error = in_pcbbind(inp, nam);
2868273Sroot 		break;
2878273Sroot 
2888273Sroot 	case PRU_LISTEN:
2898273Sroot 		error = EOPNOTSUPP;
2908273Sroot 		break;
2918273Sroot 
2924784Swnj 	case PRU_CONNECT:
29311080Ssam 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
29411080Ssam 			error = EISCONN;
29511080Ssam 			break;
29611080Ssam 		}
2978273Sroot 		error = in_pcbconnect(inp, nam);
2986507Ssam 		if (error == 0)
2996507Ssam 			soisconnected(so);
3004887Swnj 		break;
3014784Swnj 
30213118Ssam 	case PRU_CONNECT2:
30313118Ssam 		error = EOPNOTSUPP;
30413118Ssam 		break;
30513118Ssam 
3064926Swnj 	case PRU_ACCEPT:
30711080Ssam 		error = EOPNOTSUPP;
30811080Ssam 		break;
3094926Swnj 
3104784Swnj 	case PRU_DISCONNECT:
31111080Ssam 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
31211080Ssam 			error = ENOTCONN;
31311080Ssam 			break;
31411080Ssam 		}
3155166Swnj 		in_pcbdisconnect(inp);
31626404Skarels 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
3174784Swnj 		break;
3184784Swnj 
3194912Swnj 	case PRU_SHUTDOWN:
3204912Swnj 		socantsendmore(so);
3214912Swnj 		break;
3224912Swnj 
3235996Swnj 	case PRU_SEND: {
3245996Swnj 		struct in_addr laddr;
32516799Skarels 		int s;
3265996Swnj 
3278273Sroot 		if (nam) {
3285996Swnj 			laddr = inp->inp_laddr;
32911080Ssam 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
33011080Ssam 				error = EISCONN;
33111080Ssam 				break;
33211080Ssam 			}
33316799Skarels 			/*
33416799Skarels 			 * Must block input while temporarily connected.
33516799Skarels 			 */
33616799Skarels 			s = splnet();
3378273Sroot 			error = in_pcbconnect(inp, nam);
33816799Skarels 			if (error) {
33916799Skarels 				splx(s);
3406507Ssam 				break;
34116799Skarels 			}
3424955Swnj 		} else {
34311080Ssam 			if (inp->inp_faddr.s_addr == INADDR_ANY) {
34411080Ssam 				error = ENOTCONN;
34511080Ssam 				break;
34611080Ssam 			}
3474955Swnj 		}
3486507Ssam 		error = udp_output(inp, m);
34911080Ssam 		m = NULL;
3508273Sroot 		if (nam) {
3515166Swnj 			in_pcbdisconnect(inp);
35218368Skarels 			inp->inp_laddr = laddr;
35316799Skarels 			splx(s);
3545996Swnj 		}
3555996Swnj 		}
3564784Swnj 		break;
3574784Swnj 
3584784Swnj 	case PRU_ABORT:
35931750Skarels 		soisdisconnected(so);
3605166Swnj 		in_pcbdetach(inp);
3614784Swnj 		break;
3624784Swnj 
3636511Ssam 	case PRU_SOCKADDR:
3648273Sroot 		in_setsockaddr(inp, nam);
3656511Ssam 		break;
3666511Ssam 
36714124Ssam 	case PRU_PEERADDR:
36814124Ssam 		in_setpeeraddr(inp, nam);
36914124Ssam 		break;
37014124Ssam 
37116988Skarels 	case PRU_SENSE:
37216988Skarels 		/*
37316988Skarels 		 * stat: don't bother with a blocksize.
37416988Skarels 		 */
37516988Skarels 		return (0);
37616988Skarels 
37712205Ssam 	case PRU_SENDOOB:
37812205Ssam 	case PRU_FASTTIMO:
37912205Ssam 	case PRU_SLOWTIMO:
38012205Ssam 	case PRU_PROTORCV:
38112205Ssam 	case PRU_PROTOSEND:
38212205Ssam 		error =  EOPNOTSUPP;
38312205Ssam 		break;
38413118Ssam 
38516799Skarels 	case PRU_RCVD:
38616799Skarels 	case PRU_RCVOOB:
38716799Skarels 		return (EOPNOTSUPP);	/* do not free mbuf's */
38816799Skarels 
38913118Ssam 	default:
39013118Ssam 		panic("udp_usrreq");
3914805Swnj 	}
39211080Ssam release:
39311080Ssam 	if (m != NULL)
39411080Ssam 		m_freem(m);
3956507Ssam 	return (error);
3964784Swnj }
397