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