xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 9644)
1*9644Ssam /*	udp_usrreq.c	4.41	82/12/14	*/
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"
108411Swnj #include "../netinet/in.h"
116584Ssam #include "../net/if.h"
126354Ssam #include "../net/route.h"
138411Swnj #include "../netinet/in_pcb.h"
148411Swnj #include "../netinet/in_systm.h"
158411Swnj #include "../netinet/ip.h"
168411Swnj #include "../netinet/ip_var.h"
178411Swnj #include "../netinet/ip_icmp.h"
188411Swnj #include "../netinet/udp.h"
198411Swnj #include "../netinet/udp_var.h"
206507Ssam #include <errno.h>
214784Swnj 
224926Swnj /*
234926Swnj  * UDP protocol implementation.
244926Swnj  * Per RFC 768, August, 1980.
254926Swnj  */
264805Swnj udp_init()
274805Swnj {
284805Swnj 
294901Swnj 	udb.inp_next = udb.inp_prev = &udb;
304805Swnj }
314805Swnj 
324901Swnj int	udpcksum;
334926Swnj struct	sockaddr_in udp_in = { AF_INET };
344901Swnj 
354926Swnj udp_input(m0)
364926Swnj 	struct mbuf *m0;
374784Swnj {
384901Swnj 	register struct udpiphdr *ui;
394887Swnj 	register struct inpcb *inp;
404926Swnj 	register struct mbuf *m;
417844Sroot 	int len;
424784Swnj 
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 	 */
607844Sroot 	len = ntohs((u_short)ui->ui_ulen);
614926Swnj 	if (((struct ip *)ui)->ip_len != len) {
624926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
634926Swnj 			udpstat.udps_badlen++;
644926Swnj 			goto bad;
654926Swnj 		}
664926Swnj 		m_adj(m, ((struct ip *)ui)->ip_len - len);
674926Swnj 		/* (struct ip *)ui->ip_len = len; */
684926Swnj 	}
694926Swnj 
704926Swnj 	/*
715246Sroot 	 * Checksum extended UDP header and data.
724926Swnj 	 */
734901Swnj 	if (udpcksum) {
744926Swnj 		ui->ui_next = ui->ui_prev = 0;
754926Swnj 		ui->ui_x1 = 0;
767844Sroot 		ui->ui_len = htons((u_short)len);
777844Sroot 		if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
784926Swnj 			udpstat.udps_badsum++;
794901Swnj 			printf("udp cksum %x\n", ui->ui_sum);
804901Swnj 			m_freem(m);
814901Swnj 			return;
824901Swnj 		}
834901Swnj 	}
844926Swnj 
854926Swnj 	/*
867844Sroot 	 * Locate pcb for datagram.
874926Swnj 	 */
884926Swnj 	inp = in_pcblookup(&udb,
896029Sroot 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
906029Sroot 		INPLOOKUP_WILDCARD);
916584Ssam 	if (inp == 0) {
926584Ssam 		struct in_addr broadcastaddr;
934926Swnj 
948602Sroot 		broadcastaddr =
958812Sroot 		    if_makeaddr(in_netof(ui->ui_dst), INADDR_ANY);
966591Ssam 		if (ui->ui_dst.s_addr == broadcastaddr.s_addr)
976584Ssam 			goto bad;
986584Ssam 		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT);
996584Ssam 		return;
1006584Ssam 	}
1016584Ssam 
1024926Swnj 	/*
1034926Swnj 	 * Construct sockaddr format source address.
1044926Swnj 	 * Stuff source address and datagram in user buffer.
1054926Swnj 	 */
1064926Swnj 	udp_in.sin_port = ui->ui_sport;
1074926Swnj 	udp_in.sin_addr = ui->ui_src;
1085050Swnj 	m->m_len -= sizeof (struct udpiphdr);
1095050Swnj 	m->m_off += sizeof (struct udpiphdr);
1108551Sroot SBCHECK(&inp->inp_socket->so_rcv, "udpinput before");
1115050Swnj 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
1124926Swnj 		goto bad;
1138551Sroot SBCHECK(&inp->inp_socket->so_rcv, "udpinput after");
1145050Swnj 	sorwakeup(inp->inp_socket);
1154887Swnj 	return;
1164926Swnj bad:
1174887Swnj 	m_freem(m);
1184784Swnj }
1194784Swnj 
1206584Ssam udp_abort(inp)
1216584Ssam 	struct inpcb *inp;
1226584Ssam {
1236584Ssam 	struct socket *so = inp->inp_socket;
1246584Ssam 
1256584Ssam 	in_pcbdisconnect(inp);
1266584Ssam 	soisdisconnected(so);
1276584Ssam }
1286584Ssam 
1296591Ssam udp_ctlinput(cmd, arg)
1306591Ssam 	int cmd;
1316591Ssam 	caddr_t arg;
1326591Ssam {
1336591Ssam 	struct in_addr *sin;
1346591Ssam 	extern u_char inetctlerrmap[];
1356591Ssam 
1366591Ssam 	if (cmd < 0 || cmd > PRC_NCMDS)
1376591Ssam 		return;
1386591Ssam 	switch (cmd) {
1396591Ssam 
1406591Ssam 	case PRC_ROUTEDEAD:
1416591Ssam 		break;
1426591Ssam 
1436591Ssam 	case PRC_QUENCH:
1446591Ssam 		break;
1456591Ssam 
1466591Ssam 	/* these are handled by ip */
1476591Ssam 	case PRC_IFDOWN:
1486591Ssam 	case PRC_HOSTDEAD:
1496591Ssam 	case PRC_HOSTUNREACH:
1506591Ssam 		break;
1516591Ssam 
1526591Ssam 	default:
1536591Ssam 		sin = &((struct icmp *)arg)->icmp_ip.ip_dst;
1548641Sroot 		in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort);
1556591Ssam 	}
1566591Ssam }
1576591Ssam 
1584955Swnj udp_output(inp, m0)
1594926Swnj 	struct inpcb *inp;
1604926Swnj 	struct mbuf *m0;
1614784Swnj {
1624926Swnj 	register struct mbuf *m;
1634926Swnj 	register struct udpiphdr *ui;
1647157Swnj 	register struct socket *so;
1654926Swnj 	register int len = 0;
1664784Swnj 
1674926Swnj 	/*
1684926Swnj 	 * Calculate data length and get a mbuf
1695246Sroot 	 * for UDP and IP headers.
1704926Swnj 	 */
1714926Swnj 	for (m = m0; m; m = m->m_next)
1724926Swnj 		len += m->m_len;
173*9644Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
1746507Ssam 	if (m == 0) {
1756507Ssam 		m_freem(m0);
1766507Ssam 		return (ENOBUFS);
1776507Ssam 	}
1784784Swnj 
1794926Swnj 	/*
1805246Sroot 	 * Fill in mbuf with extended UDP header
1814926Swnj 	 * and addresses and length put into network format.
1824926Swnj 	 */
1834926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
1844926Swnj 	m->m_len = sizeof (struct udpiphdr);
1854926Swnj 	m->m_next = m0;
1864926Swnj 	ui = mtod(m, struct udpiphdr *);
1874926Swnj 	ui->ui_next = ui->ui_prev = 0;
1884926Swnj 	ui->ui_x1 = 0;
1894926Swnj 	ui->ui_pr = IPPROTO_UDP;
1907844Sroot 	ui->ui_len = len + sizeof (struct udphdr);
1915050Swnj 	ui->ui_src = inp->inp_laddr;
1925050Swnj 	ui->ui_dst = inp->inp_faddr;
1935050Swnj 	ui->ui_sport = inp->inp_lport;
1945050Swnj 	ui->ui_dport = inp->inp_fport;
1957844Sroot 	ui->ui_ulen = htons((u_short)ui->ui_len);
1964784Swnj 
1974926Swnj 	/*
1984926Swnj 	 * Stuff checksum and output datagram.
1994926Swnj 	 */
2004926Swnj 	ui->ui_sum = 0;
2015094Swnj 	ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
2025050Swnj 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
2035050Swnj 	((struct ip *)ui)->ip_ttl = MAXTTL;
2047157Swnj 	so = inp->inp_socket;
2057157Swnj 	return (ip_output(m, (struct mbuf *)0,
2067157Swnj 	    (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0,
2077157Swnj 	    so->so_state & SS_PRIV));
2084784Swnj }
2094784Swnj 
2108602Sroot /*ARGSUSED*/
2118273Sroot udp_usrreq(so, req, m, nam, opt)
2124887Swnj 	struct socket *so;
2134784Swnj 	int req;
2148273Sroot 	struct mbuf *m, *nam;
2158273Sroot 	struct socketopt *opt;
2164784Swnj {
2174887Swnj 	struct inpcb *inp = sotoinpcb(so);
2186507Ssam 	int error = 0;
2194784Swnj 
2205051Swnj 	if (inp == 0 && req != PRU_ATTACH)
2215050Swnj 		return (EINVAL);
2224784Swnj 	switch (req) {
2234784Swnj 
2244784Swnj 	case PRU_ATTACH:
2254887Swnj 		if (inp != 0)
2264887Swnj 			return (EINVAL);
2278273Sroot 		error = in_pcballoc(so, &udb);
2288273Sroot 		if (error)
2298273Sroot 			break;
2309032Sroot 		error = soreserve(so, 2048, 2048);
2318273Sroot 		if (error)
2328273Sroot 			break;
2334887Swnj 		break;
2344784Swnj 
2354784Swnj 	case PRU_DETACH:
2364887Swnj 		if (inp == 0)
2374887Swnj 			return (ENOTCONN);
2385166Swnj 		in_pcbdetach(inp);
2394887Swnj 		break;
2404784Swnj 
2418273Sroot 	case PRU_BIND:
2428273Sroot 		error = in_pcbbind(inp, nam);
2438273Sroot 		break;
2448273Sroot 
2458273Sroot 	case PRU_LISTEN:
2468273Sroot 		error = EOPNOTSUPP;
2478273Sroot 		break;
2488273Sroot 
2494784Swnj 	case PRU_CONNECT:
2504955Swnj 		if (inp->inp_faddr.s_addr)
2514887Swnj 			return (EISCONN);
2528273Sroot 		error = in_pcbconnect(inp, nam);
2536507Ssam 		if (error == 0)
2546507Ssam 			soisconnected(so);
2554887Swnj 		break;
2564784Swnj 
2574926Swnj 	case PRU_ACCEPT:
2584926Swnj 		return (EOPNOTSUPP);
2594926Swnj 
2604784Swnj 	case PRU_DISCONNECT:
2614955Swnj 		if (inp->inp_faddr.s_addr == 0)
2624887Swnj 			return (ENOTCONN);
2635166Swnj 		in_pcbdisconnect(inp);
2644887Swnj 		soisdisconnected(so);
2654784Swnj 		break;
2664784Swnj 
2674912Swnj 	case PRU_SHUTDOWN:
2684912Swnj 		socantsendmore(so);
2694912Swnj 		break;
2704912Swnj 
2715996Swnj 	case PRU_SEND: {
2725996Swnj 		struct in_addr laddr;
2735996Swnj 
2748273Sroot 		if (nam) {
2755996Swnj 			laddr = inp->inp_laddr;
2765224Swnj 			if (inp->inp_faddr.s_addr)
2774887Swnj 				return (EISCONN);
2788273Sroot 			error = in_pcbconnect(inp, nam);
2795224Swnj 			if (error)
2806507Ssam 				break;
2814955Swnj 		} else {
2824955Swnj 			if (inp->inp_faddr.s_addr == 0)
2834955Swnj 				return (ENOTCONN);
2844955Swnj 		}
2856507Ssam 		error = udp_output(inp, m);
2868273Sroot 		if (nam) {
2875166Swnj 			in_pcbdisconnect(inp);
2885996Swnj 			inp->inp_laddr = laddr;
2895996Swnj 		}
2905996Swnj 		}
2914784Swnj 		break;
2924784Swnj 
2934784Swnj 	case PRU_ABORT:
2945166Swnj 		in_pcbdetach(inp);
2954887Swnj 		sofree(so);
2964887Swnj 		soisdisconnected(so);
2974784Swnj 		break;
2984784Swnj 
2994784Swnj 	case PRU_CONTROL:
3004887Swnj 		return (EOPNOTSUPP);
3014784Swnj 
3026511Ssam 	case PRU_SOCKADDR:
3038273Sroot 		in_setsockaddr(inp, nam);
3046511Ssam 		break;
3056511Ssam 
3064784Swnj 	default:
3074784Swnj 		panic("udp_usrreq");
3084805Swnj 	}
3096507Ssam 	return (error);
3104784Swnj }
311