xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 26426)
123199Smckusick /*
223199Smckusick  * Copyright (c) 1982 Regents of the University of California.
323199Smckusick  * All rights reserved.  The Berkeley software License Agreement
423199Smckusick  * specifies the terms and conditions for redistribution.
523199Smckusick  *
6*26426Skarels  *	@(#)udp_usrreq.c	6.21 (Berkeley) 02/25/86
723199Smckusick  */
84784Swnj 
917065Sbloom #include "param.h"
1017065Sbloom #include "dir.h"
1117065Sbloom #include "user.h"
1217065Sbloom #include "mbuf.h"
1317065Sbloom #include "protosw.h"
1417065Sbloom #include "socket.h"
1517065Sbloom #include "socketvar.h"
1617065Sbloom #include "errno.h"
1717065Sbloom #include "stat.h"
1810897Ssam 
196584Ssam #include "../net/if.h"
206354Ssam #include "../net/route.h"
2110897Ssam 
2217065Sbloom #include "in.h"
2317065Sbloom #include "in_pcb.h"
2417065Sbloom #include "in_systm.h"
2517065Sbloom #include "ip.h"
2617065Sbloom #include "ip_var.h"
2717065Sbloom #include "ip_icmp.h"
2817065Sbloom #include "udp.h"
2917065Sbloom #include "udp_var.h"
304784Swnj 
314926Swnj /*
324926Swnj  * UDP protocol implementation.
334926Swnj  * Per RFC 768, August, 1980.
344926Swnj  */
354805Swnj udp_init()
364805Swnj {
374805Swnj 
384901Swnj 	udb.inp_next = udb.inp_prev = &udb;
394805Swnj }
404805Swnj 
4126118Skarels #ifndef	COMPAT_42
4219519Skarels int	udpcksum = 1;
4326118Skarels #else
4426118Skarels int	udpcksum = 0;		/* XXX */
4526118Skarels #endif
4626118Skarels 
474926Swnj struct	sockaddr_in udp_in = { AF_INET };
484901Swnj 
4926032Skarels udp_input(m0, ifp)
504926Swnj 	struct mbuf *m0;
5126032Skarels 	struct ifnet *ifp;
524784Swnj {
534901Swnj 	register struct udpiphdr *ui;
544887Swnj 	register struct inpcb *inp;
554926Swnj 	register struct mbuf *m;
567844Sroot 	int len;
5724823Skarels 	struct ip ip;
584784Swnj 
594926Swnj 	/*
605246Sroot 	 * Get IP and UDP header together in first mbuf.
614926Swnj 	 */
624926Swnj 	m = m0;
635308Sroot 	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
645308Sroot 	    (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
654926Swnj 		udpstat.udps_hdrops++;
665308Sroot 		return;
674926Swnj 	}
685050Swnj 	ui = mtod(m, struct udpiphdr *);
695246Sroot 	if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
705220Swnj 		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
714926Swnj 
724926Swnj 	/*
735246Sroot 	 * Make mbuf data length reflect UDP length.
745246Sroot 	 * If not enough data to reflect UDP length, drop.
754926Swnj 	 */
767844Sroot 	len = ntohs((u_short)ui->ui_ulen);
774926Swnj 	if (((struct ip *)ui)->ip_len != len) {
784926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
794926Swnj 			udpstat.udps_badlen++;
804926Swnj 			goto bad;
814926Swnj 		}
8215539Skarels 		m_adj(m, len - ((struct ip *)ui)->ip_len);
8324823Skarels 		/* ((struct ip *)ui)->ip_len = len; */
844926Swnj 	}
8524823Skarels 	/*
8624823Skarels 	 * Save a copy of the IP header in case we want restore it for ICMP.
8724823Skarels 	 */
8824823Skarels 	ip = *(struct ip*)ui;
894926Swnj 
904926Swnj 	/*
915246Sroot 	 * Checksum extended UDP header and data.
924926Swnj 	 */
9315539Skarels 	if (udpcksum && ui->ui_sum) {
944926Swnj 		ui->ui_next = ui->ui_prev = 0;
954926Swnj 		ui->ui_x1 = 0;
9621112Skarels 		ui->ui_len = ui->ui_ulen;
977844Sroot 		if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
984926Swnj 			udpstat.udps_badsum++;
994901Swnj 			m_freem(m);
1004901Swnj 			return;
1014901Swnj 		}
1024901Swnj 	}
1034926Swnj 
1044926Swnj 	/*
1057844Sroot 	 * Locate pcb for datagram.
1064926Swnj 	 */
1074926Swnj 	inp = in_pcblookup(&udb,
1086029Sroot 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
1096029Sroot 		INPLOOKUP_WILDCARD);
1106584Ssam 	if (inp == 0) {
11110144Ssam 		/* don't send ICMP response for broadcast packet */
11221112Skarels 		if (in_broadcast(ui->ui_dst))
1136584Ssam 			goto bad;
11424823Skarels 		*(struct ip *)ui = ip;
11526032Skarels 		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,
11626032Skarels 		    ifp);
1176584Ssam 		return;
1186584Ssam 	}
1196584Ssam 
1204926Swnj 	/*
1214926Swnj 	 * Construct sockaddr format source address.
1224926Swnj 	 * Stuff source address and datagram in user buffer.
1234926Swnj 	 */
1244926Swnj 	udp_in.sin_port = ui->ui_sport;
1254926Swnj 	udp_in.sin_addr = ui->ui_src;
1265050Swnj 	m->m_len -= sizeof (struct udpiphdr);
1275050Swnj 	m->m_off += sizeof (struct udpiphdr);
12812767Ssam 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
12912767Ssam 	    m, (struct mbuf *)0) == 0)
1304926Swnj 		goto bad;
1315050Swnj 	sorwakeup(inp->inp_socket);
1324887Swnj 	return;
1334926Swnj bad:
1344887Swnj 	m_freem(m);
1354784Swnj }
1364784Swnj 
137*26426Skarels /*
138*26426Skarels  * Notify a udp user of an asynchronous error;
139*26426Skarels  * just wake up so that he can collect error status.
140*26426Skarels  */
141*26426Skarels udp_notify(inp)
142*26426Skarels 	register struct inpcb *inp;
143*26426Skarels {
144*26426Skarels 
145*26426Skarels 	sorwakeup(inp->inp_socket);
146*26426Skarels 	sowwakeup(inp->inp_socket);
147*26426Skarels }
148*26426Skarels 
14924823Skarels udp_ctlinput(cmd, sa)
1506591Ssam 	int cmd;
15124823Skarels 	struct sockaddr *sa;
1526591Ssam {
1536591Ssam 	extern u_char inetctlerrmap[];
15424823Skarels 	struct sockaddr_in *sin;
15521121Skarels 	int in_rtchange();
1566591Ssam 
15724823Skarels 	if ((unsigned)cmd > PRC_NCMDS)
1586591Ssam 		return;
15924823Skarels 	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
16024823Skarels 		return;
16124823Skarels 	sin = (struct sockaddr_in *)sa;
16224823Skarels 	if (sin->sin_addr.s_addr == INADDR_ANY)
16324823Skarels 		return;
16424823Skarels 
1656591Ssam 	switch (cmd) {
1666591Ssam 
16724823Skarels 	case PRC_QUENCH:
1686591Ssam 		break;
1696591Ssam 
17024823Skarels 	case PRC_ROUTEDEAD:
17121121Skarels 	case PRC_REDIRECT_NET:
17221121Skarels 	case PRC_REDIRECT_HOST:
17324823Skarels 	case PRC_REDIRECT_TOSNET:
17424823Skarels 	case PRC_REDIRECT_TOSHOST:
17524823Skarels 		in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange);
1766591Ssam 		break;
1776591Ssam 
1786591Ssam 	default:
17921121Skarels 		if (inetctlerrmap[cmd] == 0)
18021121Skarels 			return;		/* XXX */
18124823Skarels 		in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd],
182*26426Skarels 			udp_notify);
1836591Ssam 	}
1846591Ssam }
1856591Ssam 
1864955Swnj udp_output(inp, m0)
18726060Skarels 	register struct inpcb *inp;
1884926Swnj 	struct mbuf *m0;
1894784Swnj {
1904926Swnj 	register struct mbuf *m;
1914926Swnj 	register struct udpiphdr *ui;
19217165Skarels 	register int len = 0;
1934784Swnj 
1944926Swnj 	/*
1954926Swnj 	 * Calculate data length and get a mbuf
1965246Sroot 	 * for UDP and IP headers.
1974926Swnj 	 */
1984926Swnj 	for (m = m0; m; m = m->m_next)
1994926Swnj 		len += m->m_len;
20021112Skarels 	MGET(m, M_DONTWAIT, MT_HEADER);
2016507Ssam 	if (m == 0) {
2026507Ssam 		m_freem(m0);
2036507Ssam 		return (ENOBUFS);
2046507Ssam 	}
2054784Swnj 
2064926Swnj 	/*
2075246Sroot 	 * Fill in mbuf with extended UDP header
2084926Swnj 	 * and addresses and length put into network format.
2094926Swnj 	 */
2104926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
2114926Swnj 	m->m_len = sizeof (struct udpiphdr);
2124926Swnj 	m->m_next = m0;
2134926Swnj 	ui = mtod(m, struct udpiphdr *);
2144926Swnj 	ui->ui_next = ui->ui_prev = 0;
2154926Swnj 	ui->ui_x1 = 0;
2164926Swnj 	ui->ui_pr = IPPROTO_UDP;
21715226Ssam 	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
2185050Swnj 	ui->ui_src = inp->inp_laddr;
2195050Swnj 	ui->ui_dst = inp->inp_faddr;
2205050Swnj 	ui->ui_sport = inp->inp_lport;
2215050Swnj 	ui->ui_dport = inp->inp_fport;
22215226Ssam 	ui->ui_ulen = ui->ui_len;
2234784Swnj 
2244926Swnj 	/*
2254926Swnj 	 * Stuff checksum and output datagram.
2264926Swnj 	 */
2274926Swnj 	ui->ui_sum = 0;
22819519Skarels 	if (udpcksum) {
22919519Skarels 	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
23015539Skarels 		ui->ui_sum = -1;
23121112Skarels 	}
2325050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
23326086Skarels 	((struct ip *)ui)->ip_ttl = UDP_TTL;
23426060Skarels 	return (ip_output(m, inp->inp_options, &inp->inp_route,
23526060Skarels 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
2364784Swnj }
2374784Swnj 
23818368Skarels int	udp_sendspace = 2048;		/* really max datagram size */
23918368Skarels int	udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */
24018368Skarels 
2418602Sroot /*ARGSUSED*/
24212767Ssam udp_usrreq(so, req, m, nam, rights)
2434887Swnj 	struct socket *so;
2444784Swnj 	int req;
24512767Ssam 	struct mbuf *m, *nam, *rights;
2464784Swnj {
2474887Swnj 	struct inpcb *inp = sotoinpcb(so);
2486507Ssam 	int error = 0;
2494784Swnj 
25018368Skarels 	if (req == PRU_CONTROL)
25118368Skarels 		return (in_control(so, (int)m, (caddr_t)nam,
25218368Skarels 			(struct ifnet *)rights));
25312767Ssam 	if (rights && rights->m_len) {
25412767Ssam 		error = EINVAL;
25512767Ssam 		goto release;
25612767Ssam 	}
25711080Ssam 	if (inp == NULL && req != PRU_ATTACH) {
25811080Ssam 		error = EINVAL;
25911080Ssam 		goto release;
26011080Ssam 	}
2614784Swnj 	switch (req) {
2624784Swnj 
2634784Swnj 	case PRU_ATTACH:
26411080Ssam 		if (inp != NULL) {
26511080Ssam 			error = EINVAL;
26611080Ssam 			break;
26711080Ssam 		}
2688273Sroot 		error = in_pcballoc(so, &udb);
2698273Sroot 		if (error)
2708273Sroot 			break;
27118368Skarels 		error = soreserve(so, udp_sendspace, udp_recvspace);
2728273Sroot 		if (error)
2738273Sroot 			break;
2744887Swnj 		break;
2754784Swnj 
2764784Swnj 	case PRU_DETACH:
2775166Swnj 		in_pcbdetach(inp);
2784887Swnj 		break;
2794784Swnj 
2808273Sroot 	case PRU_BIND:
2818273Sroot 		error = in_pcbbind(inp, nam);
2828273Sroot 		break;
2838273Sroot 
2848273Sroot 	case PRU_LISTEN:
2858273Sroot 		error = EOPNOTSUPP;
2868273Sroot 		break;
2878273Sroot 
2884784Swnj 	case PRU_CONNECT:
28911080Ssam 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
29011080Ssam 			error = EISCONN;
29111080Ssam 			break;
29211080Ssam 		}
2938273Sroot 		error = in_pcbconnect(inp, nam);
2946507Ssam 		if (error == 0)
2956507Ssam 			soisconnected(so);
2964887Swnj 		break;
2974784Swnj 
29813118Ssam 	case PRU_CONNECT2:
29913118Ssam 		error = EOPNOTSUPP;
30013118Ssam 		break;
30113118Ssam 
3024926Swnj 	case PRU_ACCEPT:
30311080Ssam 		error = EOPNOTSUPP;
30411080Ssam 		break;
3054926Swnj 
3064784Swnj 	case PRU_DISCONNECT:
30711080Ssam 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
30811080Ssam 			error = ENOTCONN;
30911080Ssam 			break;
31011080Ssam 		}
3115166Swnj 		in_pcbdisconnect(inp);
31226404Skarels 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
3134784Swnj 		break;
3144784Swnj 
3154912Swnj 	case PRU_SHUTDOWN:
3164912Swnj 		socantsendmore(so);
3174912Swnj 		break;
3184912Swnj 
3195996Swnj 	case PRU_SEND: {
3205996Swnj 		struct in_addr laddr;
32116799Skarels 		int s;
3225996Swnj 
3238273Sroot 		if (nam) {
3245996Swnj 			laddr = inp->inp_laddr;
32511080Ssam 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
32611080Ssam 				error = EISCONN;
32711080Ssam 				break;
32811080Ssam 			}
32916799Skarels 			/*
33016799Skarels 			 * Must block input while temporarily connected.
33116799Skarels 			 */
33216799Skarels 			s = splnet();
3338273Sroot 			error = in_pcbconnect(inp, nam);
33416799Skarels 			if (error) {
33516799Skarels 				splx(s);
3366507Ssam 				break;
33716799Skarels 			}
3384955Swnj 		} else {
33911080Ssam 			if (inp->inp_faddr.s_addr == INADDR_ANY) {
34011080Ssam 				error = ENOTCONN;
34111080Ssam 				break;
34211080Ssam 			}
3434955Swnj 		}
3446507Ssam 		error = udp_output(inp, m);
34511080Ssam 		m = NULL;
3468273Sroot 		if (nam) {
3475166Swnj 			in_pcbdisconnect(inp);
34818368Skarels 			inp->inp_laddr = laddr;
34916799Skarels 			splx(s);
3505996Swnj 		}
3515996Swnj 		}
3524784Swnj 		break;
3534784Swnj 
3544784Swnj 	case PRU_ABORT:
3555166Swnj 		in_pcbdetach(inp);
3564887Swnj 		sofree(so);
3574887Swnj 		soisdisconnected(so);
3584784Swnj 		break;
3594784Swnj 
3606511Ssam 	case PRU_SOCKADDR:
3618273Sroot 		in_setsockaddr(inp, nam);
3626511Ssam 		break;
3636511Ssam 
36414124Ssam 	case PRU_PEERADDR:
36514124Ssam 		in_setpeeraddr(inp, nam);
36614124Ssam 		break;
36714124Ssam 
36816988Skarels 	case PRU_SENSE:
36916988Skarels 		/*
37016988Skarels 		 * stat: don't bother with a blocksize.
37116988Skarels 		 */
37216988Skarels 		return (0);
37316988Skarels 
37412205Ssam 	case PRU_SENDOOB:
37512205Ssam 	case PRU_FASTTIMO:
37612205Ssam 	case PRU_SLOWTIMO:
37712205Ssam 	case PRU_PROTORCV:
37812205Ssam 	case PRU_PROTOSEND:
37912205Ssam 		error =  EOPNOTSUPP;
38012205Ssam 		break;
38113118Ssam 
38216799Skarels 	case PRU_RCVD:
38316799Skarels 	case PRU_RCVOOB:
38416799Skarels 		return (EOPNOTSUPP);	/* do not free mbuf's */
38516799Skarels 
38613118Ssam 	default:
38713118Ssam 		panic("udp_usrreq");
3884805Swnj 	}
38911080Ssam release:
39011080Ssam 	if (m != NULL)
39111080Ssam 		m_freem(m);
3926507Ssam 	return (error);
3934784Swnj }
394