xref: /csrg-svn/sys/netns/idp_usrreq.c (revision 25042)
1 /*
2  * Copyright (c) 1982 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.10 (Berkeley) 09/26/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 		}
297 		*value = m;
298 		break;
299 
300 	case PRCO_SETOPT:
301 		switch (name) {
302 			int *ok;
303 
304 		case SO_ALL_PACKETS:
305 			mask = NSP_ALL_PACKETS;
306 			goto set_head;
307 
308 		case SO_HEADERS_ON_INPUT:
309 			mask = NSP_RAWIN;
310 			goto set_head;
311 
312 		case SO_HEADERS_ON_OUTPUT:
313 			mask = NSP_RAWOUT;
314 		set_head:
315 			if (value && *value) {
316 				ok = mtod(*value, int *);
317 				if (*ok)
318 					nsp->nsp_flags |= mask;
319 				else
320 					nsp->nsp_flags &= ~mask;
321 			} else error = EINVAL;
322 			break;
323 
324 		case SO_DEFAULT_HEADERS:
325 			{
326 				register struct idp *idp
327 				    = mtod(*value, struct idp *);
328 				nsp->nsp_dpt = idp->idp_pt;
329 			}
330 #ifdef NSIP
331 			break;
332 
333 		case SO_NSIP_ROUTE:
334 			error = nsip_route(*value);
335 #endif NSIP
336 		}
337 		if (value && *value)
338 			m_freem(*value);
339 		break;
340 	}
341 	return (error);
342 }
343 
344 /*ARGSUSED*/
345 idp_usrreq(so, req, m, nam, rights)
346 	struct socket *so;
347 	int req;
348 	struct mbuf *m, *nam, *rights;
349 {
350 	struct nspcb *nsp = sotonspcb(so);
351 	int error = 0;
352 
353 	if (req == PRU_CONTROL)
354                 return (ns_control(so, (int)m, (caddr_t)nam,
355 			(struct ifnet *)rights));
356 	if (rights && rights->m_len) {
357 		error = EINVAL;
358 		goto release;
359 	}
360 	if (nsp == NULL && req != PRU_ATTACH) {
361 		error = EINVAL;
362 		goto release;
363 	}
364 	switch (req) {
365 
366 	case PRU_ATTACH:
367 		if (nsp != NULL) {
368 			error = EINVAL;
369 			break;
370 		}
371 		error = ns_pcballoc(so, &nspcb);
372 		if (error)
373 			break;
374 		error = soreserve(so, 2048, 2048);
375 		if (error)
376 			break;
377 		break;
378 
379 	case PRU_DETACH:
380 		if (nsp == NULL) {
381 			error = ENOTCONN;
382 			break;
383 		}
384 		ns_pcbdetach(nsp);
385 		break;
386 
387 	case PRU_BIND:
388 		error = ns_pcbbind(nsp, nam);
389 		break;
390 
391 	case PRU_LISTEN:
392 		error = EOPNOTSUPP;
393 		break;
394 
395 	case PRU_CONNECT:
396 		if (!ns_nullhost(nsp->nsp_faddr)) {
397 			error = EISCONN;
398 			break;
399 		}
400 		error = ns_pcbconnect(nsp, nam);
401 		if (error == 0)
402 			soisconnected(so);
403 		break;
404 
405 	case PRU_CONNECT2:
406 		error = EOPNOTSUPP;
407 		break;
408 
409 	case PRU_ACCEPT:
410 		error = EOPNOTSUPP;
411 		break;
412 
413 	case PRU_DISCONNECT:
414 		if (ns_nullhost(nsp->nsp_faddr)) {
415 			error = ENOTCONN;
416 			break;
417 		}
418 		ns_pcbdisconnect(nsp);
419 		soisdisconnected(so);
420 		break;
421 
422 	case PRU_SHUTDOWN:
423 		socantsendmore(so);
424 		break;
425 
426 	case PRU_SEND:
427 	{
428 		struct ns_addr laddr;
429 		int s;
430 
431 		if (nam) {
432 			laddr = nsp->nsp_laddr;
433 			if (!ns_nullhost(nsp->nsp_faddr)) {
434 				error = EISCONN;
435 				break;
436 			}
437 			/*
438 			 * Must block input while temporarily connected.
439 			 */
440 			s = splnet();
441 			error = ns_pcbconnect(nsp, nam);
442 			if (error) {
443 				splx(s);
444 				break;
445 			}
446 		} else {
447 			if (ns_nullhost(nsp->nsp_faddr)) {
448 				error = ENOTCONN;
449 				break;
450 			}
451 		}
452 		error = idp_output(nsp, m);
453 		m = NULL;
454 		if (nam) {
455 			ns_pcbdisconnect(nsp);
456 			splx(s);
457 			nsp->nsp_laddr.x_host = laddr.x_host;
458 			nsp->nsp_laddr.x_port = laddr.x_port;
459 		}
460 	}
461 		break;
462 
463 	case PRU_ABORT:
464 		ns_pcbdetach(nsp);
465 		sofree(so);
466 		soisdisconnected(so);
467 		break;
468 
469 	case PRU_SOCKADDR:
470 		ns_setsockaddr(nsp, nam);
471 		break;
472 
473 	case PRU_PEERADDR:
474 		ns_setpeeraddr(nsp, nam);
475 		break;
476 
477 	case PRU_SENSE:
478 		/*
479 		 * stat: don't bother with a blocksize.
480 		 */
481 		return (0);
482 
483 	case PRU_SENDOOB:
484 	case PRU_FASTTIMO:
485 	case PRU_SLOWTIMO:
486 	case PRU_PROTORCV:
487 	case PRU_PROTOSEND:
488 		error =  EOPNOTSUPP;
489 		break;
490 
491 	case PRU_CONTROL:
492 	case PRU_RCVD:
493 	case PRU_RCVOOB:
494 		return (EOPNOTSUPP);	/* do not free mbuf's */
495 
496 	default:
497 		panic("idp_usrreq");
498 	}
499 release:
500 	if (m != NULL)
501 		m_freem(m);
502 	return (error);
503 }
504 /*ARGSUSED*/
505 idp_raw_usrreq(so, req, m, nam, rights)
506 	struct socket *so;
507 	int req;
508 	struct mbuf *m, *nam, *rights;
509 {
510 	int error = 0;
511 	struct nspcb *nsp = sotonspcb(so);
512 	extern struct nspcb nsrawpcb;
513 
514 	switch (req) {
515 
516 	case PRU_ATTACH:
517 
518 		if (!suser() || (nsp != NULL)) {
519 			error = EINVAL;
520 			break;
521 		}
522 		error = ns_pcballoc(so, &nsrawpcb);
523 		if (error)
524 			break;
525 		error = soreserve(so, 2048, 2048);
526 		if (error)
527 			break;
528 		nsp = sotonspcb(so);
529 		nsp->nsp_faddr.x_host = ns_broadhost;
530 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
531 		break;
532 	default:
533 		error = idp_usrreq(so, req, m, nam, rights);
534 	}
535 	return (error);
536 }
537 
538