xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 14243)
1 /*	udp_usrreq.c	6.1	83/07/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 "../h/errno.h"
11 
12 #include "../net/if.h"
13 #include "../net/route.h"
14 
15 #include "../netinet/in.h"
16 #include "../netinet/in_pcb.h"
17 #include "../netinet/in_systm.h"
18 #include "../netinet/ip.h"
19 #include "../netinet/ip_var.h"
20 #include "../netinet/ip_icmp.h"
21 #include "../netinet/udp.h"
22 #include "../netinet/udp_var.h"
23 
24 /*
25  * UDP protocol implementation.
26  * Per RFC 768, August, 1980.
27  */
28 udp_init()
29 {
30 
31 	udb.inp_next = udb.inp_prev = &udb;
32 }
33 
34 int	udpcksum;
35 struct	sockaddr_in udp_in = { AF_INET };
36 
37 udp_input(m0)
38 	struct mbuf *m0;
39 {
40 	register struct udpiphdr *ui;
41 	register struct inpcb *inp;
42 	register struct mbuf *m;
43 	int len;
44 
45 	/*
46 	 * Get IP and UDP header together in first mbuf.
47 	 */
48 	m = m0;
49 	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
50 	    (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
51 		udpstat.udps_hdrops++;
52 		return;
53 	}
54 	ui = mtod(m, struct udpiphdr *);
55 	if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
56 		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
57 
58 	/*
59 	 * Make mbuf data length reflect UDP length.
60 	 * If not enough data to reflect UDP length, drop.
61 	 */
62 	len = ntohs((u_short)ui->ui_ulen);
63 	if (((struct ip *)ui)->ip_len != len) {
64 		if (len > ((struct ip *)ui)->ip_len) {
65 			udpstat.udps_badlen++;
66 			goto bad;
67 		}
68 		m_adj(m, ((struct ip *)ui)->ip_len - len);
69 		/* (struct ip *)ui->ip_len = len; */
70 	}
71 
72 	/*
73 	 * Checksum extended UDP header and data.
74 	 */
75 	if (udpcksum) {
76 		ui->ui_next = ui->ui_prev = 0;
77 		ui->ui_x1 = 0;
78 		ui->ui_len = htons((u_short)len);
79 		if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
80 			udpstat.udps_badsum++;
81 			m_freem(m);
82 			return;
83 		}
84 	}
85 
86 	/*
87 	 * Locate pcb for datagram.
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 		/* don't send ICMP response for broadcast packet */
94 		if (in_lnaof(ui->ui_dst) == INADDR_ANY)
95 			goto bad;
96 		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT);
97 		return;
98 	}
99 
100 	/*
101 	 * Construct sockaddr format source address.
102 	 * Stuff source address and datagram in user buffer.
103 	 */
104 	udp_in.sin_port = ui->ui_sport;
105 	udp_in.sin_addr = ui->ui_src;
106 	m->m_len -= sizeof (struct udpiphdr);
107 	m->m_off += sizeof (struct udpiphdr);
108 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
109 	    m, (struct mbuf *)0) == 0)
110 		goto bad;
111 	sorwakeup(inp->inp_socket);
112 	return;
113 bad:
114 	m_freem(m);
115 }
116 
117 udp_abort(inp)
118 	struct inpcb *inp;
119 {
120 	struct socket *so = inp->inp_socket;
121 
122 	in_pcbdisconnect(inp);
123 	soisdisconnected(so);
124 }
125 
126 udp_ctlinput(cmd, arg)
127 	int cmd;
128 	caddr_t arg;
129 {
130 	struct in_addr *sin;
131 	extern u_char inetctlerrmap[];
132 
133 	if (cmd < 0 || cmd > PRC_NCMDS)
134 		return;
135 	switch (cmd) {
136 
137 	case PRC_ROUTEDEAD:
138 		break;
139 
140 	case PRC_QUENCH:
141 		break;
142 
143 	/* these are handled by ip */
144 	case PRC_IFDOWN:
145 	case PRC_HOSTDEAD:
146 	case PRC_HOSTUNREACH:
147 		break;
148 
149 	default:
150 		sin = &((struct icmp *)arg)->icmp_ip.ip_dst;
151 		in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort);
152 	}
153 }
154 
155 udp_output(inp, m0)
156 	struct inpcb *inp;
157 	struct mbuf *m0;
158 {
159 	register struct mbuf *m;
160 	register struct udpiphdr *ui;
161 	register struct socket *so;
162 	register int len = 0;
163 	int flags;
164 
165 	/*
166 	 * Calculate data length and get a mbuf
167 	 * for UDP and IP headers.
168 	 */
169 	for (m = m0; m; m = m->m_next)
170 		len += m->m_len;
171 	m = m_get(M_DONTWAIT, MT_HEADER);
172 	if (m == 0) {
173 		m_freem(m0);
174 		return (ENOBUFS);
175 	}
176 
177 	/*
178 	 * Fill in mbuf with extended UDP header
179 	 * and addresses and length put into network format.
180 	 */
181 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
182 	m->m_len = sizeof (struct udpiphdr);
183 	m->m_next = m0;
184 	ui = mtod(m, struct udpiphdr *);
185 	ui->ui_next = ui->ui_prev = 0;
186 	ui->ui_x1 = 0;
187 	ui->ui_pr = IPPROTO_UDP;
188 	ui->ui_len = len + sizeof (struct udphdr);
189 	ui->ui_src = inp->inp_laddr;
190 	ui->ui_dst = inp->inp_faddr;
191 	ui->ui_sport = inp->inp_lport;
192 	ui->ui_dport = inp->inp_fport;
193 	ui->ui_ulen = htons((u_short)ui->ui_len);
194 
195 	/*
196 	 * Stuff checksum and output datagram.
197 	 */
198 	ui->ui_sum = 0;
199 	ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
200 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
201 	((struct ip *)ui)->ip_ttl = MAXTTL;
202 	so = inp->inp_socket;
203 	flags = (so->so_options & SO_DONTROUTE) | (so->so_state & SS_PRIV);
204 	return (ip_output(m, (struct mbuf *)0, (struct route *)0, flags));
205 }
206 
207 /*ARGSUSED*/
208 udp_usrreq(so, req, m, nam, rights)
209 	struct socket *so;
210 	int req;
211 	struct mbuf *m, *nam, *rights;
212 {
213 	struct inpcb *inp = sotoinpcb(so);
214 	int error = 0;
215 
216 	if (rights && rights->m_len) {
217 		error = EINVAL;
218 		goto release;
219 	}
220 	if (inp == NULL && req != PRU_ATTACH) {
221 		error = EINVAL;
222 		goto release;
223 	}
224 	switch (req) {
225 
226 	case PRU_ATTACH:
227 		if (inp != NULL) {
228 			error = EINVAL;
229 			break;
230 		}
231 		error = in_pcballoc(so, &udb);
232 		if (error)
233 			break;
234 		error = soreserve(so, 2048, 2048);
235 		if (error)
236 			break;
237 		break;
238 
239 	case PRU_DETACH:
240 		if (inp == NULL) {
241 			error = ENOTCONN;
242 			break;
243 		}
244 		in_pcbdetach(inp);
245 		break;
246 
247 	case PRU_BIND:
248 		error = in_pcbbind(inp, nam);
249 		break;
250 
251 	case PRU_LISTEN:
252 		error = EOPNOTSUPP;
253 		break;
254 
255 	case PRU_CONNECT:
256 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
257 			error = EISCONN;
258 			break;
259 		}
260 		error = in_pcbconnect(inp, nam);
261 		if (error == 0)
262 			soisconnected(so);
263 		break;
264 
265 	case PRU_CONNECT2:
266 		error = EOPNOTSUPP;
267 		break;
268 
269 	case PRU_ACCEPT:
270 		error = EOPNOTSUPP;
271 		break;
272 
273 	case PRU_DISCONNECT:
274 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
275 			error = ENOTCONN;
276 			break;
277 		}
278 		in_pcbdisconnect(inp);
279 		soisdisconnected(so);
280 		break;
281 
282 	case PRU_SHUTDOWN:
283 		socantsendmore(so);
284 		break;
285 
286 	case PRU_SEND: {
287 		struct in_addr laddr;
288 
289 		if (nam) {
290 			laddr = inp->inp_laddr;
291 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
292 				error = EISCONN;
293 				break;
294 			}
295 			error = in_pcbconnect(inp, nam);
296 			if (error)
297 				break;
298 		} else {
299 			if (inp->inp_faddr.s_addr == INADDR_ANY) {
300 				error = ENOTCONN;
301 				break;
302 			}
303 		}
304 		error = udp_output(inp, m);
305 		m = NULL;
306 		if (nam) {
307 			in_pcbdisconnect(inp);
308 			inp->inp_laddr = laddr;
309 		}
310 		}
311 		break;
312 
313 	case PRU_ABORT:
314 		in_pcbdetach(inp);
315 		sofree(so);
316 		soisdisconnected(so);
317 		break;
318 
319 	case PRU_SOCKADDR:
320 		in_setsockaddr(inp, nam);
321 		break;
322 
323 	case PRU_PEERADDR:
324 		in_setpeeraddr(inp, nam);
325 		break;
326 
327 	case PRU_CONTROL:
328 		m = NULL;
329 		error = EOPNOTSUPP;
330 		break;
331 
332 	case PRU_SENSE:
333 		m = NULL;
334 		/* fall thru... */
335 
336 	case PRU_RCVD:
337 	case PRU_RCVOOB:
338 	case PRU_SENDOOB:
339 	case PRU_FASTTIMO:
340 	case PRU_SLOWTIMO:
341 	case PRU_PROTORCV:
342 	case PRU_PROTOSEND:
343 		error =  EOPNOTSUPP;
344 		break;
345 
346 	default:
347 		panic("udp_usrreq");
348 	}
349 release:
350 	if (m != NULL)
351 		m_freem(m);
352 	return (error);
353 }
354