xref: /csrg-svn/sys/netiso/cltp_usrreq.c (revision 39540)
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)cltp_usrreq.c	7.1 (Berkeley) 11/15/89
18  */
19 
20 #ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */
21 #include "param.h"
22 #include "user.h"
23 #include "malloc.h"
24 #include "mbuf.h"
25 #include "protosw.h"
26 #include "socket.h"
27 #include "socketvar.h"
28 #include "errno.h"
29 #include "stat.h"
30 
31 #include "../net/if.h"
32 #include "../net/route.h"
33 
34 #include "argo_debug.h"
35 #include "iso.h"
36 #include "iso_pcb.h"
37 #include "iso_var.h"
38 #include "clnp.h"
39 #include "cltp_var.h"
40 #endif
41 
42 /*
43  * CLTP protocol implementation.
44  * Per ISO 8602, December, 1987.
45  */
46 cltp_init()
47 {
48 
49 	cltb.isop_next = cltb.isop_prev = &cltb;
50 }
51 
52 int cltp_cksum = 1;
53 
54 
55 /* ARGUSED */
56 cltp_input(m0, srcsa, dstsa, cons_channel, output)
57 	struct mbuf *m0;
58 	struct sockaddr *srcsa, *dstsa;
59 	u_int cons_channel;
60 	int (*output)();
61 {
62 	register struct isopcb *isop;
63 	register struct mbuf *m = m0;
64 	register u_char *up = mtod(m, u_char *);
65 	register struct sockaddr_iso *src = (struct sockaddr_iso *)srcsa;
66 	int len, hdrlen = *up + 1, dlen = 0;
67 	u_char *uplim = up + hdrlen;
68 	caddr_t dtsap;
69 
70 	for (len = 0; m; m = m->m_next)
71 		len += m->m_len;
72 	up += 2; /* skip header */
73 	while (up < uplim) switch (*up) { /* process options */
74 	case CLTPOVAL_SRC:
75 		src->siso_tlen = up[1];
76 		src->siso_len = up[1] + TSEL(src) - (caddr_t)src;
77 		if (src->siso_len < sizeof(*src))
78 			src->siso_len = sizeof(*src);
79 		else if (src->siso_len > sizeof(*src)) {
80 			MGET(m, M_DONTWAIT, MT_SONAME);
81 			if (m == 0)
82 				goto bad;
83 			m->m_len = src->siso_len;
84 			src = mtod(m, struct sockaddr_iso *);
85 			bcopy((caddr_t)srcsa, (caddr_t)src, srcsa->sa_len);
86 		}
87 		bcopy((caddr_t)up + 2, TSEL(src), up[1]);
88 		up += 2 + src->siso_tlen;
89 		continue;
90 
91 	case CLTPOVAL_DST:
92 		dtsap = 2 + (caddr_t)up;
93 		dlen = up[1];
94 		up += 2 + dlen;
95 		continue;
96 
97 	case CLTPOVAL_CSM:
98 		if (iso_check_csum(m0, len))
99 			goto bad;
100 		up += 4;
101 
102 	default:
103 		printf("clts: unknown option (%x)\n", up[0]);
104 		goto bad;
105 	}
106 	if (dlen == 0 || src->siso_tlen == 0)
107 		goto bad;
108 	for (isop = cltb.isop_next;; isop = isop->isop_next) {
109 		if (isop == &cltb)
110 			goto bad;
111 		if (isop->isop_laddr &&
112 		    bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0)
113 			break;
114 	}
115 	m = m0;
116 	m->m_len += hdrlen;
117 	if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src,
118 	    m, (struct mbuf *)0) == 0)
119 		goto bad;
120 	sorwakeup(isop->isop_socket);
121 	m0 = 0;
122 bad:
123 	if (src != (struct sockaddr_iso *)srcsa)
124 		m_freem(dtom(src));
125 	if (m0)
126 		m_freem(m0);
127 	return;
128 }
129 
130 /*
131  * Notify a cltp user of an asynchronous error;
132  * just wake up so that he can collect error status.
133  */
134 cltp_notify(isop)
135 	register struct isopcb *isop;
136 {
137 
138 	sorwakeup(isop->isop_socket);
139 	sowwakeup(isop->isop_socket);
140 }
141 
142 cltp_ctlinput(cmd, sa)
143 	int cmd;
144 	struct sockaddr *sa;
145 {
146 	extern u_char inetctlerrmap[];
147 	struct sockaddr_iso *siso;
148 	int iso_rtchange();
149 
150 	if ((unsigned)cmd > PRC_NCMDS)
151 		return;
152 	if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT)
153 		return;
154 	siso = (struct sockaddr_iso *)sa;
155 	if (siso == 0 || siso->siso_nlen == 0)
156 		return;
157 
158 	switch (cmd) {
159 	case PRC_ROUTEDEAD:
160 	case PRC_REDIRECT_NET:
161 	case PRC_REDIRECT_HOST:
162 	case PRC_REDIRECT_TOSNET:
163 	case PRC_REDIRECT_TOSHOST:
164 		iso_pcbnotify(&cltb, siso,
165 				(int)inetctlerrmap[cmd], iso_rtchange);
166 		break;
167 
168 	default:
169 		if (inetctlerrmap[cmd] == 0)
170 			return;		/* XXX */
171 		iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd],
172 			cltp_notify);
173 	}
174 }
175 
176 cltp_output(isop, m)
177 	register struct isopcb *isop;
178 	register struct mbuf *m;
179 {
180 	register int len;
181 	register struct sockaddr_iso *siso;
182 	int hdrlen, error = 0, docsum;
183 	register u_char *up;
184 
185 	if (isop->isop_laddr == 0 || isop->isop_faddr == 0) {
186 		error = ENOTCONN;
187 		goto bad;
188 	}
189 	/*
190 	 * Calculate data length and get a mbuf for CLTP header.
191 	 */
192 	hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen
193 		   + 2 + isop->isop_faddr->siso_tlen;
194 	if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum)
195 		hdrlen += 4;
196 	M_PREPEND(m, hdrlen, M_WAIT);
197 	len = m->m_pkthdr.len;
198 	/*
199 	 * Fill in mbuf with extended CLTP header
200 	 */
201 	up = mtod(m, u_char *);
202 	up[0] = UD_TPDU_type;
203 	up[1] = hdrlen - 1;
204 	up[2] = CLTPOVAL_DST;
205 	up[3] = (siso = isop->isop_laddr)->siso_tlen;
206 	up += 4;
207 	bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen);
208 	up += siso->siso_tlen;
209 	up[0] = CLTPOVAL_SRC;
210 	up[1] = (siso = isop->isop_faddr)->siso_tlen;
211 	up += 2;
212 	bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen);
213 	/*
214 	 * Stuff checksum and output datagram.
215 	 */
216 	if (docsum) {
217 		up += siso->siso_tlen;
218 		up[0] = CLTPOVAL_CSM;
219 		up[1] = 2;
220 		iso_gen_cksum(m, 2 + up - mtod(m, u_char *), len);
221 	}
222 	return (tpclnp_output(isop, m, len, !docsum));
223 bad:
224 	m_freem(m);
225 	return (error);
226 }
227 
228 #ifndef TP_LOCAL
229 /* XXXX should go in iso.h maybe? from tp_param.h, in any case */
230 #define		TP_LOCAL				22
231 #define		TP_FOREIGN				33
232 #endif
233 
234 u_long	cltp_sendspace = 9216;		/* really max datagram size */
235 u_long	cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso));
236 					/* 40 1K datagrams */
237 
238 
239 /*ARGSUSED*/
240 cltp_usrreq(so, req, m, nam, rights, control)
241 	struct socket *so;
242 	int req;
243 	struct mbuf *m, *nam, *rights, *control;
244 {
245 	struct isopcb *isop = sotoisopcb(so);
246 	int s, error = 0;
247 
248 	if (req == PRU_CONTROL)
249 		return (iso_control(so, (int)m, (caddr_t)nam,
250 			(struct ifnet *)rights));
251 	if (rights && rights->m_len) {
252 		error = EINVAL;
253 		goto release;
254 	}
255 	if (isop == NULL && req != PRU_ATTACH) {
256 		error = EINVAL;
257 		goto release;
258 	}
259 	switch (req) {
260 
261 	case PRU_ATTACH:
262 		if (isop != NULL) {
263 			error = EINVAL;
264 			break;
265 		}
266 		error = iso_pcballoc(so, &cltb);
267 		if (error)
268 			break;
269 		error = soreserve(so, cltp_sendspace, cltp_recvspace);
270 		if (error)
271 			break;
272 		break;
273 
274 	case PRU_DETACH:
275 		iso_pcbdetach(isop);
276 		break;
277 
278 	case PRU_BIND:
279 		error = iso_pcbbind(isop, nam);
280 		break;
281 
282 	case PRU_LISTEN:
283 		error = EOPNOTSUPP;
284 		break;
285 
286 	case PRU_CONNECT:
287 		if (isop->isop_faddr) {
288 			error = EISCONN;
289 			break;
290 		}
291 		error = iso_pcbconnect(isop, nam);
292 		if (error == 0)
293 			soisconnected(so);
294 		break;
295 
296 	case PRU_CONNECT2:
297 		error = EOPNOTSUPP;
298 		break;
299 
300 	case PRU_ACCEPT:
301 		error = EOPNOTSUPP;
302 		break;
303 
304 	case PRU_DISCONNECT:
305 		if (isop->isop_faddr == 0) {
306 			error = ENOTCONN;
307 			break;
308 		}
309 		iso_pcbdisconnect(isop);
310 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
311 		break;
312 
313 	case PRU_SHUTDOWN:
314 		socantsendmore(so);
315 		break;
316 
317 	case PRU_SEND:
318 		if (nam) {
319 			if (isop->isop_faddr) {
320 				error = EISCONN;
321 				break;
322 			}
323 			/*
324 			 * Must block input while temporarily connected.
325 			 */
326 			s = splnet();
327 			error = iso_pcbconnect(isop, nam);
328 			if (error) {
329 				splx(s);
330 				break;
331 			}
332 		} else {
333 			if (isop->isop_faddr == 0) {
334 				error = ENOTCONN;
335 				break;
336 			}
337 		}
338 		error = cltp_output(isop, m);
339 		m = 0;
340 		if (nam) {
341 			iso_pcbdisconnect(isop);
342 			splx(s);
343 		}
344 		break;
345 
346 	case PRU_ABORT:
347 		soisdisconnected(so);
348 		iso_pcbdetach(isop);
349 		break;
350 
351 	case PRU_SOCKADDR:
352 		iso_getnetaddr(isop, nam, TP_LOCAL);
353 		break;
354 
355 	case PRU_PEERADDR:
356 		iso_getnetaddr(isop, nam, TP_FOREIGN);
357 		break;
358 
359 	case PRU_SENSE:
360 		/*
361 		 * stat: don't bother with a blocksize.
362 		 */
363 		return (0);
364 
365 	case PRU_SENDOOB:
366 	case PRU_FASTTIMO:
367 	case PRU_SLOWTIMO:
368 	case PRU_PROTORCV:
369 	case PRU_PROTOSEND:
370 		error =  EOPNOTSUPP;
371 		break;
372 
373 	case PRU_RCVD:
374 	case PRU_RCVOOB:
375 		return (EOPNOTSUPP);	/* do not free mbuf's */
376 
377 	default:
378 		panic("cltp_usrreq");
379 	}
380 release:
381 	if (m != NULL)
382 		m_freem(m);
383 	return (error);
384 }
385