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