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