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