xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 5051)
1*5051Swnj /*	udp_usrreq.c	4.9	81/11/23	*/
24784Swnj 
34784Swnj #include "../h/param.h"
44887Swnj #include "../h/dir.h"
54887Swnj #include "../h/user.h"
64784Swnj #include "../h/mbuf.h"
75050Swnj #define	PRUREQUESTS
84805Swnj #include "../h/protosw.h"
94887Swnj #include "../h/socket.h"
104887Swnj #include "../h/socketvar.h"
114805Swnj #include "../net/inet.h"
124887Swnj #include "../net/inet_pcb.h"
134805Swnj #include "../net/inet_systm.h"
144901Swnj #include "../net/ip.h"
154901Swnj #include "../net/ip_var.h"
164887Swnj #include "../net/udp.h"
174887Swnj #include "../net/udp_var.h"
184784Swnj 
194926Swnj /*
204926Swnj  * UDP protocol implementation.
214926Swnj  * Per RFC 768, August, 1980.
224926Swnj  */
234805Swnj udp_init()
244805Swnj {
254805Swnj 
264901Swnj 	udb.inp_next = udb.inp_prev = &udb;
274805Swnj }
284805Swnj 
294901Swnj int	udpcksum;
304926Swnj struct	sockaddr_in udp_in = { AF_INET };
314901Swnj 
324926Swnj udp_input(m0)
334926Swnj 	struct mbuf *m0;
344784Swnj {
354901Swnj 	register struct udpiphdr *ui;
364887Swnj 	register struct inpcb *inp;
374926Swnj 	register struct mbuf *m;
384926Swnj 	int len, ulen;
394784Swnj 
404926Swnj 	/*
414926Swnj 	 * Get ip and udp header together in first mbuf.
424926Swnj 	 */
434926Swnj 	m = m0;
444926Swnj 	if (m->m_len < sizeof (struct udpiphdr) &&
454926Swnj 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
464926Swnj 		udpstat.udps_hdrops++;
474926Swnj 		goto bad;
484926Swnj 	}
495050Swnj 	ui = mtod(m, struct udpiphdr *);
505050Swnj 	if (ui->ui_len > sizeof (struct ip))
515050Swnj 		ip_stripoptions((struct ip *)ui, (char *)0);
524926Swnj 
534926Swnj 	/*
544926Swnj 	 * Make mbuf data length reflect udp length.
554926Swnj 	 * If not enough data to reflect udp length, drop.
564926Swnj 	 */
574955Swnj 	ulen = ntohs((u_short)ui->ui_ulen);
584926Swnj 	len = sizeof (struct udpiphdr) + ulen;
594926Swnj 	if (((struct ip *)ui)->ip_len != len) {
604926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
614926Swnj 			udpstat.udps_badlen++;
624926Swnj 			goto bad;
634926Swnj 		}
644926Swnj 		m_adj(m, ((struct ip *)ui)->ip_len - len);
654926Swnj 		/* (struct ip *)ui->ip_len = len; */
664926Swnj 	}
674926Swnj 
684926Swnj 	/*
694926Swnj 	 * Checksum extended udp header and data.
704926Swnj 	 */
714901Swnj 	if (udpcksum) {
724926Swnj 		ui->ui_next = ui->ui_prev = 0;
734926Swnj 		ui->ui_x1 = 0;
744955Swnj 		ui->ui_len = htons((u_short)(sizeof (struct udpiphdr) + ulen));
755050Swnj 		if ((ui->ui_sum = inet_cksum(m, len)) != 0xffff) {
764926Swnj 			udpstat.udps_badsum++;
774901Swnj 			printf("udp cksum %x\n", ui->ui_sum);
784901Swnj 			m_freem(m);
794901Swnj 			return;
804901Swnj 		}
814901Swnj 	}
824926Swnj 
834926Swnj 	/*
844926Swnj 	 * Convert addresses and ports to host format.
854926Swnj 	 * Locate pcb for datagram.
864926Swnj 	 */
874926Swnj 	inp = in_pcblookup(&udb,
884926Swnj 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
89*5051Swnj 	if (inp == 0)
904926Swnj 		goto bad;
914926Swnj 
924926Swnj 	/*
934926Swnj 	 * Construct sockaddr format source address.
944926Swnj 	 * Stuff source address and datagram in user buffer.
954926Swnj 	 */
964926Swnj 	udp_in.sin_port = ui->ui_sport;
974926Swnj 	udp_in.sin_addr = ui->ui_src;
985050Swnj 	m->m_len -= sizeof (struct udpiphdr);
995050Swnj 	m->m_off += sizeof (struct udpiphdr);
1005050Swnj 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
1014926Swnj 		goto bad;
1025050Swnj 	sorwakeup(inp->inp_socket);
1034887Swnj 	return;
1044926Swnj bad:
1054887Swnj 	m_freem(m);
1064784Swnj }
1074784Swnj 
1084887Swnj udp_ctlinput(m)
1094887Swnj 	struct mbuf *m;
1104887Swnj {
1114887Swnj 
1125050Swnj 	printf("udp_ctlinput\n");
1134887Swnj 	m_freem(m);
1144887Swnj }
1154887Swnj 
1164926Swnj /*ARGSUSED*/
1174955Swnj udp_output(inp, m0)
1184926Swnj 	struct inpcb *inp;
1194926Swnj 	struct mbuf *m0;
1204784Swnj {
1214926Swnj 	register struct mbuf *m;
1224926Swnj 	register struct udpiphdr *ui;
1234926Swnj 	register int len = 0;
1244784Swnj 
1254926Swnj 	/*
1264926Swnj 	 * Calculate data length and get a mbuf
1274926Swnj 	 * for udp and ip headers.
1284926Swnj 	 */
1294926Swnj 	for (m = m0; m; m = m->m_next)
1304926Swnj 		len += m->m_len;
1314926Swnj 	m = m_get(0);
132*5051Swnj 	if (m == 0)
1334926Swnj 		goto bad;
1344784Swnj 
1354926Swnj 	/*
1364926Swnj 	 * Fill in mbuf with extended udp header
1374926Swnj 	 * and addresses and length put into network format.
1384926Swnj 	 */
1394926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
1404926Swnj 	m->m_len = sizeof (struct udpiphdr);
1414926Swnj 	m->m_next = m0;
1424926Swnj 	ui = mtod(m, struct udpiphdr *);
1434926Swnj 	ui->ui_next = ui->ui_prev = 0;
1444926Swnj 	ui->ui_x1 = 0;
1454926Swnj 	ui->ui_pr = IPPROTO_UDP;
1465050Swnj 	ui->ui_len = sizeof (struct udpiphdr) + len;
1475050Swnj 	ui->ui_src = inp->inp_laddr;
1485050Swnj 	ui->ui_dst = inp->inp_faddr;
1495050Swnj 	ui->ui_sport = inp->inp_lport;
1505050Swnj 	ui->ui_dport = inp->inp_fport;
1514955Swnj 	ui->ui_ulen = htons((u_short)len);
1524784Swnj 
1534926Swnj 	/*
1544926Swnj 	 * Stuff checksum and output datagram.
1554926Swnj 	 */
1564926Swnj 	ui->ui_sum = 0;
1574926Swnj 	ui->ui_sum = inet_cksum(m, sizeof (struct udpiphdr) + len);
1585050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1595050Swnj 	((struct ip *)ui)->ip_ttl = MAXTTL;
1604887Swnj 	ip_output(m);
1614926Swnj 	return;
1624926Swnj bad:
1634926Swnj 	m_freem(m);
1644784Swnj }
1654784Swnj 
1664912Swnj /*ARGSUSED*/
1674887Swnj udp_usrreq(so, req, m, addr)
1684887Swnj 	struct socket *so;
1694784Swnj 	int req;
1704784Swnj 	struct mbuf *m;
1714912Swnj 	caddr_t addr;
1724784Swnj {
1734887Swnj 	struct inpcb *inp = sotoinpcb(so);
1744887Swnj 	int error;
1754784Swnj 
176*5051Swnj 	if (inp == 0 && req != PRU_ATTACH)
1775050Swnj 		return (EINVAL);
1784784Swnj 	switch (req) {
1794784Swnj 
1804784Swnj 	case PRU_ATTACH:
1814887Swnj 		if (inp != 0)
1824887Swnj 			return (EINVAL);
1834955Swnj 		error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
184*5051Swnj 		if (error)
1854955Swnj 			return (error);
1864887Swnj 		break;
1874784Swnj 
1884784Swnj 	case PRU_DETACH:
1894887Swnj 		if (inp == 0)
1904887Swnj 			return (ENOTCONN);
1914912Swnj 		in_pcbfree(inp);
1924887Swnj 		break;
1934784Swnj 
1944784Swnj 	case PRU_CONNECT:
1954955Swnj 		if (inp->inp_faddr.s_addr)
1964887Swnj 			return (EISCONN);
1974955Swnj 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
198*5051Swnj 		if (error)
1994887Swnj 			return (error);
2004887Swnj 		soisconnected(so);
2014887Swnj 		break;
2024784Swnj 
2034926Swnj 	case PRU_ACCEPT:
2044926Swnj 		return (EOPNOTSUPP);
2054926Swnj 
2064784Swnj 	case PRU_DISCONNECT:
2074955Swnj 		if (inp->inp_faddr.s_addr == 0)
2084887Swnj 			return (ENOTCONN);
2094955Swnj 		inp->inp_faddr.s_addr = 0;
2104887Swnj 		soisdisconnected(so);
2114784Swnj 		break;
2124784Swnj 
2134912Swnj 	case PRU_SHUTDOWN:
2144912Swnj 		socantsendmore(so);
2154912Swnj 		break;
2164912Swnj 
2174784Swnj 	case PRU_SEND:
2184887Swnj 		if (addr) {
2194955Swnj 			if (inp->inp_faddr.s_addr)
2204887Swnj 				return (EISCONN);
2214955Swnj 			error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
222*5051Swnj 			if (error)
2234955Swnj 				return (error);
2244955Swnj 		} else {
2254955Swnj 			if (inp->inp_faddr.s_addr == 0)
2264955Swnj 				return (ENOTCONN);
2274955Swnj 		}
2284955Swnj 		udp_output(inp, m);
2294955Swnj 		if (addr)
2304955Swnj 			inp->inp_faddr.s_addr = 0;
2314784Swnj 		break;
2324784Swnj 
2334784Swnj 	case PRU_ABORT:
2344887Swnj 		in_pcbfree(inp);
2354887Swnj 		sofree(so);
2364887Swnj 		soisdisconnected(so);
2374784Swnj 		break;
2384784Swnj 
2394784Swnj 	case PRU_CONTROL:
2404887Swnj 		return (EOPNOTSUPP);
2414784Swnj 
2424784Swnj 	default:
2434784Swnj 		panic("udp_usrreq");
2444805Swnj 	}
2454887Swnj 	return (0);
2464784Swnj }
2474805Swnj 
2484955Swnj /*ARGSUSED*/
2494926Swnj udp_sense(m)
2504926Swnj 	struct mbuf *m;
2514805Swnj {
2524955Swnj 
2535050Swnj 	printf("udp_sense\n");
2544926Swnj 	return (EOPNOTSUPP);
2554805Swnj }
256