xref: /csrg-svn/sys/netns/idp_usrreq.c (revision 23977)
1 /*
2  * Copyright (c) 1982 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *      @(#)idp_usrreq.c	6.5 (Berkeley) 07/19/85
7  */
8 
9 #include "param.h"
10 #include "dir.h"
11 #include "user.h"
12 #include "mbuf.h"
13 #include "protosw.h"
14 #include "socket.h"
15 #include "socketvar.h"
16 #include "errno.h"
17 #include "stat.h"
18 
19 #include "../net/if.h"
20 #include "../net/route.h"
21 
22 #include "ns.h"
23 #include "ns_pcb.h"
24 #include "idp.h"
25 #include "idp_var.h"
26 #include "ns_error.h"
27 
28 /*
29  * IDP protocol implementation.
30  */
31 
32 struct	sockaddr_ns idp_ns = { AF_NS };
33 
34 /*
35  *  This may also be called for raw listeners.
36  */
37 idp_input(m, nsp)
38 	struct mbuf *m;
39 	register struct nspcb *nsp;
40 {
41 	register struct idp *idp = mtod(m, struct idp *);
42 
43 	if (nsp==0) {
44 		nsp = ns_pcblookup(&idp->idp_sna,
45 					idp->idp_dna.x_port, NS_WILDCARD);
46 		if (nsp==0) {
47 			ns_error(m, NS_ERR_NOSOCK, 0);
48 			return;
49 		}
50 	}
51 
52 	/*
53 	 * Construct sockaddr format source address.
54 	 * Stuff source address and datagram in user buffer.
55 	 */
56 	idp_ns.sns_addr = idp->idp_sna;
57 	nsp->nsp_rpt = idp->idp_pt;
58 	if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
59 		m->m_len -= sizeof (struct idp);
60 		m->m_off += sizeof (struct idp);
61 	}
62 	if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
63 	    m, (struct mbuf *)0) == 0)
64 		goto bad;
65 	sorwakeup(nsp->nsp_socket);
66 	return;
67 bad:
68 	m_freem(m);
69 }
70 
71 idp_abort(nsp)
72 	struct nspcb *nsp;
73 {
74 	struct socket *so = nsp->nsp_socket;
75 
76 	ns_pcbdisconnect(nsp);
77 	soisdisconnected(so);
78 }
79 /*
80  * Drop connection, reporting
81  * the specified error.
82  */
83 struct nspcb *
84 idp_drop(nsp, errno)
85 	register struct nspcb *nsp;
86 	int errno;
87 {
88 	struct socket *so = nsp->nsp_socket;
89 
90 	/*
91 	 * someday, in the xerox world
92 	 * we will generate error protocol packets
93 	 * announcing that the socket has gone away.
94 	 */
95 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
96 		tp->t_state = TCPS_CLOSED;
97 		(void) tcp_output(tp);
98 	}*/
99 	so->so_error = errno;
100 	ns_pcbdisconnect(nsp);
101 	soisdisconnected(so);
102 }
103 
104 idp_output(nsp, m0)
105 	struct nspcb *nsp;
106 	struct mbuf *m0;
107 {
108 	register struct mbuf *m;
109 	register struct idp *idp;
110 	register struct socket *so;
111 	register int len = 0;
112 	register struct route *ro;
113 	struct mbuf *mprev;
114 	extern int idpcksum;
115 
116 	/*
117 	 * Calculate data length.
118 	 */
119 	for (m = m0; m; m = m->m_next) {
120 		mprev = m;
121 		len += m->m_len;
122 	}
123 	/*
124 	 * Make sure packet is actually of even length.
125 	 */
126 
127 	if (len & 1) {
128 		m = mprev;
129 		if (m->m_len + m->m_off < MMAXOFF) {
130 			m->m_len++;
131 		} else {
132 			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
133 
134 			if (m1 == 0) {
135 				m_freem(m0);
136 				return (ENOBUFS);
137 			}
138 			m1->m_len = 1;
139 			m1->m_off = MMAXOFF - 1;
140 			* mtod(m1, char *) = 0;
141 			m->m_next = m1;
142 		}
143 	}
144 
145 	/*
146 	 * Fill in mbuf with extended IDP header
147 	 * and addresses and length put into network format.
148 	 */
149 	if (nsp->nsp_flags & NSP_RAWOUT) {
150 		m = m0;
151 		idp = mtod(m, struct idp *);
152 	} else {
153 		m = m_get(M_DONTWAIT, MT_HEADER);
154 		if (m == 0) {
155 			m_freem(m0);
156 			return (ENOBUFS);
157 		}
158 		m->m_off = MMAXOFF - sizeof (struct idp);
159 		m->m_len = sizeof (struct idp);
160 		m->m_next = m0;
161 		idp = mtod(m, struct idp *);
162 		idp->idp_tc = 0;
163 		idp->idp_pt = nsp->nsp_dpt;
164 		idp->idp_sna = nsp->nsp_laddr;
165 		idp->idp_dna = nsp->nsp_faddr;
166 		len += sizeof (struct idp);
167 	}
168 
169 	idp->idp_len = htons((u_short)len);
170 
171 	if (idpcksum) {
172 		idp->idp_sum = 0;
173 		len = ((len - 1) | 1) + 1;
174 		idp->idp_sum = ns_cksum(m, len);
175 	} else
176 		idp->idp_sum = 0xffff;
177 
178 	/*
179 	 * Output datagram.
180 	 */
181 	so = nsp->nsp_socket;
182 	if (so->so_options & SO_DONTROUTE)
183 		return (ns_output(m, (struct route *)0,
184 		    (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
185 	/*
186 	 * Use cached route for previous datagram if
187 	 * this is also to the same destination.
188 	 *
189 	 * NB: We don't handle broadcasts because that
190 	 *     would require 3 subroutine calls.
191 	 */
192 	ro = &nsp->nsp_route;
193 	if (ro->ro_rt &&
194 		((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) &&
195 		!(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) {
196 		RTFREE(ro->ro_rt);
197 		ro->ro_rt = (struct rtentry *)0;
198 		nsp->nsp_lastnet = idp->idp_dna.x_net;
199 	}
200 	return (ns_output(m, ro, so->so_options & SO_BROADCAST));
201 }
202 /*ARGSUSED*/
203 idp_ctloutput(req, so, level, name, value)
204 	int req, level;
205 	struct socket *so;
206 	int name;
207 	struct mbuf **value;
208 {
209 	register struct mbuf *m;
210 	struct nspcb *nsp = sotonspcb(so);
211 	int mask, error = 0;
212 	extern long ns_pexseq;
213 
214 	if (nsp == NULL)
215 		return (EINVAL);
216 
217 	switch (req) {
218 
219 	case PRCO_GETOPT:
220 		if (value==NULL)
221 			return (EINVAL);
222 		m = m_get(M_DONTWAIT, MT_DATA);
223 		if (m==NULL)
224 			return (ENOBUFS);
225 		switch (name) {
226 
227 		case SO_HEADERS_ON_INPUT:
228 			mask = NSP_RAWIN;
229 			goto get_flags;
230 
231 		case SO_HEADERS_ON_OUTPUT:
232 			mask = NSP_RAWOUT;
233 		get_flags:
234 			m->m_len = sizeof(short);
235 			m->m_off = MMAXOFF - sizeof(short);
236 			*mtod(m, short *) = nsp->nsp_flags & mask;
237 			break;
238 
239 		case SO_DEFAULT_HEADERS:
240 			m->m_len = sizeof(struct idp);
241 			m->m_off = MMAXOFF - sizeof(struct idp);
242 			{
243 				register struct idp *idp = mtod(m, struct idp *);
244 				idp->idp_len = 0;
245 				idp->idp_sum = 0;
246 				idp->idp_tc = 0;
247 				idp->idp_pt = nsp->nsp_dpt;
248 				idp->idp_dna = nsp->nsp_faddr;
249 				idp->idp_sna = nsp->nsp_laddr;
250 			}
251 			break;
252 
253 		case SO_SEQNO:
254 			m->m_len = sizeof(long);
255 			m->m_off = MMAXOFF - sizeof(long);
256 			*mtod(m, long *) = ns_pexseq++;
257 		}
258 		*value = m;
259 		break;
260 
261 	case PRCO_SETOPT:
262 		switch (name) {
263 			int mask, *ok;
264 
265 		case SO_HEADERS_ON_INPUT:
266 			mask = NSP_RAWIN;
267 			goto set_head;
268 
269 		case SO_HEADERS_ON_OUTPUT:
270 			mask = NSP_RAWOUT;
271 		set_head:
272 			if (value && *value) {
273 				ok = mtod(*value, int *);
274 				if (*ok)
275 					nsp->nsp_flags |= mask;
276 				else
277 					nsp->nsp_flags &= ~mask;
278 			} else error = EINVAL;
279 			break;
280 
281 		case SO_DEFAULT_HEADERS:
282 			{
283 				register struct idp *idp
284 				    = mtod(*value, struct idp *);
285 				nsp->nsp_dpt = idp->idp_pt;
286 			}
287 #ifdef NSIP
288 			break;
289 
290 		case SO_NSIP_ROUTE:
291 			error = nsip_route(*value);
292 #endif NSIP
293 		}
294 		if (value && *value)
295 			m_freem(*value);
296 		break;
297 	}
298 	return (error);
299 }
300 
301 /*ARGSUSED*/
302 idp_usrreq(so, req, m, nam, rights)
303 	struct socket *so;
304 	int req;
305 	struct mbuf *m, *nam, *rights;
306 {
307 	struct nspcb *nsp = sotonspcb(so);
308 	int error = 0;
309 
310 	if (req == PRU_CONTROL)
311                 return (ns_control(so, (int)m, (caddr_t)nam,
312 			(struct ifnet *)rights));
313 	if (rights && rights->m_len) {
314 		error = EINVAL;
315 		goto release;
316 	}
317 	if (nsp == NULL && req != PRU_ATTACH) {
318 		error = EINVAL;
319 		goto release;
320 	}
321 	switch (req) {
322 
323 	case PRU_ATTACH:
324 		if (nsp != NULL) {
325 			error = EINVAL;
326 			break;
327 		}
328 		error = ns_pcballoc(so, &nspcb);
329 		if (error)
330 			break;
331 		error = soreserve(so, 2048, 2048);
332 		if (error)
333 			break;
334 		break;
335 
336 	case PRU_DETACH:
337 		if (nsp == NULL) {
338 			error = ENOTCONN;
339 			break;
340 		}
341 		ns_pcbdetach(nsp);
342 		break;
343 
344 	case PRU_BIND:
345 		error = ns_pcbbind(nsp, nam);
346 		break;
347 
348 	case PRU_LISTEN:
349 		error = EOPNOTSUPP;
350 		break;
351 
352 	case PRU_CONNECT:
353 		if (!ns_nullhost(nsp->nsp_faddr)) {
354 			error = EISCONN;
355 			break;
356 		}
357 		error = ns_pcbconnect(nsp, nam);
358 		if (error == 0)
359 			soisconnected(so);
360 		break;
361 
362 	case PRU_CONNECT2:
363 		error = EOPNOTSUPP;
364 		break;
365 
366 	case PRU_ACCEPT:
367 		error = EOPNOTSUPP;
368 		break;
369 
370 	case PRU_DISCONNECT:
371 		if (ns_nullhost(nsp->nsp_faddr)) {
372 			error = ENOTCONN;
373 			break;
374 		}
375 		ns_pcbdisconnect(nsp);
376 		soisdisconnected(so);
377 		break;
378 
379 	case PRU_SHUTDOWN:
380 		socantsendmore(so);
381 		break;
382 
383 	case PRU_SEND:
384 	{
385 		struct ns_addr laddr;
386 		int s;
387 
388 		if (nam) {
389 			laddr = nsp->nsp_laddr;
390 			if (!ns_nullhost(nsp->nsp_faddr)) {
391 				error = EISCONN;
392 				break;
393 			}
394 			/*
395 			 * Must block input while temporarily connected.
396 			 */
397 			s = splnet();
398 			error = ns_pcbconnect(nsp, nam);
399 			if (error) {
400 				splx(s);
401 				break;
402 			}
403 		} else {
404 			if (ns_nullhost(nsp->nsp_faddr)) {
405 				error = ENOTCONN;
406 				break;
407 			}
408 		}
409 		error = idp_output(nsp, m);
410 		m = NULL;
411 		if (nam) {
412 			ns_pcbdisconnect(nsp);
413 			splx(s);
414 			nsp->nsp_laddr.x_host = laddr.x_host;
415 			nsp->nsp_laddr.x_port = laddr.x_port;
416 		}
417 	}
418 		break;
419 
420 	case PRU_ABORT:
421 		ns_pcbdetach(nsp);
422 		sofree(so);
423 		soisdisconnected(so);
424 		break;
425 
426 	case PRU_SOCKADDR:
427 		ns_setsockaddr(nsp, nam);
428 		break;
429 
430 	case PRU_PEERADDR:
431 		ns_setpeeraddr(nsp, nam);
432 		break;
433 
434 	case PRU_SENSE:
435 		/*
436 		 * stat: don't bother with a blocksize.
437 		 */
438 		return (0);
439 
440 	case PRU_SENDOOB:
441 	case PRU_FASTTIMO:
442 	case PRU_SLOWTIMO:
443 	case PRU_PROTORCV:
444 	case PRU_PROTOSEND:
445 		error =  EOPNOTSUPP;
446 		break;
447 
448 	case PRU_CONTROL:
449 	case PRU_RCVD:
450 	case PRU_RCVOOB:
451 		return (EOPNOTSUPP);	/* do not free mbuf's */
452 
453 	default:
454 		panic("idp_usrreq");
455 	}
456 release:
457 	if (m != NULL)
458 		m_freem(m);
459 	return (error);
460 }
461 /*ARGSUSED*/
462 idp_raw_usrreq(so, req, m, nam, rights)
463 	struct socket *so;
464 	int req;
465 	struct mbuf *m, *nam, *rights;
466 {
467 	int error = 0;
468 	struct nspcb *nsp = sotonspcb(so);
469 	extern struct nspcb nsrawpcb;
470 
471 	switch (req) {
472 
473 	case PRU_ATTACH:
474 
475 		if (!suser() || (nsp != NULL)) {
476 			error = EINVAL;
477 			break;
478 		}
479 		error = ns_pcballoc(so, &nsrawpcb);
480 		if (error)
481 			break;
482 		error = soreserve(so, 2048, 2048);
483 		if (error)
484 			break;
485 		nsp = sotonspcb(so);
486 		nsp->nsp_faddr.x_host = ns_broadhost;
487 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
488 		break;
489 	default:
490 		error = idp_usrreq(so, req, m, nam, rights);
491 	}
492 	return (error);
493 }
494 
495