xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 6511)
1*6511Ssam /*	udp_usrreq.c	4.26	82/04/10	*/
24784Swnj 
34784Swnj #include "../h/param.h"
44887Swnj #include "../h/dir.h"
54887Swnj #include "../h/user.h"
64784Swnj #include "../h/mbuf.h"
74805Swnj #include "../h/protosw.h"
84887Swnj #include "../h/socket.h"
94887Swnj #include "../h/socketvar.h"
105094Swnj #include "../net/in.h"
116354Ssam #include "../net/route.h"
125094Swnj #include "../net/in_pcb.h"
135094Swnj #include "../net/in_systm.h"
144901Swnj #include "../net/ip.h"
154901Swnj #include "../net/ip_var.h"
164887Swnj #include "../net/udp.h"
174887Swnj #include "../net/udp_var.h"
186507Ssam #include <errno.h>
194784Swnj 
204926Swnj /*
214926Swnj  * UDP protocol implementation.
224926Swnj  * Per RFC 768, August, 1980.
234926Swnj  */
244805Swnj udp_init()
254805Swnj {
264805Swnj 
275094Swnj COUNT(UDP_INIT);
284901Swnj 	udb.inp_next = udb.inp_prev = &udb;
294805Swnj }
304805Swnj 
314901Swnj int	udpcksum;
324926Swnj struct	sockaddr_in udp_in = { AF_INET };
334901Swnj 
344926Swnj udp_input(m0)
354926Swnj 	struct mbuf *m0;
364784Swnj {
374901Swnj 	register struct udpiphdr *ui;
384887Swnj 	register struct inpcb *inp;
394926Swnj 	register struct mbuf *m;
404926Swnj 	int len, ulen;
414784Swnj 
425094Swnj COUNT(UDP_INPUT);
434926Swnj 	/*
445246Sroot 	 * Get IP and UDP header together in first mbuf.
454926Swnj 	 */
464926Swnj 	m = m0;
475308Sroot 	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
485308Sroot 	    (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
494926Swnj 		udpstat.udps_hdrops++;
505308Sroot 		return;
514926Swnj 	}
525050Swnj 	ui = mtod(m, struct udpiphdr *);
535246Sroot 	if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
545220Swnj 		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
554926Swnj 
564926Swnj 	/*
575246Sroot 	 * Make mbuf data length reflect UDP length.
585246Sroot 	 * If not enough data to reflect UDP length, drop.
594926Swnj 	 */
604955Swnj 	ulen = ntohs((u_short)ui->ui_ulen);
615220Swnj 	len = sizeof (struct udphdr) + ulen;
624926Swnj 	if (((struct ip *)ui)->ip_len != len) {
634926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
644926Swnj 			udpstat.udps_badlen++;
654926Swnj 			goto bad;
664926Swnj 		}
674926Swnj 		m_adj(m, ((struct ip *)ui)->ip_len - len);
684926Swnj 		/* (struct ip *)ui->ip_len = len; */
694926Swnj 	}
704926Swnj 
714926Swnj 	/*
725246Sroot 	 * Checksum extended UDP header and data.
734926Swnj 	 */
744901Swnj 	if (udpcksum) {
754926Swnj 		ui->ui_next = ui->ui_prev = 0;
764926Swnj 		ui->ui_x1 = 0;
775220Swnj 		ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen));
785220Swnj 		if (ui->ui_sum = in_cksum(m, len)) {
794926Swnj 			udpstat.udps_badsum++;
804901Swnj 			printf("udp cksum %x\n", ui->ui_sum);
814901Swnj 			m_freem(m);
824901Swnj 			return;
834901Swnj 		}
844901Swnj 	}
854926Swnj 
864926Swnj 	/*
875996Swnj 	 * Locate pcb for datagram.  On wildcard match, update
885996Swnj 	 * control block to anchor network and host address.
894926Swnj 	 */
904926Swnj 	inp = in_pcblookup(&udb,
916029Sroot 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
926029Sroot 		INPLOOKUP_WILDCARD);
935051Swnj 	if (inp == 0)
944926Swnj 		goto bad;
954926Swnj 
964926Swnj 	/*
974926Swnj 	 * Construct sockaddr format source address.
984926Swnj 	 * Stuff source address and datagram in user buffer.
994926Swnj 	 */
1004926Swnj 	udp_in.sin_port = ui->ui_sport;
1014926Swnj 	udp_in.sin_addr = ui->ui_src;
1025050Swnj 	m->m_len -= sizeof (struct udpiphdr);
1035050Swnj 	m->m_off += sizeof (struct udpiphdr);
1045050Swnj 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
1054926Swnj 		goto bad;
1065050Swnj 	sorwakeup(inp->inp_socket);
1074887Swnj 	return;
1084926Swnj bad:
1094887Swnj 	m_freem(m);
1104784Swnj }
1114784Swnj 
1124887Swnj udp_ctlinput(m)
1134887Swnj 	struct mbuf *m;
1144887Swnj {
1154887Swnj 
1165094Swnj COUNT(UDP_CTLINPUT);
1174887Swnj 	m_freem(m);
1184887Swnj }
1194887Swnj 
1204955Swnj udp_output(inp, m0)
1214926Swnj 	struct inpcb *inp;
1224926Swnj 	struct mbuf *m0;
1234784Swnj {
1244926Swnj 	register struct mbuf *m;
1254926Swnj 	register struct udpiphdr *ui;
1264926Swnj 	register int len = 0;
1274784Swnj 
1285094Swnj COUNT(UDP_OUTPUT);
1294926Swnj 	/*
1304926Swnj 	 * Calculate data length and get a mbuf
1315246Sroot 	 * for UDP and IP headers.
1324926Swnj 	 */
1334926Swnj 	for (m = m0; m; m = m->m_next)
1344926Swnj 		len += m->m_len;
1355585Sroot 	m = m_get(M_DONTWAIT);
1366507Ssam 	if (m == 0) {
1376507Ssam 		m_freem(m0);
1386507Ssam 		return (ENOBUFS);
1396507Ssam 	}
1404784Swnj 
1414926Swnj 	/*
1425246Sroot 	 * Fill in mbuf with extended UDP header
1434926Swnj 	 * and addresses and length put into network format.
1444926Swnj 	 */
1454926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
1464926Swnj 	m->m_len = sizeof (struct udpiphdr);
1474926Swnj 	m->m_next = m0;
1484926Swnj 	ui = mtod(m, struct udpiphdr *);
1494926Swnj 	ui->ui_next = ui->ui_prev = 0;
1504926Swnj 	ui->ui_x1 = 0;
1514926Swnj 	ui->ui_pr = IPPROTO_UDP;
1525050Swnj 	ui->ui_len = sizeof (struct udpiphdr) + len;
1535050Swnj 	ui->ui_src = inp->inp_laddr;
1545050Swnj 	ui->ui_dst = inp->inp_faddr;
1555050Swnj 	ui->ui_sport = inp->inp_lport;
1565050Swnj 	ui->ui_dport = inp->inp_fport;
1574955Swnj 	ui->ui_ulen = htons((u_short)len);
1584784Swnj 
1594926Swnj 	/*
1604926Swnj 	 * Stuff checksum and output datagram.
1614926Swnj 	 */
1624926Swnj 	ui->ui_sum = 0;
1635094Swnj 	ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
1645050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1655050Swnj 	((struct ip *)ui)->ip_ttl = MAXTTL;
1666507Ssam 	return (ip_output(m, (struct mbuf *)0, 0,
1676507Ssam 	    inp->inp_socket->so_state & SS_PRIV));
1684784Swnj }
1694784Swnj 
1704887Swnj udp_usrreq(so, req, m, addr)
1714887Swnj 	struct socket *so;
1724784Swnj 	int req;
1734784Swnj 	struct mbuf *m;
1744912Swnj 	caddr_t addr;
1754784Swnj {
1764887Swnj 	struct inpcb *inp = sotoinpcb(so);
1776507Ssam 	int error = 0;
1784784Swnj 
1795094Swnj COUNT(UDP_USRREQ);
1805051Swnj 	if (inp == 0 && req != PRU_ATTACH)
1815050Swnj 		return (EINVAL);
1824784Swnj 	switch (req) {
1834784Swnj 
1844784Swnj 	case PRU_ATTACH:
1854887Swnj 		if (inp != 0)
1864887Swnj 			return (EINVAL);
1876507Ssam 		error = in_pcbattach(so, &udb, 2048, 2048,
1886507Ssam 				(struct sockaddr_in *)addr);
1894887Swnj 		break;
1904784Swnj 
1914784Swnj 	case PRU_DETACH:
1924887Swnj 		if (inp == 0)
1934887Swnj 			return (ENOTCONN);
1945166Swnj 		in_pcbdetach(inp);
1954887Swnj 		break;
1964784Swnj 
1974784Swnj 	case PRU_CONNECT:
1984955Swnj 		if (inp->inp_faddr.s_addr)
1994887Swnj 			return (EISCONN);
2005166Swnj 		error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
2016507Ssam 		if (error == 0)
2026507Ssam 			soisconnected(so);
2034887Swnj 		break;
2044784Swnj 
2054926Swnj 	case PRU_ACCEPT:
2064926Swnj 		return (EOPNOTSUPP);
2074926Swnj 
2084784Swnj 	case PRU_DISCONNECT:
2094955Swnj 		if (inp->inp_faddr.s_addr == 0)
2104887Swnj 			return (ENOTCONN);
2115166Swnj 		in_pcbdisconnect(inp);
2124887Swnj 		soisdisconnected(so);
2134784Swnj 		break;
2144784Swnj 
2154912Swnj 	case PRU_SHUTDOWN:
2164912Swnj 		socantsendmore(so);
2174912Swnj 		break;
2184912Swnj 
2195996Swnj 	case PRU_SEND: {
2205996Swnj 		struct in_addr laddr;
2215996Swnj 
2224887Swnj 		if (addr) {
2235996Swnj 			laddr = inp->inp_laddr;
2245224Swnj 			if (inp->inp_faddr.s_addr)
2254887Swnj 				return (EISCONN);
2265166Swnj 			error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
2275224Swnj 			if (error)
2286507Ssam 				break;
2294955Swnj 		} else {
2304955Swnj 			if (inp->inp_faddr.s_addr == 0)
2314955Swnj 				return (ENOTCONN);
2324955Swnj 		}
2336507Ssam 		error = udp_output(inp, m);
2345996Swnj 		if (addr) {
2355166Swnj 			in_pcbdisconnect(inp);
2365996Swnj 			inp->inp_laddr = laddr;
2375996Swnj 		}
2385996Swnj 		}
2394784Swnj 		break;
2404784Swnj 
2414784Swnj 	case PRU_ABORT:
2425166Swnj 		in_pcbdetach(inp);
2434887Swnj 		sofree(so);
2444887Swnj 		soisdisconnected(so);
2454784Swnj 		break;
2464784Swnj 
2474784Swnj 	case PRU_CONTROL:
2484887Swnj 		return (EOPNOTSUPP);
2494784Swnj 
250*6511Ssam 	case PRU_SOCKADDR:
251*6511Ssam 		in_setsockaddr((struct sockaddr_in *)addr, inp);
252*6511Ssam 		break;
253*6511Ssam 
2544784Swnj 	default:
2554784Swnj 		panic("udp_usrreq");
2564805Swnj 	}
2576507Ssam 	return (error);
2584784Swnj }
259