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