xref: /original-bsd/sys/netns/idp_usrreq.c (revision caa496f3)
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.9 (Berkeley) 05/14/90
18  */
19 
20 #include "param.h"
21 #include "user.h"
22 #include "malloc.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 = { sizeof(idp_ns), AF_NS };
45 
46 /*
47  *  This may also be called for raw listeners.
48  */
49 idp_input(m, nsp)
50 	struct mbuf *m;
51 	register struct nspcb *nsp;
52 {
53 	register struct idp *idp = mtod(m, struct idp *);
54 	struct ifnet *ifp = m->m_pkthdr.rcvif;
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 *ifa;
65 
66 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
67 			if (ifa->ifa_addr->sa_family == AF_NS) {
68 				idp_ns.sns_addr.x_net =
69 					IA_SNS(ifa)->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_pkthdr.len -= sizeof (struct idp);
78 		m->m_data += sizeof (struct idp);
79 	}
80 	if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
81 	    m, (struct mbuf *)0) == 0)
82 		goto bad;
83 	sorwakeup(nsp->nsp_socket);
84 	return;
85 bad:
86 	m_freem(m);
87 }
88 
89 idp_abort(nsp)
90 	struct nspcb *nsp;
91 {
92 	struct socket *so = nsp->nsp_socket;
93 
94 	ns_pcbdisconnect(nsp);
95 	soisdisconnected(so);
96 }
97 /*
98  * Drop connection, reporting
99  * the specified error.
100  */
101 struct nspcb *
102 idp_drop(nsp, errno)
103 	register struct nspcb *nsp;
104 	int errno;
105 {
106 	struct socket *so = nsp->nsp_socket;
107 
108 	/*
109 	 * someday, in the xerox world
110 	 * we will generate error protocol packets
111 	 * announcing that the socket has gone away.
112 	 */
113 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
114 		tp->t_state = TCPS_CLOSED;
115 		(void) tcp_output(tp);
116 	}*/
117 	so->so_error = errno;
118 	ns_pcbdisconnect(nsp);
119 	soisdisconnected(so);
120 }
121 
122 int noIdpRoute;
123 idp_output(nsp, m0)
124 	struct nspcb *nsp;
125 	struct mbuf *m0;
126 {
127 	register struct mbuf *m;
128 	register struct idp *idp;
129 	register struct socket *so;
130 	register int len = 0;
131 	register struct route *ro;
132 	struct mbuf *mprev;
133 	extern int idpcksum;
134 
135 	/*
136 	 * Calculate data length.
137 	 */
138 	for (m = m0; m; m = m->m_next) {
139 		mprev = m;
140 		len += m->m_len;
141 	}
142 	/*
143 	 * Make sure packet is actually of even length.
144 	 */
145 
146 	if (len & 1) {
147 		m = mprev;
148 		if ((m->m_flags & M_EXT) == 0 &&
149 			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
150 			m->m_len++;
151 		} else {
152 			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
153 
154 			if (m1 == 0) {
155 				m_freem(m0);
156 				return (ENOBUFS);
157 			}
158 			m1->m_len = 1;
159 			* mtod(m1, char *) = 0;
160 			m->m_next = m1;
161 		}
162 		m0->m_pkthdr.len++;
163 	}
164 
165 	/*
166 	 * Fill in mbuf with extended IDP header
167 	 * and addresses and length put into network format.
168 	 */
169 	m = m0;
170 	if (nsp->nsp_flags & NSP_RAWOUT) {
171 		idp = mtod(m, struct idp *);
172 	} else {
173 		M_PREPEND(m, sizeof (struct idp), M_DONTWAIT);
174 		if (m == 0)
175 			return (ENOBUFS);
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 			*mtod(m, short *) = nsp->nsp_flags & mask;
283 			break;
284 
285 		case SO_DEFAULT_HEADERS:
286 			m->m_len = sizeof(struct idp);
287 			{
288 				register struct idp *idp = mtod(m, struct idp *);
289 				idp->idp_len = 0;
290 				idp->idp_sum = 0;
291 				idp->idp_tc = 0;
292 				idp->idp_pt = nsp->nsp_dpt;
293 				idp->idp_dna = nsp->nsp_faddr;
294 				idp->idp_sna = nsp->nsp_laddr;
295 			}
296 			break;
297 
298 		case SO_SEQNO:
299 			m->m_len = sizeof(long);
300 			*mtod(m, long *) = ns_pexseq++;
301 			break;
302 
303 		default:
304 			error = EINVAL;
305 		}
306 		*value = m;
307 		break;
308 
309 	case PRCO_SETOPT:
310 		switch (name) {
311 			int *ok;
312 
313 		case SO_ALL_PACKETS:
314 			mask = NSP_ALL_PACKETS;
315 			goto set_head;
316 
317 		case SO_HEADERS_ON_INPUT:
318 			mask = NSP_RAWIN;
319 			goto set_head;
320 
321 		case SO_HEADERS_ON_OUTPUT:
322 			mask = NSP_RAWOUT;
323 		set_head:
324 			if (value && *value) {
325 				ok = mtod(*value, int *);
326 				if (*ok)
327 					nsp->nsp_flags |= mask;
328 				else
329 					nsp->nsp_flags &= ~mask;
330 			} else error = EINVAL;
331 			break;
332 
333 		case SO_DEFAULT_HEADERS:
334 			{
335 				register struct idp *idp
336 				    = mtod(*value, struct idp *);
337 				nsp->nsp_dpt = idp->idp_pt;
338 			}
339 			break;
340 #ifdef NSIP
341 
342 		case SO_NSIP_ROUTE:
343 			error = nsip_route(*value);
344 			break;
345 #endif NSIP
346 		default:
347 			error = EINVAL;
348 		}
349 		if (value && *value)
350 			m_freem(*value);
351 		break;
352 	}
353 	return (error);
354 }
355 
356 /*ARGSUSED*/
357 idp_usrreq(so, req, m, nam, control)
358 	struct socket *so;
359 	int req;
360 	struct mbuf *m, *nam, *control;
361 {
362 	struct nspcb *nsp = sotonspcb(so);
363 	int error = 0;
364 
365 	if (req == PRU_CONTROL)
366                 return (ns_control(so, (int)m, (caddr_t)nam,
367 			(struct ifnet *)control));
368 	if (control && control->m_len) {
369 		error = EINVAL;
370 		goto release;
371 	}
372 	if (nsp == NULL && req != PRU_ATTACH) {
373 		error = EINVAL;
374 		goto release;
375 	}
376 	switch (req) {
377 
378 	case PRU_ATTACH:
379 		if (nsp != NULL) {
380 			error = EINVAL;
381 			break;
382 		}
383 		error = ns_pcballoc(so, &nspcb);
384 		if (error)
385 			break;
386 		error = soreserve(so, (u_long) 2048, (u_long) 2048);
387 		if (error)
388 			break;
389 		break;
390 
391 	case PRU_DETACH:
392 		if (nsp == NULL) {
393 			error = ENOTCONN;
394 			break;
395 		}
396 		ns_pcbdetach(nsp);
397 		break;
398 
399 	case PRU_BIND:
400 		error = ns_pcbbind(nsp, nam);
401 		break;
402 
403 	case PRU_LISTEN:
404 		error = EOPNOTSUPP;
405 		break;
406 
407 	case PRU_CONNECT:
408 		if (!ns_nullhost(nsp->nsp_faddr)) {
409 			error = EISCONN;
410 			break;
411 		}
412 		error = ns_pcbconnect(nsp, nam);
413 		if (error == 0)
414 			soisconnected(so);
415 		break;
416 
417 	case PRU_CONNECT2:
418 		error = EOPNOTSUPP;
419 		break;
420 
421 	case PRU_ACCEPT:
422 		error = EOPNOTSUPP;
423 		break;
424 
425 	case PRU_DISCONNECT:
426 		if (ns_nullhost(nsp->nsp_faddr)) {
427 			error = ENOTCONN;
428 			break;
429 		}
430 		ns_pcbdisconnect(nsp);
431 		soisdisconnected(so);
432 		break;
433 
434 	case PRU_SHUTDOWN:
435 		socantsendmore(so);
436 		break;
437 
438 	case PRU_SEND:
439 	{
440 		struct ns_addr laddr;
441 		int s;
442 
443 		if (nam) {
444 			laddr = nsp->nsp_laddr;
445 			if (!ns_nullhost(nsp->nsp_faddr)) {
446 				error = EISCONN;
447 				break;
448 			}
449 			/*
450 			 * Must block input while temporarily connected.
451 			 */
452 			s = splnet();
453 			error = ns_pcbconnect(nsp, nam);
454 			if (error) {
455 				splx(s);
456 				break;
457 			}
458 		} else {
459 			if (ns_nullhost(nsp->nsp_faddr)) {
460 				error = ENOTCONN;
461 				break;
462 			}
463 		}
464 		error = idp_output(nsp, m);
465 		m = NULL;
466 		if (nam) {
467 			ns_pcbdisconnect(nsp);
468 			splx(s);
469 			nsp->nsp_laddr.x_host = laddr.x_host;
470 			nsp->nsp_laddr.x_port = laddr.x_port;
471 		}
472 	}
473 		break;
474 
475 	case PRU_ABORT:
476 		ns_pcbdetach(nsp);
477 		sofree(so);
478 		soisdisconnected(so);
479 		break;
480 
481 	case PRU_SOCKADDR:
482 		ns_setsockaddr(nsp, nam);
483 		break;
484 
485 	case PRU_PEERADDR:
486 		ns_setpeeraddr(nsp, nam);
487 		break;
488 
489 	case PRU_SENSE:
490 		/*
491 		 * stat: don't bother with a blocksize.
492 		 */
493 		return (0);
494 
495 	case PRU_SENDOOB:
496 	case PRU_FASTTIMO:
497 	case PRU_SLOWTIMO:
498 	case PRU_PROTORCV:
499 	case PRU_PROTOSEND:
500 		error =  EOPNOTSUPP;
501 		break;
502 
503 	case PRU_CONTROL:
504 	case PRU_RCVD:
505 	case PRU_RCVOOB:
506 		return (EOPNOTSUPP);	/* do not free mbuf's */
507 
508 	default:
509 		panic("idp_usrreq");
510 	}
511 release:
512 	if (control != NULL)
513 		m_freem(control);
514 	if (m != NULL)
515 		m_freem(m);
516 	return (error);
517 }
518 /*ARGSUSED*/
519 idp_raw_usrreq(so, req, m, nam, control)
520 	struct socket *so;
521 	int req;
522 	struct mbuf *m, *nam, *control;
523 {
524 	int error = 0;
525 	struct nspcb *nsp = sotonspcb(so);
526 	extern struct nspcb nsrawpcb;
527 
528 	switch (req) {
529 
530 	case PRU_ATTACH:
531 
532 		if (suser(u.u_cred, &u.u_acflag) || (nsp != NULL)) {
533 			error = EINVAL;
534 			break;
535 		}
536 		error = ns_pcballoc(so, &nsrawpcb);
537 		if (error)
538 			break;
539 		error = soreserve(so, (u_long) 2048, (u_long) 2048);
540 		if (error)
541 			break;
542 		nsp = sotonspcb(so);
543 		nsp->nsp_faddr.x_host = ns_broadhost;
544 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
545 		break;
546 	default:
547 		error = idp_usrreq(so, req, m, nam, control);
548 	}
549 	return (error);
550 }
551 
552