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