xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 4955)
1*4955Swnj /*	udp_usrreq.c	4.7	81/11/20	*/
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"
104805Swnj #include "../net/inet.h"
114887Swnj #include "../net/inet_pcb.h"
124805Swnj #include "../net/inet_systm.h"
134901Swnj #include "../net/ip.h"
144901Swnj #include "../net/ip_var.h"
154887Swnj #include "../net/udp.h"
164887Swnj #include "../net/udp_var.h"
174784Swnj 
184926Swnj /*
194926Swnj  * UDP protocol implementation.
204926Swnj  * Per RFC 768, August, 1980.
214926Swnj  */
224805Swnj udp_init()
234805Swnj {
244805Swnj 
254901Swnj 	udb.inp_next = udb.inp_prev = &udb;
264805Swnj }
274805Swnj 
284901Swnj int	udpcksum;
294926Swnj struct	sockaddr_in udp_in = { AF_INET };
304901Swnj 
314926Swnj udp_input(m0)
324926Swnj 	struct mbuf *m0;
334784Swnj {
344901Swnj 	register struct udpiphdr *ui;
354887Swnj 	register struct inpcb *inp;
364926Swnj 	register struct mbuf *m;
374926Swnj 	int len, ulen;
384784Swnj 
394926Swnj 	/*
404926Swnj 	 * Get ip and udp header together in first mbuf.
414926Swnj 	 */
424926Swnj 	m = m0;
434901Swnj 	ui = mtod(m, struct udpiphdr *);
444926Swnj 	if (ui->ui_len > sizeof (struct ip))
45*4955Swnj 		ip_stripoptions((struct ip *)ui, (char *)0);
464926Swnj 	if (m->m_len < sizeof (struct udpiphdr) &&
474926Swnj 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
484926Swnj 		udpstat.udps_hdrops++;
494926Swnj 		goto bad;
504926Swnj 	}
514926Swnj 
524926Swnj 	/*
534926Swnj 	 * Make mbuf data length reflect udp length.
544926Swnj 	 * If not enough data to reflect udp length, drop.
554926Swnj 	 */
56*4955Swnj 	ulen = ntohs((u_short)ui->ui_ulen);
574926Swnj 	len = sizeof (struct udpiphdr) + ulen;
584926Swnj 	if (((struct ip *)ui)->ip_len != len) {
594926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
604926Swnj 			udpstat.udps_badlen++;
614926Swnj 			goto bad;
624926Swnj 		}
634926Swnj 		m_adj(m, ((struct ip *)ui)->ip_len - len);
644926Swnj 		/* (struct ip *)ui->ip_len = len; */
654926Swnj 	}
664926Swnj 
674926Swnj 	/*
684926Swnj 	 * Checksum extended udp header and data.
694926Swnj 	 */
704901Swnj 	if (udpcksum) {
714926Swnj 		ui->ui_next = ui->ui_prev = 0;
724926Swnj 		ui->ui_x1 = 0;
73*4955Swnj 		ui->ui_len = htons((u_short)(sizeof (struct udpiphdr) + ulen));
744926Swnj 		if (ui->ui_sum = inet_cksum(m, len)) {
754926Swnj 			udpstat.udps_badsum++;
764901Swnj 			printf("udp cksum %x\n", ui->ui_sum);
774901Swnj 			m_freem(m);
784901Swnj 			return;
794901Swnj 		}
804901Swnj 	}
814926Swnj 
824926Swnj 	/*
834926Swnj 	 * Convert addresses and ports to host format.
844926Swnj 	 * Locate pcb for datagram.
854926Swnj 	 */
864926Swnj 	ui->ui_src.s_addr = ntohl(ui->ui_src.s_addr);
874926Swnj 	ui->ui_dst.s_addr = ntohl(ui->ui_dst.s_addr);
884926Swnj 	ui->ui_sport = ntohs(ui->ui_sport);
894926Swnj 	ui->ui_dport = ntohs(ui->ui_dport);
904926Swnj 	inp = in_pcblookup(&udb,
914926Swnj 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
924887Swnj 	if (inp == 0)
934926Swnj 		goto bad;
944926Swnj 
954926Swnj 	/*
964926Swnj 	 * Construct sockaddr format source address.
974926Swnj 	 * Stuff source address and datagram in user buffer.
984926Swnj 	 */
994926Swnj 	udp_in.sin_port = ui->ui_sport;
1004926Swnj 	udp_in.sin_addr = ui->ui_src;
101*4955Swnj 	if (sbappendaddr(&inp->inp_socket->so_snd, (struct sockaddr *)&udp_in, m) == 0)
1024926Swnj 		goto bad;
1034887Swnj 	return;
1044926Swnj bad:
1054887Swnj 	m_freem(m);
1064784Swnj }
1074784Swnj 
1084887Swnj udp_ctlinput(m)
1094887Swnj 	struct mbuf *m;
1104887Swnj {
1114887Swnj 
1124887Swnj 	m_freem(m);
1134887Swnj }
1144887Swnj 
1154926Swnj /*ARGSUSED*/
116*4955Swnj udp_output(inp, m0)
1174926Swnj 	struct inpcb *inp;
1184926Swnj 	struct mbuf *m0;
1194784Swnj {
1204926Swnj 	register struct mbuf *m;
1214926Swnj 	register struct udpiphdr *ui;
1224926Swnj 	register int len = 0;
1234784Swnj 
1244926Swnj 	/*
1254926Swnj 	 * Calculate data length and get a mbuf
1264926Swnj 	 * for udp and ip headers.
1274926Swnj 	 */
1284926Swnj 	for (m = m0; m; m = m->m_next)
1294926Swnj 		len += m->m_len;
1304926Swnj 	m = m_get(0);
1314926Swnj 	if (m == 0)
1324926Swnj 		goto bad;
1334784Swnj 
1344926Swnj 	/*
1354926Swnj 	 * Fill in mbuf with extended udp header
1364926Swnj 	 * and addresses and length put into network format.
1374926Swnj 	 */
1384926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
1394926Swnj 	m->m_len = sizeof (struct udpiphdr);
1404926Swnj 	m->m_next = m0;
1414926Swnj 	ui = mtod(m, struct udpiphdr *);
1424926Swnj 	ui->ui_next = ui->ui_prev = 0;
1434926Swnj 	ui->ui_x1 = 0;
1444926Swnj 	ui->ui_pr = IPPROTO_UDP;
145*4955Swnj 	ui->ui_len = htons((u_short)(sizeof (struct udphdr) + len));
146*4955Swnj 	ui->ui_src.s_addr = htonl(inp->inp_laddr.s_addr);
147*4955Swnj 	ui->ui_dst.s_addr = htonl(inp->inp_faddr.s_addr);
1484926Swnj 	ui->ui_sport = htons(inp->inp_lport);
1494926Swnj 	ui->ui_dport = htons(inp->inp_fport);
150*4955Swnj 	ui->ui_ulen = htons((u_short)len);
1514784Swnj 
1524926Swnj 	/*
1534926Swnj 	 * Stuff checksum and output datagram.
1544926Swnj 	 */
1554926Swnj 	ui->ui_sum = 0;
1564926Swnj 	ui->ui_sum = inet_cksum(m, sizeof (struct udpiphdr) + len);
1574887Swnj 	ip_output(m);
1584926Swnj 	return;
1594926Swnj bad:
1604926Swnj 	m_freem(m);
1614784Swnj }
1624784Swnj 
1634912Swnj /*ARGSUSED*/
1644887Swnj udp_usrreq(so, req, m, addr)
1654887Swnj 	struct socket *so;
1664784Swnj 	int req;
1674784Swnj 	struct mbuf *m;
1684912Swnj 	caddr_t addr;
1694784Swnj {
1704887Swnj 	struct inpcb *inp = sotoinpcb(so);
1714887Swnj 	int error;
1724784Swnj 
1734784Swnj 	switch (req) {
1744784Swnj 
1754784Swnj 	case PRU_ATTACH:
1764887Swnj 		if (inp != 0)
1774887Swnj 			return (EINVAL);
178*4955Swnj 		error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
179*4955Swnj 		if (error)
180*4955Swnj 			return (error);
1814887Swnj 		so->so_pcb = (caddr_t)inp;
1824887Swnj 		break;
1834784Swnj 
1844784Swnj 	case PRU_DETACH:
1854887Swnj 		if (inp == 0)
1864887Swnj 			return (ENOTCONN);
1874912Swnj 		in_pcbfree(inp);
1884887Swnj 		break;
1894784Swnj 
1904784Swnj 	case PRU_CONNECT:
191*4955Swnj 		if (inp->inp_faddr.s_addr)
1924887Swnj 			return (EISCONN);
193*4955Swnj 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
194*4955Swnj 		if (error)
1954887Swnj 			return (error);
1964887Swnj 		soisconnected(so);
1974887Swnj 		break;
1984784Swnj 
1994926Swnj 	case PRU_ACCEPT:
2004926Swnj 		return (EOPNOTSUPP);
2014926Swnj 
2024784Swnj 	case PRU_DISCONNECT:
203*4955Swnj 		if (inp->inp_faddr.s_addr == 0)
2044887Swnj 			return (ENOTCONN);
205*4955Swnj 		inp->inp_faddr.s_addr = 0;
2064887Swnj 		soisdisconnected(so);
2074784Swnj 		break;
2084784Swnj 
2094912Swnj 	case PRU_SHUTDOWN:
2104912Swnj 		socantsendmore(so);
2114912Swnj 		break;
2124912Swnj 
2134784Swnj 	case PRU_SEND:
2144887Swnj 		if (addr) {
215*4955Swnj 			if (inp->inp_faddr.s_addr)
2164887Swnj 				return (EISCONN);
217*4955Swnj 			error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
218*4955Swnj 			if (error)
219*4955Swnj 				return (error);
220*4955Swnj 		} else {
221*4955Swnj 			if (inp->inp_faddr.s_addr == 0)
222*4955Swnj 				return (ENOTCONN);
223*4955Swnj 		}
224*4955Swnj 		udp_output(inp, m);
225*4955Swnj 		if (addr)
226*4955Swnj 			inp->inp_faddr.s_addr = 0;
2274784Swnj 		break;
2284784Swnj 
2294784Swnj 	case PRU_ABORT:
2304887Swnj 		in_pcbfree(inp);
2314887Swnj 		sofree(so);
2324887Swnj 		soisdisconnected(so);
2334784Swnj 		break;
2344784Swnj 
2354784Swnj 	case PRU_CONTROL:
2364887Swnj 		return (EOPNOTSUPP);
2374784Swnj 
2384784Swnj 	default:
2394784Swnj 		panic("udp_usrreq");
2404805Swnj 	}
2414887Swnj 	return (0);
2424784Swnj }
2434805Swnj 
244*4955Swnj /*ARGSUSED*/
2454926Swnj udp_sense(m)
2464926Swnj 	struct mbuf *m;
2474805Swnj {
248*4955Swnj 
2494926Swnj 	return (EOPNOTSUPP);
2504805Swnj }
251