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