xref: /csrg-svn/sys/netiso/cltp_usrreq.c (revision 39925)
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.2 (Berkeley) 01/16/90
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 			cltpstat.cltps_badsum++;
100 			goto bad;
101 		}
102 		up += 4;
103 		continue;
104 
105 	default:
106 		printf("clts: unknown option (%x)\n", up[0]);
107 		cltpstat.cltps_hdrops++;
108 		goto bad;
109 	}
110 	if (dlen == 0 || src->siso_tlen == 0)
111 		goto bad;
112 	for (isop = cltb.isop_next;; isop = isop->isop_next) {
113 		if (isop == &cltb) {
114 			cltpstat.cltps_noport++;
115 			goto bad;
116 		}
117 		if (isop->isop_laddr &&
118 		    bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0)
119 			break;
120 	}
121 	m = m0;
122 	m->m_len -= hdrlen;
123 	m->m_data += hdrlen;
124 	if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src,
125 	    m, (struct mbuf *)0) == 0)
126 		goto bad;
127 	cltpstat.cltps_ipackets++;
128 	sorwakeup(isop->isop_socket);
129 	m0 = 0;
130 bad:
131 	if (src != (struct sockaddr_iso *)srcsa)
132 		m_freem(dtom(src));
133 	if (m0)
134 		m_freem(m0);
135 	return 0;
136 }
137 
138 /*
139  * Notify a cltp user of an asynchronous error;
140  * just wake up so that he can collect error status.
141  */
142 cltp_notify(isop)
143 	register struct isopcb *isop;
144 {
145 
146 	sorwakeup(isop->isop_socket);
147 	sowwakeup(isop->isop_socket);
148 }
149 
150 cltp_ctlinput(cmd, sa)
151 	int cmd;
152 	struct sockaddr *sa;
153 {
154 	extern u_char inetctlerrmap[];
155 	struct sockaddr_iso *siso;
156 	int iso_rtchange();
157 
158 	if ((unsigned)cmd > PRC_NCMDS)
159 		return;
160 	if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT)
161 		return;
162 	siso = (struct sockaddr_iso *)sa;
163 	if (siso == 0 || siso->siso_nlen == 0)
164 		return;
165 
166 	switch (cmd) {
167 	case PRC_ROUTEDEAD:
168 	case PRC_REDIRECT_NET:
169 	case PRC_REDIRECT_HOST:
170 	case PRC_REDIRECT_TOSNET:
171 	case PRC_REDIRECT_TOSHOST:
172 		iso_pcbnotify(&cltb, siso,
173 				(int)inetctlerrmap[cmd], iso_rtchange);
174 		break;
175 
176 	default:
177 		if (inetctlerrmap[cmd] == 0)
178 			return;		/* XXX */
179 		iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd],
180 			cltp_notify);
181 	}
182 }
183 
184 cltp_output(isop, m)
185 	register struct isopcb *isop;
186 	register struct mbuf *m;
187 {
188 	register int len;
189 	register struct sockaddr_iso *siso;
190 	int hdrlen, error = 0, docsum;
191 	register u_char *up;
192 
193 	if (isop->isop_laddr == 0 || isop->isop_faddr == 0) {
194 		error = ENOTCONN;
195 		goto bad;
196 	}
197 	/*
198 	 * Calculate data length and get a mbuf for CLTP header.
199 	 */
200 	hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen
201 		   + 2 + isop->isop_faddr->siso_tlen;
202 	if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum)
203 		hdrlen += 4;
204 	M_PREPEND(m, hdrlen, M_WAIT);
205 	len = m->m_pkthdr.len;
206 	/*
207 	 * Fill in mbuf with extended CLTP header
208 	 */
209 	up = mtod(m, u_char *);
210 	up[0] = hdrlen - 1;
211 	up[1] = UD_TPDU_type;
212 	up[2] = CLTPOVAL_SRC;
213 	up[3] = (siso = isop->isop_laddr)->siso_tlen;
214 	up += 4;
215 	bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen);
216 	up += siso->siso_tlen;
217 	up[0] = CLTPOVAL_DST;
218 	up[1] = (siso = isop->isop_faddr)->siso_tlen;
219 	up += 2;
220 	bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen);
221 	/*
222 	 * Stuff checksum and output datagram.
223 	 */
224 	if (docsum) {
225 		up += siso->siso_tlen;
226 		up[0] = CLTPOVAL_CSM;
227 		up[1] = 2;
228 		iso_gen_csum(m, 2 + up - mtod(m, u_char *), len);
229 	}
230 	cltpstat.cltps_opackets++;
231 	return (tpclnp_output(isop, m, len, !docsum));
232 bad:
233 	m_freem(m);
234 	return (error);
235 }
236 
237 #ifndef TP_LOCAL
238 /* XXXX should go in iso.h maybe? from tp_param.h, in any case */
239 #define		TP_LOCAL				22
240 #define		TP_FOREIGN				33
241 #endif
242 
243 u_long	cltp_sendspace = 9216;		/* really max datagram size */
244 u_long	cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso));
245 					/* 40 1K datagrams */
246 
247 
248 /*ARGSUSED*/
249 cltp_usrreq(so, req, m, nam, rights, control)
250 	struct socket *so;
251 	int req;
252 	struct mbuf *m, *nam, *rights, *control;
253 {
254 	struct isopcb *isop = sotoisopcb(so);
255 	int s, error = 0;
256 
257 	if (req == PRU_CONTROL)
258 		return (iso_control(so, (int)m, (caddr_t)nam,
259 			(struct ifnet *)rights));
260 	if (rights && rights->m_len) {
261 		error = EINVAL;
262 		goto release;
263 	}
264 	if (isop == NULL && req != PRU_ATTACH) {
265 		error = EINVAL;
266 		goto release;
267 	}
268 	switch (req) {
269 
270 	case PRU_ATTACH:
271 		if (isop != NULL) {
272 			error = EINVAL;
273 			break;
274 		}
275 		error = iso_pcballoc(so, &cltb);
276 		if (error)
277 			break;
278 		error = soreserve(so, cltp_sendspace, cltp_recvspace);
279 		if (error)
280 			break;
281 		break;
282 
283 	case PRU_DETACH:
284 		iso_pcbdetach(isop);
285 		break;
286 
287 	case PRU_BIND:
288 		error = iso_pcbbind(isop, nam);
289 		break;
290 
291 	case PRU_LISTEN:
292 		error = EOPNOTSUPP;
293 		break;
294 
295 	case PRU_CONNECT:
296 		if (isop->isop_faddr) {
297 			error = EISCONN;
298 			break;
299 		}
300 		error = iso_pcbconnect(isop, nam);
301 		if (error == 0)
302 			soisconnected(so);
303 		break;
304 
305 	case PRU_CONNECT2:
306 		error = EOPNOTSUPP;
307 		break;
308 
309 	case PRU_ACCEPT:
310 		error = EOPNOTSUPP;
311 		break;
312 
313 	case PRU_DISCONNECT:
314 		if (isop->isop_faddr == 0) {
315 			error = ENOTCONN;
316 			break;
317 		}
318 		iso_pcbdisconnect(isop);
319 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
320 		break;
321 
322 	case PRU_SHUTDOWN:
323 		socantsendmore(so);
324 		break;
325 
326 	case PRU_SEND:
327 		if (nam) {
328 			if (isop->isop_faddr) {
329 				error = EISCONN;
330 				break;
331 			}
332 			/*
333 			 * Must block input while temporarily connected.
334 			 */
335 			s = splnet();
336 			error = iso_pcbconnect(isop, nam);
337 			if (error) {
338 				splx(s);
339 				break;
340 			}
341 		} else {
342 			if (isop->isop_faddr == 0) {
343 				error = ENOTCONN;
344 				break;
345 			}
346 		}
347 		error = cltp_output(isop, m);
348 		m = 0;
349 		if (nam) {
350 			iso_pcbdisconnect(isop);
351 			splx(s);
352 		}
353 		break;
354 
355 	case PRU_ABORT:
356 		soisdisconnected(so);
357 		iso_pcbdetach(isop);
358 		break;
359 
360 	case PRU_SOCKADDR:
361 		iso_getnetaddr(isop, nam, TP_LOCAL);
362 		break;
363 
364 	case PRU_PEERADDR:
365 		iso_getnetaddr(isop, nam, TP_FOREIGN);
366 		break;
367 
368 	case PRU_SENSE:
369 		/*
370 		 * stat: don't bother with a blocksize.
371 		 */
372 		return (0);
373 
374 	case PRU_SENDOOB:
375 	case PRU_FASTTIMO:
376 	case PRU_SLOWTIMO:
377 	case PRU_PROTORCV:
378 	case PRU_PROTOSEND:
379 		error =  EOPNOTSUPP;
380 		break;
381 
382 	case PRU_RCVD:
383 	case PRU_RCVOOB:
384 		return (EOPNOTSUPP);	/* do not free mbuf's */
385 
386 	default:
387 		panic("cltp_usrreq");
388 	}
389 release:
390 	if (m != NULL)
391 		m_freem(m);
392 	return (error);
393 }
394