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