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