xref: /csrg-svn/sys/netns/idp_usrreq.c (revision 23500)
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.4 (Berkeley) 06/16/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 		return (EINVAL);
181 
182 	switch (req) {
183 
184 	case PRCO_GETOPT:
185 		if (value==NULL)
186 			return (EINVAL);
187 		m = m_get(M_DONTWAIT, MT_DATA);
188 		if (m==NULL)
189 			return (ENOBUFS);
190 		switch (name) {
191 
192 		case SO_HEADERS_ON_INPUT:
193 			mask = NSP_RAWIN;
194 			goto get_flags;
195 
196 		case SO_HEADERS_ON_OUTPUT:
197 			mask = NSP_RAWOUT;
198 		get_flags:
199 			m->m_len = sizeof(short);
200 			m->m_off = MMAXOFF - sizeof(short);
201 			*mtod(m, short *) = nsp->nsp_flags & mask;
202 			break;
203 
204 		case SO_DEFAULT_HEADERS:
205 			m->m_len = sizeof(struct idp);
206 			m->m_off = MMAXOFF - sizeof(struct idp);
207 			{
208 				register struct idp *idp = mtod(m, struct idp *);
209 				idp->idp_len = 0;
210 				idp->idp_sum = 0;
211 				idp->idp_tc = 0;
212 				idp->idp_pt = nsp->nsp_dpt;
213 				idp->idp_dna = nsp->nsp_faddr;
214 				idp->idp_sna = nsp->nsp_laddr;
215 			}
216 		}
217 		*value = m;
218 		break;
219 
220 	case PRCO_SETOPT:
221 		switch (name) {
222 			int mask, *ok;
223 
224 		case SO_HEADERS_ON_INPUT:
225 			mask = NSP_RAWIN;
226 			goto set_head;
227 
228 		case SO_HEADERS_ON_OUTPUT:
229 			mask = NSP_RAWOUT;
230 		set_head:
231 			if (value && *value) {
232 				ok = mtod(*value, int *);
233 				if (*ok)
234 					nsp->nsp_flags |= mask;
235 				else
236 					nsp->nsp_flags &= ~mask;
237 			} else error = EINVAL;
238 			break;
239 
240 		case SO_DEFAULT_HEADERS:
241 			{
242 				register struct idp *idp
243 				    = mtod(*value, struct idp *);
244 				nsp->nsp_dpt = idp->idp_pt;
245 			}
246 #ifdef NSIP
247 			break;
248 
249 		case SO_NSIP_ROUTE:
250 			error = nsip_route(*value);
251 #endif NSIP
252 		}
253 		if (value && *value)
254 			m_freem(*value);
255 		break;
256 	}
257 	return (error);
258 }
259 
260 /*ARGSUSED*/
261 idp_usrreq(so, req, m, nam, rights)
262 	struct socket *so;
263 	int req;
264 	struct mbuf *m, *nam, *rights;
265 {
266 	struct nspcb *nsp = sotonspcb(so);
267 	int error = 0;
268 
269 	if (req == PRU_CONTROL)
270                 return (ns_control(so, (int)m, (caddr_t)nam,
271 			(struct ifnet *)rights));
272 	if (rights && rights->m_len) {
273 		error = EINVAL;
274 		goto release;
275 	}
276 	if (nsp == NULL && req != PRU_ATTACH) {
277 		error = EINVAL;
278 		goto release;
279 	}
280 	switch (req) {
281 
282 	case PRU_ATTACH:
283 		if (nsp != NULL) {
284 			error = EINVAL;
285 			break;
286 		}
287 		error = ns_pcballoc(so, &nspcb);
288 		if (error)
289 			break;
290 		error = soreserve(so, 2048, 2048);
291 		if (error)
292 			break;
293 		break;
294 
295 	case PRU_DETACH:
296 		if (nsp == NULL) {
297 			error = ENOTCONN;
298 			break;
299 		}
300 		ns_pcbdetach(nsp);
301 		break;
302 
303 	case PRU_BIND:
304 		error = ns_pcbbind(nsp, nam);
305 		break;
306 
307 	case PRU_LISTEN:
308 		error = EOPNOTSUPP;
309 		break;
310 
311 	case PRU_CONNECT:
312 		if (!ns_nullhost(nsp->nsp_faddr)) {
313 			error = EISCONN;
314 			break;
315 		}
316 		error = ns_pcbconnect(nsp, nam);
317 		if (error == 0)
318 			soisconnected(so);
319 		break;
320 
321 	case PRU_CONNECT2:
322 		error = EOPNOTSUPP;
323 		break;
324 
325 	case PRU_ACCEPT:
326 		error = EOPNOTSUPP;
327 		break;
328 
329 	case PRU_DISCONNECT:
330 		if (ns_nullhost(nsp->nsp_faddr)) {
331 			error = ENOTCONN;
332 			break;
333 		}
334 		ns_pcbdisconnect(nsp);
335 		soisdisconnected(so);
336 		break;
337 
338 	case PRU_SHUTDOWN:
339 		socantsendmore(so);
340 		break;
341 
342 	case PRU_SEND:
343 	{
344 		struct ns_addr laddr;
345 		int s;
346 
347 		if (nam) {
348 			laddr = nsp->nsp_laddr;
349 			if (!ns_nullhost(nsp->nsp_faddr)) {
350 				error = EISCONN;
351 				break;
352 			}
353 			/*
354 			 * Must block input while temporarily connected.
355 			 */
356 			s = splnet();
357 			error = ns_pcbconnect(nsp, nam);
358 			if (error) {
359 				splx(s);
360 				break;
361 			}
362 		} else {
363 			if (ns_nullhost(nsp->nsp_faddr)) {
364 				error = ENOTCONN;
365 				break;
366 			}
367 		}
368 		error = idp_output(nsp, m);
369 		m = NULL;
370 		if (nam) {
371 			ns_pcbdisconnect(nsp);
372 			splx(s);
373 			nsp->nsp_laddr.x_host = laddr.x_host;
374 			nsp->nsp_laddr.x_port = laddr.x_port;
375 		}
376 	}
377 		break;
378 
379 	case PRU_ABORT:
380 		ns_pcbdetach(nsp);
381 		sofree(so);
382 		soisdisconnected(so);
383 		break;
384 
385 	case PRU_SOCKADDR:
386 		ns_setsockaddr(nsp, nam);
387 		break;
388 
389 	case PRU_PEERADDR:
390 		ns_setpeeraddr(nsp, nam);
391 		break;
392 
393 	case PRU_SENSE:
394 		/*
395 		 * stat: don't bother with a blocksize.
396 		 */
397 		return (0);
398 
399 	case PRU_SENDOOB:
400 	case PRU_FASTTIMO:
401 	case PRU_SLOWTIMO:
402 	case PRU_PROTORCV:
403 	case PRU_PROTOSEND:
404 		error =  EOPNOTSUPP;
405 		break;
406 
407 	case PRU_CONTROL:
408 	case PRU_RCVD:
409 	case PRU_RCVOOB:
410 		return (EOPNOTSUPP);	/* do not free mbuf's */
411 
412 	default:
413 		panic("idp_usrreq");
414 	}
415 release:
416 	if (m != NULL)
417 		m_freem(m);
418 	return (error);
419 }
420 /*ARGSUSED*/
421 idp_raw_usrreq(so, req, m, nam, rights)
422 	struct socket *so;
423 	int req;
424 	struct mbuf *m, *nam, *rights;
425 {
426 	int error = 0;
427 	struct nspcb *nsp = sotonspcb(so);
428 	extern struct nspcb nsrawpcb;
429 
430 	switch (req) {
431 
432 	case PRU_ATTACH:
433 
434 		if (!suser() || (nsp != NULL)) {
435 			error = EINVAL;
436 			break;
437 		}
438 		error = ns_pcballoc(so, &nsrawpcb);
439 		if (error)
440 			break;
441 		error = soreserve(so, 2048, 2048);
442 		if (error)
443 			break;
444 		nsp = sotonspcb(so);
445 		nsp->nsp_faddr.x_host = ns_broadhost;
446 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
447 		break;
448 	default:
449 		error = idp_usrreq(so, req, m, nam, rights);
450 	}
451 	return (error);
452 }
453 
454