xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 5220)
1*5220Swnj /*	udp_usrreq.c	4.15	81/12/09	*/
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"
115094Swnj #include "../net/in_pcb.h"
125094Swnj #include "../net/in_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 
255094Swnj COUNT(UDP_INIT);
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 
405094Swnj COUNT(UDP_INPUT);
414926Swnj 	/*
424926Swnj 	 * Get ip and udp header together in first mbuf.
434926Swnj 	 */
444926Swnj 	m = m0;
454926Swnj 	if (m->m_len < sizeof (struct udpiphdr) &&
464926Swnj 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
474926Swnj 		udpstat.udps_hdrops++;
484926Swnj 		goto bad;
494926Swnj 	}
505050Swnj 	ui = mtod(m, struct udpiphdr *);
515050Swnj 	if (ui->ui_len > sizeof (struct ip))
52*5220Swnj 		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
534926Swnj 
544926Swnj 	/*
554926Swnj 	 * Make mbuf data length reflect udp length.
564926Swnj 	 * If not enough data to reflect udp length, drop.
574926Swnj 	 */
584955Swnj 	ulen = ntohs((u_short)ui->ui_ulen);
59*5220Swnj 	len = sizeof (struct udphdr) + ulen;
60*5220Swnj printf("len %d, ulen %d, ((struct ip *)ui)->ip_len %d\n",
61*5220Swnj     len, ulen, ((struct ip *)ui)->ip_len);
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 	/*
724926Swnj 	 * Checksum extended udp header and data.
734926Swnj 	 */
744901Swnj 	if (udpcksum) {
754926Swnj 		ui->ui_next = ui->ui_prev = 0;
764926Swnj 		ui->ui_x1 = 0;
77*5220Swnj 		ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen));
78*5220Swnj 		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 	/*
874926Swnj 	 * Locate pcb for datagram.
884926Swnj 	 */
894926Swnj 	inp = in_pcblookup(&udb,
904926Swnj 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
915051Swnj 	if (inp == 0)
924926Swnj 		goto bad;
934926Swnj 
944926Swnj 	/*
954926Swnj 	 * Construct sockaddr format source address.
964926Swnj 	 * Stuff source address and datagram in user buffer.
974926Swnj 	 */
984926Swnj 	udp_in.sin_port = ui->ui_sport;
994926Swnj 	udp_in.sin_addr = ui->ui_src;
1005050Swnj 	m->m_len -= sizeof (struct udpiphdr);
1015050Swnj 	m->m_off += sizeof (struct udpiphdr);
102*5220Swnj printf("sbappendaddr called with m %x m->m_len %d m->m_off %d\n",
103*5220Swnj m, m->m_len, m->m_off);
104*5220Swnj printf("*mtod(m, char *) %x\n", *mtod(m, char *));
1055050Swnj 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
1064926Swnj 		goto bad;
1075050Swnj 	sorwakeup(inp->inp_socket);
1084887Swnj 	return;
1094926Swnj bad:
1104887Swnj 	m_freem(m);
1114784Swnj }
1124784Swnj 
1134887Swnj udp_ctlinput(m)
1144887Swnj 	struct mbuf *m;
1154887Swnj {
1164887Swnj 
1175094Swnj COUNT(UDP_CTLINPUT);
1185050Swnj 	printf("udp_ctlinput\n");
1194887Swnj 	m_freem(m);
1204887Swnj }
1214887Swnj 
1224926Swnj /*ARGSUSED*/
1234955Swnj udp_output(inp, m0)
1244926Swnj 	struct inpcb *inp;
1254926Swnj 	struct mbuf *m0;
1264784Swnj {
1274926Swnj 	register struct mbuf *m;
1284926Swnj 	register struct udpiphdr *ui;
1294926Swnj 	register int len = 0;
1304784Swnj 
1315094Swnj COUNT(UDP_OUTPUT);
1324926Swnj 	/*
1334926Swnj 	 * Calculate data length and get a mbuf
1344926Swnj 	 * for udp and ip headers.
1354926Swnj 	 */
1364926Swnj 	for (m = m0; m; m = m->m_next)
1374926Swnj 		len += m->m_len;
1384926Swnj 	m = m_get(0);
1395051Swnj 	if (m == 0)
1404926Swnj 		goto bad;
1414784Swnj 
1424926Swnj 	/*
1434926Swnj 	 * Fill in mbuf with extended udp header
1444926Swnj 	 * and addresses and length put into network format.
1454926Swnj 	 */
1464926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
1474926Swnj 	m->m_len = sizeof (struct udpiphdr);
1484926Swnj 	m->m_next = m0;
1494926Swnj 	ui = mtod(m, struct udpiphdr *);
1504926Swnj 	ui->ui_next = ui->ui_prev = 0;
1514926Swnj 	ui->ui_x1 = 0;
1524926Swnj 	ui->ui_pr = IPPROTO_UDP;
1535050Swnj 	ui->ui_len = sizeof (struct udpiphdr) + len;
1545050Swnj 	ui->ui_src = inp->inp_laddr;
1555050Swnj 	ui->ui_dst = inp->inp_faddr;
1565050Swnj 	ui->ui_sport = inp->inp_lport;
1575050Swnj 	ui->ui_dport = inp->inp_fport;
1584955Swnj 	ui->ui_ulen = htons((u_short)len);
1594784Swnj 
1604926Swnj 	/*
1614926Swnj 	 * Stuff checksum and output datagram.
1624926Swnj 	 */
1634926Swnj 	ui->ui_sum = 0;
1645094Swnj 	ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
1655050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1665050Swnj 	((struct ip *)ui)->ip_ttl = MAXTTL;
1675115Swnj 	(void) ip_output(m, (struct mbuf *)0);
1684926Swnj 	return;
1694926Swnj bad:
1704926Swnj 	m_freem(m);
1714784Swnj }
1724784Swnj 
1734912Swnj /*ARGSUSED*/
1744887Swnj udp_usrreq(so, req, m, addr)
1754887Swnj 	struct socket *so;
1764784Swnj 	int req;
1774784Swnj 	struct mbuf *m;
1784912Swnj 	caddr_t addr;
1794784Swnj {
1804887Swnj 	struct inpcb *inp = sotoinpcb(so);
1814887Swnj 	int error;
1824784Swnj 
1835094Swnj COUNT(UDP_USRREQ);
1845051Swnj 	if (inp == 0 && req != PRU_ATTACH)
1855050Swnj 		return (EINVAL);
186*5220Swnj printf("udp_usrreq %d\n", req);
1874784Swnj 	switch (req) {
1884784Swnj 
1894784Swnj 	case PRU_ATTACH:
1904887Swnj 		if (inp != 0)
1914887Swnj 			return (EINVAL);
1925166Swnj 		error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
1935051Swnj 		if (error)
1944955Swnj 			return (error);
1954887Swnj 		break;
1964784Swnj 
1974784Swnj 	case PRU_DETACH:
1984887Swnj 		if (inp == 0)
1994887Swnj 			return (ENOTCONN);
2005166Swnj 		in_pcbdetach(inp);
2014887Swnj 		break;
2024784Swnj 
2034784Swnj 	case PRU_CONNECT:
2044955Swnj 		if (inp->inp_faddr.s_addr)
2054887Swnj 			return (EISCONN);
2065166Swnj 		error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
2075051Swnj 		if (error)
2084887Swnj 			return (error);
2094887Swnj 		soisconnected(so);
2104887Swnj 		break;
2114784Swnj 
2124926Swnj 	case PRU_ACCEPT:
2134926Swnj 		return (EOPNOTSUPP);
2144926Swnj 
2154784Swnj 	case PRU_DISCONNECT:
2164955Swnj 		if (inp->inp_faddr.s_addr == 0)
2174887Swnj 			return (ENOTCONN);
2185166Swnj 		in_pcbdisconnect(inp);
2194887Swnj 		soisdisconnected(so);
2204784Swnj 		break;
2214784Swnj 
2224912Swnj 	case PRU_SHUTDOWN:
2234912Swnj 		socantsendmore(so);
2244912Swnj 		break;
2254912Swnj 
2264784Swnj 	case PRU_SEND:
2274887Swnj 		if (addr) {
228*5220Swnj 			if (inp->inp_faddr.s_addr) {
229*5220Swnj 				printf("EISCONN\n");
2304887Swnj 				return (EISCONN);
231*5220Swnj 			}
2325166Swnj 			error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
233*5220Swnj 			if (error) {
234*5220Swnj 				printf("pcbconnect error %d\n", error);
2354955Swnj 				return (error);
236*5220Swnj 			}
2374955Swnj 		} else {
2384955Swnj 			if (inp->inp_faddr.s_addr == 0)
2394955Swnj 				return (ENOTCONN);
2404955Swnj 		}
241*5220Swnj printf("to udp_output\n");
2424955Swnj 		udp_output(inp, m);
2434955Swnj 		if (addr)
2445166Swnj 			in_pcbdisconnect(inp);
2454784Swnj 		break;
2464784Swnj 
2474784Swnj 	case PRU_ABORT:
2485166Swnj 		in_pcbdetach(inp);
2494887Swnj 		sofree(so);
2504887Swnj 		soisdisconnected(so);
2514784Swnj 		break;
2524784Swnj 
2534784Swnj 	case PRU_CONTROL:
2544887Swnj 		return (EOPNOTSUPP);
2554784Swnj 
2564784Swnj 	default:
2574784Swnj 		panic("udp_usrreq");
2584805Swnj 	}
2594887Swnj 	return (0);
2604784Swnj }
261