xref: /csrg-svn/sys/netns/idp_usrreq.c (revision 25335)
1 /*
2  * Copyright (c) 1984,1985 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	6.11 (Berkeley) 10/30/85
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_netof(idp->idp_sna)==0 && 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);
166 		m->m_len = sizeof (struct idp);
167 		m->m_next = m0;
168 		idp = mtod(m, struct idp *);
169 		idp->idp_tc = 0;
170 		idp->idp_pt = nsp->nsp_dpt;
171 		idp->idp_sna = nsp->nsp_laddr;
172 		idp->idp_dna = nsp->nsp_faddr;
173 		len += sizeof (struct idp);
174 	}
175 
176 	idp->idp_len = htons((u_short)len);
177 
178 	if (idpcksum) {
179 		idp->idp_sum = 0;
180 		len = ((len - 1) | 1) + 1;
181 		idp->idp_sum = ns_cksum(m, len);
182 	} else
183 		idp->idp_sum = 0xffff;
184 
185 	/*
186 	 * Output datagram.
187 	 */
188 	so = nsp->nsp_socket;
189 	if (so->so_options & SO_DONTROUTE)
190 		return (ns_output(m, (struct route *)0,
191 		    (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
192 	/*
193 	 * Use cached route for previous datagram if
194 	 * possible.  If the previous net was the same
195 	 * and the interface was a broadcast medium, or
196 	 * if the previous destination was identical,
197 	 * then we are ok.
198 	 *
199 	 * NB: We don't handle broadcasts because that
200 	 *     would require 3 subroutine calls.
201 	 */
202 	ro = &nsp->nsp_route;
203 #ifdef ancient_history
204 	/*
205 	 * I think that this will all be handled in ns_pcbconnect!
206 	 */
207 	if (ro->ro_rt) {
208 		if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
209 			/*
210 			 * This assumes we have no GH type routes
211 			 */
212 			if (ro->ro_rt->rt_flags & RTF_HOST) {
213 				if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
214 					goto re_route;
215 
216 			}
217 			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
218 				register struct ns_addr *dst =
219 						&satons_addr(ro->ro_dst);
220 				dst->x_host = idp->idp_dna.x_host;
221 			}
222 			/*
223 			 * Otherwise, we go through the same gateway
224 			 * and dst is already set up.
225 			 */
226 		} else {
227 		re_route:
228 			RTFREE(ro->ro_rt);
229 			ro->ro_rt = (struct rtentry *)0;
230 		}
231 	}
232 	nsp->nsp_lastdst = idp->idp_dna;
233 #endif ancient_history
234 	if (noIdpRoute) ro = 0;
235 	return (ns_output(m, ro, so->so_options & SO_BROADCAST));
236 }
237 /* ARGSUSED */
238 idp_ctloutput(req, so, level, name, value)
239 	int req, level;
240 	struct socket *so;
241 	int name;
242 	struct mbuf **value;
243 {
244 	register struct mbuf *m;
245 	struct nspcb *nsp = sotonspcb(so);
246 	int mask, error = 0;
247 	extern long ns_pexseq;
248 
249 	if (nsp == NULL)
250 		return (EINVAL);
251 
252 	switch (req) {
253 
254 	case PRCO_GETOPT:
255 		if (value==NULL)
256 			return (EINVAL);
257 		m = m_get(M_DONTWAIT, MT_DATA);
258 		if (m==NULL)
259 			return (ENOBUFS);
260 		switch (name) {
261 
262 		case SO_ALL_PACKETS:
263 			mask = NSP_ALL_PACKETS;
264 			goto get_flags;
265 
266 		case SO_HEADERS_ON_INPUT:
267 			mask = NSP_RAWIN;
268 			goto get_flags;
269 
270 		case SO_HEADERS_ON_OUTPUT:
271 			mask = NSP_RAWOUT;
272 		get_flags:
273 			m->m_len = sizeof(short);
274 			m->m_off = MMAXOFF - sizeof(short);
275 			*mtod(m, short *) = nsp->nsp_flags & mask;
276 			break;
277 
278 		case SO_DEFAULT_HEADERS:
279 			m->m_len = sizeof(struct idp);
280 			m->m_off = MMAXOFF - sizeof(struct idp);
281 			{
282 				register struct idp *idp = mtod(m, struct idp *);
283 				idp->idp_len = 0;
284 				idp->idp_sum = 0;
285 				idp->idp_tc = 0;
286 				idp->idp_pt = nsp->nsp_dpt;
287 				idp->idp_dna = nsp->nsp_faddr;
288 				idp->idp_sna = nsp->nsp_laddr;
289 			}
290 			break;
291 
292 		case SO_SEQNO:
293 			m->m_len = sizeof(long);
294 			m->m_off = MMAXOFF - sizeof(long);
295 			*mtod(m, long *) = ns_pexseq++;
296 			break;
297 
298 		default:
299 			error = EINVAL;
300 		}
301 		*value = m;
302 		break;
303 
304 	case PRCO_SETOPT:
305 		switch (name) {
306 			int *ok;
307 
308 		case SO_ALL_PACKETS:
309 			mask = NSP_ALL_PACKETS;
310 			goto set_head;
311 
312 		case SO_HEADERS_ON_INPUT:
313 			mask = NSP_RAWIN;
314 			goto set_head;
315 
316 		case SO_HEADERS_ON_OUTPUT:
317 			mask = NSP_RAWOUT;
318 		set_head:
319 			if (value && *value) {
320 				ok = mtod(*value, int *);
321 				if (*ok)
322 					nsp->nsp_flags |= mask;
323 				else
324 					nsp->nsp_flags &= ~mask;
325 			} else error = EINVAL;
326 			break;
327 
328 		case SO_DEFAULT_HEADERS:
329 			{
330 				register struct idp *idp
331 				    = mtod(*value, struct idp *);
332 				nsp->nsp_dpt = idp->idp_pt;
333 			}
334 			break;
335 #ifdef NSIP
336 
337 		case SO_NSIP_ROUTE:
338 			error = nsip_route(*value);
339 			break;
340 #endif NSIP
341 		default:
342 			error = EINVAL;
343 		}
344 		if (value && *value)
345 			m_freem(*value);
346 		break;
347 	}
348 	return (error);
349 }
350 
351 /*ARGSUSED*/
352 idp_usrreq(so, req, m, nam, rights)
353 	struct socket *so;
354 	int req;
355 	struct mbuf *m, *nam, *rights;
356 {
357 	struct nspcb *nsp = sotonspcb(so);
358 	int error = 0;
359 
360 	if (req == PRU_CONTROL)
361                 return (ns_control(so, (int)m, (caddr_t)nam,
362 			(struct ifnet *)rights));
363 	if (rights && rights->m_len) {
364 		error = EINVAL;
365 		goto release;
366 	}
367 	if (nsp == NULL && req != PRU_ATTACH) {
368 		error = EINVAL;
369 		goto release;
370 	}
371 	switch (req) {
372 
373 	case PRU_ATTACH:
374 		if (nsp != NULL) {
375 			error = EINVAL;
376 			break;
377 		}
378 		error = ns_pcballoc(so, &nspcb);
379 		if (error)
380 			break;
381 		error = soreserve(so, 2048, 2048);
382 		if (error)
383 			break;
384 		break;
385 
386 	case PRU_DETACH:
387 		if (nsp == NULL) {
388 			error = ENOTCONN;
389 			break;
390 		}
391 		ns_pcbdetach(nsp);
392 		break;
393 
394 	case PRU_BIND:
395 		error = ns_pcbbind(nsp, nam);
396 		break;
397 
398 	case PRU_LISTEN:
399 		error = EOPNOTSUPP;
400 		break;
401 
402 	case PRU_CONNECT:
403 		if (!ns_nullhost(nsp->nsp_faddr)) {
404 			error = EISCONN;
405 			break;
406 		}
407 		error = ns_pcbconnect(nsp, nam);
408 		if (error == 0)
409 			soisconnected(so);
410 		break;
411 
412 	case PRU_CONNECT2:
413 		error = EOPNOTSUPP;
414 		break;
415 
416 	case PRU_ACCEPT:
417 		error = EOPNOTSUPP;
418 		break;
419 
420 	case PRU_DISCONNECT:
421 		if (ns_nullhost(nsp->nsp_faddr)) {
422 			error = ENOTCONN;
423 			break;
424 		}
425 		ns_pcbdisconnect(nsp);
426 		soisdisconnected(so);
427 		break;
428 
429 	case PRU_SHUTDOWN:
430 		socantsendmore(so);
431 		break;
432 
433 	case PRU_SEND:
434 	{
435 		struct ns_addr laddr;
436 		int s;
437 
438 		if (nam) {
439 			laddr = nsp->nsp_laddr;
440 			if (!ns_nullhost(nsp->nsp_faddr)) {
441 				error = EISCONN;
442 				break;
443 			}
444 			/*
445 			 * Must block input while temporarily connected.
446 			 */
447 			s = splnet();
448 			error = ns_pcbconnect(nsp, nam);
449 			if (error) {
450 				splx(s);
451 				break;
452 			}
453 		} else {
454 			if (ns_nullhost(nsp->nsp_faddr)) {
455 				error = ENOTCONN;
456 				break;
457 			}
458 		}
459 		error = idp_output(nsp, m);
460 		m = NULL;
461 		if (nam) {
462 			ns_pcbdisconnect(nsp);
463 			splx(s);
464 			nsp->nsp_laddr.x_host = laddr.x_host;
465 			nsp->nsp_laddr.x_port = laddr.x_port;
466 		}
467 	}
468 		break;
469 
470 	case PRU_ABORT:
471 		ns_pcbdetach(nsp);
472 		sofree(so);
473 		soisdisconnected(so);
474 		break;
475 
476 	case PRU_SOCKADDR:
477 		ns_setsockaddr(nsp, nam);
478 		break;
479 
480 	case PRU_PEERADDR:
481 		ns_setpeeraddr(nsp, nam);
482 		break;
483 
484 	case PRU_SENSE:
485 		/*
486 		 * stat: don't bother with a blocksize.
487 		 */
488 		return (0);
489 
490 	case PRU_SENDOOB:
491 	case PRU_FASTTIMO:
492 	case PRU_SLOWTIMO:
493 	case PRU_PROTORCV:
494 	case PRU_PROTOSEND:
495 		error =  EOPNOTSUPP;
496 		break;
497 
498 	case PRU_CONTROL:
499 	case PRU_RCVD:
500 	case PRU_RCVOOB:
501 		return (EOPNOTSUPP);	/* do not free mbuf's */
502 
503 	default:
504 		panic("idp_usrreq");
505 	}
506 release:
507 	if (m != NULL)
508 		m_freem(m);
509 	return (error);
510 }
511 /*ARGSUSED*/
512 idp_raw_usrreq(so, req, m, nam, rights)
513 	struct socket *so;
514 	int req;
515 	struct mbuf *m, *nam, *rights;
516 {
517 	int error = 0;
518 	struct nspcb *nsp = sotonspcb(so);
519 	extern struct nspcb nsrawpcb;
520 
521 	switch (req) {
522 
523 	case PRU_ATTACH:
524 
525 		if (!suser() || (nsp != NULL)) {
526 			error = EINVAL;
527 			break;
528 		}
529 		error = ns_pcballoc(so, &nsrawpcb);
530 		if (error)
531 			break;
532 		error = soreserve(so, 2048, 2048);
533 		if (error)
534 			break;
535 		nsp = sotonspcb(so);
536 		nsp->nsp_faddr.x_host = ns_broadhost;
537 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
538 		break;
539 	default:
540 		error = idp_usrreq(so, req, m, nam, rights);
541 	}
542 	return (error);
543 }
544 
545