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