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