xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 4926)
1*4926Swnj /*	udp_usrreq.c	4.6	81/11/18	*/
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_host.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 
19*4926Swnj /*
20*4926Swnj  * UDP protocol implementation.
21*4926Swnj  * Per RFC 768, August, 1980.
22*4926Swnj  */
234805Swnj udp_init()
244805Swnj {
254805Swnj 
264901Swnj 	udb.inp_next = udb.inp_prev = &udb;
274805Swnj }
284805Swnj 
294901Swnj int	udpcksum;
30*4926Swnj struct	sockaddr_in udp_in = { AF_INET };
314901Swnj 
32*4926Swnj udp_input(m0)
33*4926Swnj 	struct mbuf *m0;
344784Swnj {
354901Swnj 	register struct udpiphdr *ui;
364887Swnj 	register struct inpcb *inp;
37*4926Swnj 	register struct mbuf *m;
38*4926Swnj 	int len, ulen;
394784Swnj 
40*4926Swnj 	/*
41*4926Swnj 	 * Get ip and udp header together in first mbuf.
42*4926Swnj 	 */
43*4926Swnj 	m = m0;
444901Swnj 	ui = mtod(m, struct udpiphdr *);
45*4926Swnj 	if (ui->ui_len > sizeof (struct ip))
464901Swnj 		ip_stripoptions((struct ip *)ui);
47*4926Swnj 	if (m->m_len < sizeof (struct udpiphdr) &&
48*4926Swnj 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
49*4926Swnj 		udpstat.udps_hdrops++;
50*4926Swnj 		goto bad;
51*4926Swnj 	}
52*4926Swnj 
53*4926Swnj 	/*
54*4926Swnj 	 * Make mbuf data length reflect udp length.
55*4926Swnj 	 * If not enough data to reflect udp length, drop.
56*4926Swnj 	 */
57*4926Swnj 	ulen = ntohs(ui->ui_ulen);
58*4926Swnj 	len = sizeof (struct udpiphdr) + ulen;
59*4926Swnj 	if (((struct ip *)ui)->ip_len != len) {
60*4926Swnj 		if (len > ((struct ip *)ui)->ip_len) {
61*4926Swnj 			udpstat.udps_badlen++;
62*4926Swnj 			goto bad;
63*4926Swnj 		}
64*4926Swnj 		m_adj(m, ((struct ip *)ui)->ip_len - len);
65*4926Swnj 		/* (struct ip *)ui->ip_len = len; */
66*4926Swnj 	}
67*4926Swnj 
68*4926Swnj 	/*
69*4926Swnj 	 * Checksum extended udp header and data.
70*4926Swnj 	 */
714901Swnj 	if (udpcksum) {
72*4926Swnj 		ui->ui_next = ui->ui_prev = 0;
73*4926Swnj 		ui->ui_x1 = 0;
74*4926Swnj 		ui->ui_len = htons(sizeof (struct udpiphdr) + ulen);
75*4926Swnj 		if (ui->ui_sum = inet_cksum(m, len)) {
76*4926Swnj 			udpstat.udps_badsum++;
774901Swnj 			printf("udp cksum %x\n", ui->ui_sum);
784901Swnj 			m_freem(m);
794901Swnj 			return;
804901Swnj 		}
814901Swnj 	}
82*4926Swnj 
83*4926Swnj 	/*
84*4926Swnj 	 * Convert addresses and ports to host format.
85*4926Swnj 	 * Locate pcb for datagram.
86*4926Swnj 	 */
87*4926Swnj 	ui->ui_src.s_addr = ntohl(ui->ui_src.s_addr);
88*4926Swnj 	ui->ui_dst.s_addr = ntohl(ui->ui_dst.s_addr);
89*4926Swnj 	ui->ui_sport = ntohs(ui->ui_sport);
90*4926Swnj 	ui->ui_dport = ntohs(ui->ui_dport);
91*4926Swnj 	inp = in_pcblookup(&udb,
92*4926Swnj 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
934887Swnj 	if (inp == 0)
94*4926Swnj 		goto bad;
95*4926Swnj 
96*4926Swnj 	/*
97*4926Swnj 	 * Construct sockaddr format source address.
98*4926Swnj 	 * Stuff source address and datagram in user buffer.
99*4926Swnj 	 */
100*4926Swnj 	udp_in.sin_port = ui->ui_sport;
101*4926Swnj 	udp_in.sin_addr = ui->ui_src;
102*4926Swnj 	if (sbappendaddr(inp->inp_socket, &udp_in, m) == 0)
103*4926Swnj 		goto bad;
1044887Swnj 	return;
105*4926Swnj bad:
1064887Swnj 	m_freem(m);
1074784Swnj }
1084784Swnj 
1094887Swnj udp_ctlinput(m)
1104887Swnj 	struct mbuf *m;
1114887Swnj {
1124887Swnj 
1134887Swnj 	m_freem(m);
1144887Swnj }
1154887Swnj 
116*4926Swnj /*ARGSUSED*/
117*4926Swnj udp_output(inp, raddr, rport, m0)
118*4926Swnj 	struct inpcb *inp;
119*4926Swnj 	struct in_addr *raddr;
120*4926Swnj 	u_short rport;
121*4926Swnj 	struct mbuf *m0;
1224784Swnj {
123*4926Swnj 	register struct mbuf *m;
124*4926Swnj 	register struct udpiphdr *ui;
125*4926Swnj 	register int len = 0;
1264784Swnj 
127*4926Swnj 	/*
128*4926Swnj 	 * Calculate data length and get a mbuf
129*4926Swnj 	 * for udp and ip headers.
130*4926Swnj 	 */
131*4926Swnj 	for (m = m0; m; m = m->m_next)
132*4926Swnj 		len += m->m_len;
133*4926Swnj 	m = m_get(0);
134*4926Swnj 	if (m == 0)
135*4926Swnj 		goto bad;
1364784Swnj 
137*4926Swnj 	/*
138*4926Swnj 	 * Fill in mbuf with extended udp header
139*4926Swnj 	 * and addresses and length put into network format.
140*4926Swnj 	 */
141*4926Swnj 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
142*4926Swnj 	m->m_len = sizeof (struct udpiphdr);
143*4926Swnj 	m->m_next = m0;
144*4926Swnj 	ui = mtod(m, struct udpiphdr *);
145*4926Swnj 	ui->ui_next = ui->ui_prev = 0;
146*4926Swnj 	ui->ui_x1 = 0;
147*4926Swnj 	ui->ui_pr = IPPROTO_UDP;
148*4926Swnj 	ui->ui_len = htons(sizeof (struct udphdr) + len);
149*4926Swnj 	ui->ui_src.s_addr = htonl(inp->inp_lhost);
150*4926Swnj 	ui->ui_dst.s_addr = htonl(raddr->s_addr);
151*4926Swnj 	ui->ui_sport = htons(inp->inp_lport);
152*4926Swnj 	ui->ui_dport = htons(inp->inp_fport);
153*4926Swnj 	ui->ui_ulen = htons(len);
1544784Swnj 
155*4926Swnj 	/*
156*4926Swnj 	 * Stuff checksum and output datagram.
157*4926Swnj 	 */
158*4926Swnj 	ui->ui_sum = 0;
159*4926Swnj 	ui->ui_sum = inet_cksum(m, sizeof (struct udpiphdr) + len);
1604887Swnj 	ip_output(m);
161*4926Swnj 	return;
162*4926Swnj bad:
163*4926Swnj 	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);
174*4926Swnj 	struct sockaddr_in *sin;
1754887Swnj 	int error;
1764784Swnj 
1774784Swnj 	switch (req) {
1784784Swnj 
1794784Swnj 	case PRU_ATTACH:
1804887Swnj 		if (inp != 0)
1814887Swnj 			return (EINVAL);
1824912Swnj 		inp = in_pcballoc();
1834887Swnj 		if (inp == NULL)
1844887Swnj 			return (ENOBUFS);
1854887Swnj 		so->so_pcb = (caddr_t)inp;
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:
1954887Swnj 		if (inp->inp_fhost)
1964887Swnj 			return (EISCONN);
197*4926Swnj 		in_hosteval(inp, (struct sockaddr *)addr, &error);
1984887Swnj 		if (inp->inp_fhost == 0)
1994887Swnj 			return (error);
2004887Swnj 		soisconnected(so);
2014887Swnj 		break;
2024784Swnj 
203*4926Swnj 	case PRU_ACCEPT:
204*4926Swnj 		return (EOPNOTSUPP);
205*4926Swnj 
2064784Swnj 	case PRU_DISCONNECT:
2074887Swnj 		if (inp->inp_fhost == 0)
2084887Swnj 			return (ENOTCONN);
2094912Swnj 		in_hostfree(inp->inp_fhost);
2104887Swnj 		inp->inp_fhost = 0;
2114887Swnj 		soisdisconnected(so);
2124784Swnj 		break;
2134784Swnj 
2144912Swnj 	case PRU_SHUTDOWN:
2154912Swnj 		socantsendmore(so);
2164912Swnj 		break;
2174912Swnj 
2184784Swnj 	case PRU_SEND:
2194887Swnj 		if (addr) {
2204887Swnj 			if (inp->inp_fhost)
2214887Swnj 				return (EISCONN);
222*4926Swnj 			sin = (struct sockaddr_in *)addr;
223*4926Swnj 			if (sin->sin_family != AF_INET)
224*4926Swnj 				return (EAFNOSUPPORT);
225*4926Swnj 			udp_output(inp, sin->sin_addr, sin->sin_port, m);
2264887Swnj 		} else
227*4926Swnj 			udp_output(inp,
228*4926Swnj 			    inp->inp_fhost->h_addr, inp->inp_fport, m);
2294784Swnj 		break;
2304784Swnj 
2314784Swnj 	case PRU_ABORT:
2324887Swnj 		in_pcbfree(inp);
2334887Swnj 		sofree(so);
2344887Swnj 		soisdisconnected(so);
2354784Swnj 		break;
2364784Swnj 
2374784Swnj 	case PRU_CONTROL:
2384887Swnj 		return (EOPNOTSUPP);
2394784Swnj 
2404784Swnj 	default:
2414784Swnj 		panic("udp_usrreq");
2424805Swnj 	}
2434887Swnj 	return (0);
2444784Swnj }
2454805Swnj 
246*4926Swnj udp_sense(m)
247*4926Swnj 	struct mbuf *m;
2484805Swnj {
249*4926Swnj 	return (EOPNOTSUPP);
2504805Swnj 
2514805Swnj }
252