xref: /original-bsd/sys/netinet/udp_usrreq.c (revision 9c59a687)
1 /*	udp_usrreq.c	4.24	82/03/29	*/
2 
3 #include "../h/param.h"
4 #include "../h/dir.h"
5 #include "../h/user.h"
6 #include "../h/mbuf.h"
7 #include "../h/protosw.h"
8 #include "../h/socket.h"
9 #include "../h/socketvar.h"
10 #include "../net/in.h"
11 #include "../net/route.h"
12 #include "../net/in_pcb.h"
13 #include "../net/in_systm.h"
14 #include "../net/ip.h"
15 #include "../net/ip_var.h"
16 #include "../net/udp.h"
17 #include "../net/udp_var.h"
18 
19 /*
20  * UDP protocol implementation.
21  * Per RFC 768, August, 1980.
22  */
23 udp_init()
24 {
25 
26 COUNT(UDP_INIT);
27 	udb.inp_next = udb.inp_prev = &udb;
28 }
29 
30 int	udpcksum;
31 struct	sockaddr_in udp_in = { AF_INET };
32 
33 udp_input(m0)
34 	struct mbuf *m0;
35 {
36 	register struct udpiphdr *ui;
37 	register struct inpcb *inp;
38 	register struct mbuf *m;
39 	int len, ulen;
40 
41 COUNT(UDP_INPUT);
42 	/*
43 	 * Get IP and UDP header together in first mbuf.
44 	 */
45 	m = m0;
46 	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
47 	    (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
48 		udpstat.udps_hdrops++;
49 		return;
50 	}
51 	ui = mtod(m, struct udpiphdr *);
52 	if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
53 		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
54 
55 	/*
56 	 * Make mbuf data length reflect UDP length.
57 	 * If not enough data to reflect UDP length, drop.
58 	 */
59 	ulen = ntohs((u_short)ui->ui_ulen);
60 	len = sizeof (struct udphdr) + ulen;
61 	if (((struct ip *)ui)->ip_len != len) {
62 		if (len > ((struct ip *)ui)->ip_len) {
63 			udpstat.udps_badlen++;
64 			goto bad;
65 		}
66 		m_adj(m, ((struct ip *)ui)->ip_len - len);
67 		/* (struct ip *)ui->ip_len = len; */
68 	}
69 
70 	/*
71 	 * Checksum extended UDP header and data.
72 	 */
73 	if (udpcksum) {
74 		ui->ui_next = ui->ui_prev = 0;
75 		ui->ui_x1 = 0;
76 		ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen));
77 		if (ui->ui_sum = in_cksum(m, len)) {
78 			udpstat.udps_badsum++;
79 			printf("udp cksum %x\n", ui->ui_sum);
80 			m_freem(m);
81 			return;
82 		}
83 	}
84 
85 	/*
86 	 * Locate pcb for datagram.  On wildcard match, update
87 	 * control block to anchor network and host address.
88 	 */
89 	inp = in_pcblookup(&udb,
90 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
91 		INPLOOKUP_WILDCARD);
92 	if (inp == 0)
93 		goto bad;
94 
95 	/*
96 	 * Construct sockaddr format source address.
97 	 * Stuff source address and datagram in user buffer.
98 	 */
99 	udp_in.sin_port = ui->ui_sport;
100 	udp_in.sin_addr = ui->ui_src;
101 	m->m_len -= sizeof (struct udpiphdr);
102 	m->m_off += sizeof (struct udpiphdr);
103 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
104 		goto bad;
105 	sorwakeup(inp->inp_socket);
106 	return;
107 bad:
108 	m_freem(m);
109 }
110 
111 udp_ctlinput(m)
112 	struct mbuf *m;
113 {
114 
115 COUNT(UDP_CTLINPUT);
116 	m_freem(m);
117 }
118 
119 udp_output(inp, m0)
120 	struct inpcb *inp;
121 	struct mbuf *m0;
122 {
123 	register struct mbuf *m;
124 	register struct udpiphdr *ui;
125 	register int len = 0;
126 
127 COUNT(UDP_OUTPUT);
128 	/*
129 	 * Calculate data length and get a mbuf
130 	 * for UDP and IP headers.
131 	 */
132 	for (m = m0; m; m = m->m_next)
133 		len += m->m_len;
134 	m = m_get(M_DONTWAIT);
135 	if (m == 0)
136 		goto bad;
137 
138 	/*
139 	 * Fill in mbuf with extended UDP header
140 	 * and addresses and length put into network format.
141 	 */
142 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
143 	m->m_len = sizeof (struct udpiphdr);
144 	m->m_next = m0;
145 	ui = mtod(m, struct udpiphdr *);
146 	ui->ui_next = ui->ui_prev = 0;
147 	ui->ui_x1 = 0;
148 	ui->ui_pr = IPPROTO_UDP;
149 	ui->ui_len = sizeof (struct udpiphdr) + len;
150 	ui->ui_src = inp->inp_laddr;
151 	ui->ui_dst = inp->inp_faddr;
152 	ui->ui_sport = inp->inp_lport;
153 	ui->ui_dport = inp->inp_fport;
154 	ui->ui_ulen = htons((u_short)len);
155 
156 	/*
157 	 * Stuff checksum and output datagram.
158 	 */
159 	ui->ui_sum = 0;
160 	ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
161 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
162 	((struct ip *)ui)->ip_ttl = MAXTTL;
163 	(void) ip_output(m, (struct mbuf *)0, 0,
164 	    inp->inp_socket->so_state & SS_PRIV);
165 	return;
166 bad:
167 	m_freem(m);
168 }
169 
170 udp_usrreq(so, req, m, addr)
171 	struct socket *so;
172 	int req;
173 	struct mbuf *m;
174 	caddr_t addr;
175 {
176 	struct inpcb *inp = sotoinpcb(so);
177 	int error;
178 
179 COUNT(UDP_USRREQ);
180 	if (inp == 0 && req != PRU_ATTACH)
181 		return (EINVAL);
182 	switch (req) {
183 
184 	case PRU_ATTACH:
185 		if (inp != 0)
186 			return (EINVAL);
187 		error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
188 		if (error)
189 			return (error);
190 		break;
191 
192 	case PRU_DETACH:
193 		if (inp == 0)
194 			return (ENOTCONN);
195 		in_pcbdetach(inp);
196 		break;
197 
198 	case PRU_CONNECT:
199 		if (inp->inp_faddr.s_addr)
200 			return (EISCONN);
201 		error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
202 		if (error)
203 			return (error);
204 		soisconnected(so);
205 		break;
206 
207 	case PRU_ACCEPT:
208 		return (EOPNOTSUPP);
209 
210 	case PRU_DISCONNECT:
211 		if (inp->inp_faddr.s_addr == 0)
212 			return (ENOTCONN);
213 		in_pcbdisconnect(inp);
214 		soisdisconnected(so);
215 		break;
216 
217 	case PRU_SHUTDOWN:
218 		socantsendmore(so);
219 		break;
220 
221 	case PRU_SEND: {
222 		struct in_addr laddr;
223 
224 		if (addr) {
225 			laddr = inp->inp_laddr;
226 			if (inp->inp_faddr.s_addr)
227 				return (EISCONN);
228 			error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
229 			if (error)
230 				return (error);
231 		} else {
232 			if (inp->inp_faddr.s_addr == 0)
233 				return (ENOTCONN);
234 		}
235 		udp_output(inp, m);
236 		if (addr) {
237 			in_pcbdisconnect(inp);
238 			inp->inp_laddr = laddr;
239 			in_setsockaddr(inp);
240 		}
241 		}
242 		break;
243 
244 	case PRU_ABORT:
245 		in_pcbdetach(inp);
246 		sofree(so);
247 		soisdisconnected(so);
248 		break;
249 
250 	case PRU_CONTROL:
251 		return (EOPNOTSUPP);
252 
253 	default:
254 		panic("udp_usrreq");
255 	}
256 	return (0);
257 }
258