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