xref: /csrg-svn/sys/netns/idp_usrreq.c (revision 24611)
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.8 (Berkeley) 09/06/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) {
53 		register struct ifaddr *ia;
54 
55 		for (ia = ifp->if_addrlist; 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 idp_output(nsp, m0)
111 	struct nspcb *nsp;
112 	struct mbuf *m0;
113 {
114 	register struct mbuf *m;
115 	register struct idp *idp;
116 	register struct socket *so;
117 	register int len = 0;
118 	register struct route *ro;
119 	struct mbuf *mprev;
120 	extern int idpcksum;
121 
122 	/*
123 	 * Calculate data length.
124 	 */
125 	for (m = m0; m; m = m->m_next) {
126 		mprev = m;
127 		len += m->m_len;
128 	}
129 	/*
130 	 * Make sure packet is actually of even length.
131 	 */
132 
133 	if (len & 1) {
134 		m = mprev;
135 		if (m->m_len + m->m_off < MMAXOFF) {
136 			m->m_len++;
137 		} else {
138 			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
139 
140 			if (m1 == 0) {
141 				m_freem(m0);
142 				return (ENOBUFS);
143 			}
144 			m1->m_len = 1;
145 			m1->m_off = MMAXOFF - 1;
146 			* mtod(m1, char *) = 0;
147 			m->m_next = m1;
148 		}
149 	}
150 
151 	/*
152 	 * Fill in mbuf with extended IDP header
153 	 * and addresses and length put into network format.
154 	 */
155 	if (nsp->nsp_flags & NSP_RAWOUT) {
156 		m = m0;
157 		idp = mtod(m, struct idp *);
158 	} else {
159 		m = m_get(M_DONTWAIT, MT_HEADER);
160 		if (m == 0) {
161 			m_freem(m0);
162 			return (ENOBUFS);
163 		}
164 		m->m_off = MMAXOFF - sizeof (struct idp);
165 		m->m_len = sizeof (struct idp);
166 		m->m_next = m0;
167 		idp = mtod(m, struct idp *);
168 		idp->idp_tc = 0;
169 		idp->idp_pt = nsp->nsp_dpt;
170 		idp->idp_sna = nsp->nsp_laddr;
171 		idp->idp_dna = nsp->nsp_faddr;
172 		len += sizeof (struct idp);
173 	}
174 
175 	idp->idp_len = htons((u_short)len);
176 
177 	if (idpcksum) {
178 		idp->idp_sum = 0;
179 		len = ((len - 1) | 1) + 1;
180 		idp->idp_sum = ns_cksum(m, len);
181 	} else
182 		idp->idp_sum = 0xffff;
183 
184 	/*
185 	 * Output datagram.
186 	 */
187 	so = nsp->nsp_socket;
188 	if (so->so_options & SO_DONTROUTE)
189 		return (ns_output(m, (struct route *)0,
190 		    (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
191 	/*
192 	 * Use cached route for previous datagram if
193 	 * this is also to the same destination.
194 	 *
195 	 * NB: We don't handle broadcasts because that
196 	 *     would require 3 subroutine calls.
197 	 */
198 	ro = &nsp->nsp_route;
199 	if (ro->ro_rt &&
200 		((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) &&
201 		!(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) {
202 		RTFREE(ro->ro_rt);
203 		ro->ro_rt = (struct rtentry *)0;
204 		nsp->nsp_lastnet = idp->idp_dna.x_net;
205 	}
206 	return (ns_output(m, ro, so->so_options & SO_BROADCAST));
207 }
208 /* ARGSUSED */
209 idp_ctloutput(req, so, level, name, value)
210 	int req, level;
211 	struct socket *so;
212 	int name;
213 	struct mbuf **value;
214 {
215 	register struct mbuf *m;
216 	struct nspcb *nsp = sotonspcb(so);
217 	int mask, error = 0;
218 	extern long ns_pexseq;
219 
220 	if (nsp == NULL)
221 		return (EINVAL);
222 
223 	switch (req) {
224 
225 	case PRCO_GETOPT:
226 		if (value==NULL)
227 			return (EINVAL);
228 		m = m_get(M_DONTWAIT, MT_DATA);
229 		if (m==NULL)
230 			return (ENOBUFS);
231 		switch (name) {
232 
233 		case SO_ALL_PACKETS:
234 			mask = NSP_ALL_PACKETS;
235 			goto get_flags;
236 
237 		case SO_HEADERS_ON_INPUT:
238 			mask = NSP_RAWIN;
239 			goto get_flags;
240 
241 		case SO_HEADERS_ON_OUTPUT:
242 			mask = NSP_RAWOUT;
243 		get_flags:
244 			m->m_len = sizeof(short);
245 			m->m_off = MMAXOFF - sizeof(short);
246 			*mtod(m, short *) = nsp->nsp_flags & mask;
247 			break;
248 
249 		case SO_DEFAULT_HEADERS:
250 			m->m_len = sizeof(struct idp);
251 			m->m_off = MMAXOFF - sizeof(struct idp);
252 			{
253 				register struct idp *idp = mtod(m, struct idp *);
254 				idp->idp_len = 0;
255 				idp->idp_sum = 0;
256 				idp->idp_tc = 0;
257 				idp->idp_pt = nsp->nsp_dpt;
258 				idp->idp_dna = nsp->nsp_faddr;
259 				idp->idp_sna = nsp->nsp_laddr;
260 			}
261 			break;
262 
263 		case SO_SEQNO:
264 			m->m_len = sizeof(long);
265 			m->m_off = MMAXOFF - sizeof(long);
266 			*mtod(m, long *) = ns_pexseq++;
267 		}
268 		*value = m;
269 		break;
270 
271 	case PRCO_SETOPT:
272 		switch (name) {
273 			int *ok;
274 
275 		case SO_ALL_PACKETS:
276 			mask = NSP_ALL_PACKETS;
277 			goto set_head;
278 
279 		case SO_HEADERS_ON_INPUT:
280 			mask = NSP_RAWIN;
281 			goto set_head;
282 
283 		case SO_HEADERS_ON_OUTPUT:
284 			mask = NSP_RAWOUT;
285 		set_head:
286 			if (value && *value) {
287 				ok = mtod(*value, int *);
288 				if (*ok)
289 					nsp->nsp_flags |= mask;
290 				else
291 					nsp->nsp_flags &= ~mask;
292 			} else error = EINVAL;
293 			break;
294 
295 		case SO_DEFAULT_HEADERS:
296 			{
297 				register struct idp *idp
298 				    = mtod(*value, struct idp *);
299 				nsp->nsp_dpt = idp->idp_pt;
300 			}
301 #ifdef NSIP
302 			break;
303 
304 		case SO_NSIP_ROUTE:
305 			error = nsip_route(*value);
306 #endif NSIP
307 		}
308 		if (value && *value)
309 			m_freem(*value);
310 		break;
311 	}
312 	return (error);
313 }
314 
315 /*ARGSUSED*/
316 idp_usrreq(so, req, m, nam, rights)
317 	struct socket *so;
318 	int req;
319 	struct mbuf *m, *nam, *rights;
320 {
321 	struct nspcb *nsp = sotonspcb(so);
322 	int error = 0;
323 
324 	if (req == PRU_CONTROL)
325                 return (ns_control(so, (int)m, (caddr_t)nam,
326 			(struct ifnet *)rights));
327 	if (rights && rights->m_len) {
328 		error = EINVAL;
329 		goto release;
330 	}
331 	if (nsp == NULL && req != PRU_ATTACH) {
332 		error = EINVAL;
333 		goto release;
334 	}
335 	switch (req) {
336 
337 	case PRU_ATTACH:
338 		if (nsp != NULL) {
339 			error = EINVAL;
340 			break;
341 		}
342 		error = ns_pcballoc(so, &nspcb);
343 		if (error)
344 			break;
345 		error = soreserve(so, 2048, 2048);
346 		if (error)
347 			break;
348 		break;
349 
350 	case PRU_DETACH:
351 		if (nsp == NULL) {
352 			error = ENOTCONN;
353 			break;
354 		}
355 		ns_pcbdetach(nsp);
356 		break;
357 
358 	case PRU_BIND:
359 		error = ns_pcbbind(nsp, nam);
360 		break;
361 
362 	case PRU_LISTEN:
363 		error = EOPNOTSUPP;
364 		break;
365 
366 	case PRU_CONNECT:
367 		if (!ns_nullhost(nsp->nsp_faddr)) {
368 			error = EISCONN;
369 			break;
370 		}
371 		error = ns_pcbconnect(nsp, nam);
372 		if (error == 0)
373 			soisconnected(so);
374 		break;
375 
376 	case PRU_CONNECT2:
377 		error = EOPNOTSUPP;
378 		break;
379 
380 	case PRU_ACCEPT:
381 		error = EOPNOTSUPP;
382 		break;
383 
384 	case PRU_DISCONNECT:
385 		if (ns_nullhost(nsp->nsp_faddr)) {
386 			error = ENOTCONN;
387 			break;
388 		}
389 		ns_pcbdisconnect(nsp);
390 		soisdisconnected(so);
391 		break;
392 
393 	case PRU_SHUTDOWN:
394 		socantsendmore(so);
395 		break;
396 
397 	case PRU_SEND:
398 	{
399 		struct ns_addr laddr;
400 		int s;
401 
402 		if (nam) {
403 			laddr = nsp->nsp_laddr;
404 			if (!ns_nullhost(nsp->nsp_faddr)) {
405 				error = EISCONN;
406 				break;
407 			}
408 			/*
409 			 * Must block input while temporarily connected.
410 			 */
411 			s = splnet();
412 			error = ns_pcbconnect(nsp, nam);
413 			if (error) {
414 				splx(s);
415 				break;
416 			}
417 		} else {
418 			if (ns_nullhost(nsp->nsp_faddr)) {
419 				error = ENOTCONN;
420 				break;
421 			}
422 		}
423 		error = idp_output(nsp, m);
424 		m = NULL;
425 		if (nam) {
426 			ns_pcbdisconnect(nsp);
427 			splx(s);
428 			nsp->nsp_laddr.x_host = laddr.x_host;
429 			nsp->nsp_laddr.x_port = laddr.x_port;
430 		}
431 	}
432 		break;
433 
434 	case PRU_ABORT:
435 		ns_pcbdetach(nsp);
436 		sofree(so);
437 		soisdisconnected(so);
438 		break;
439 
440 	case PRU_SOCKADDR:
441 		ns_setsockaddr(nsp, nam);
442 		break;
443 
444 	case PRU_PEERADDR:
445 		ns_setpeeraddr(nsp, nam);
446 		break;
447 
448 	case PRU_SENSE:
449 		/*
450 		 * stat: don't bother with a blocksize.
451 		 */
452 		return (0);
453 
454 	case PRU_SENDOOB:
455 	case PRU_FASTTIMO:
456 	case PRU_SLOWTIMO:
457 	case PRU_PROTORCV:
458 	case PRU_PROTOSEND:
459 		error =  EOPNOTSUPP;
460 		break;
461 
462 	case PRU_CONTROL:
463 	case PRU_RCVD:
464 	case PRU_RCVOOB:
465 		return (EOPNOTSUPP);	/* do not free mbuf's */
466 
467 	default:
468 		panic("idp_usrreq");
469 	}
470 release:
471 	if (m != NULL)
472 		m_freem(m);
473 	return (error);
474 }
475 /*ARGSUSED*/
476 idp_raw_usrreq(so, req, m, nam, rights)
477 	struct socket *so;
478 	int req;
479 	struct mbuf *m, *nam, *rights;
480 {
481 	int error = 0;
482 	struct nspcb *nsp = sotonspcb(so);
483 	extern struct nspcb nsrawpcb;
484 
485 	switch (req) {
486 
487 	case PRU_ATTACH:
488 
489 		if (!suser() || (nsp != NULL)) {
490 			error = EINVAL;
491 			break;
492 		}
493 		error = ns_pcballoc(so, &nsrawpcb);
494 		if (error)
495 			break;
496 		error = soreserve(so, 2048, 2048);
497 		if (error)
498 			break;
499 		nsp = sotonspcb(so);
500 		nsp->nsp_faddr.x_host = ns_broadhost;
501 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
502 		break;
503 	default:
504 		error = idp_usrreq(so, req, m, nam, rights);
505 	}
506 	return (error);
507 }
508 
509