make sure to calculate initial credit for both CE_bit options for CC and CR
[unix-history] / usr / src / sys / netiso / cltp_usrreq.c
CommitLineData
cb94d50b
KS
1/*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved.
4 *
dbf0c423 5 * %sccs.include.redist.c%
cb94d50b 6 *
9cc3f5cf 7 * @(#)cltp_usrreq.c 7.8 (Berkeley) %G%
cb94d50b
KS
8 */
9
10#ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */
11#include "param.h"
cb94d50b
KS
12#include "malloc.h"
13#include "mbuf.h"
14#include "protosw.h"
15#include "socket.h"
16#include "socketvar.h"
17#include "errno.h"
18#include "stat.h"
19
20#include "../net/if.h"
21#include "../net/route.h"
22
23#include "argo_debug.h"
24#include "iso.h"
25#include "iso_pcb.h"
26#include "iso_var.h"
27#include "clnp.h"
28#include "cltp_var.h"
29#endif
30
31/*
32 * CLTP protocol implementation.
33 * Per ISO 8602, December, 1987.
34 */
35cltp_init()
36{
37
38 cltb.isop_next = cltb.isop_prev = &cltb;
39}
40
41int cltp_cksum = 1;
42
43
44/* ARGUSED */
45cltp_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:
c6f34efd
KS
87 if (iso_check_csum(m0, len)) {
88 cltpstat.cltps_badsum++;
cb94d50b 89 goto bad;
c6f34efd 90 }
cb94d50b 91 up += 4;
c6f34efd 92 continue;
cb94d50b
KS
93
94 default:
95 printf("clts: unknown option (%x)\n", up[0]);
c6f34efd 96 cltpstat.cltps_hdrops++;
cb94d50b
KS
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) {
c6f34efd
KS
102 if (isop == &cltb) {
103 cltpstat.cltps_noport++;
cb94d50b 104 goto bad;
c6f34efd 105 }
cb94d50b
KS
106 if (isop->isop_laddr &&
107 bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0)
108 break;
109 }
110 m = m0;
c6f34efd
KS
111 m->m_len -= hdrlen;
112 m->m_data += hdrlen;
cb94d50b
KS
113 if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src,
114 m, (struct mbuf *)0) == 0)
115 goto bad;
c6f34efd 116 cltpstat.cltps_ipackets++;
cb94d50b
KS
117 sorwakeup(isop->isop_socket);
118 m0 = 0;
119bad:
120 if (src != (struct sockaddr_iso *)srcsa)
121 m_freem(dtom(src));
122 if (m0)
123 m_freem(m0);
c6f34efd 124 return 0;
cb94d50b
KS
125}
126
127/*
128 * Notify a cltp user of an asynchronous error;
129 * just wake up so that he can collect error status.
130 */
131cltp_notify(isop)
132 register struct isopcb *isop;
133{
134
135 sorwakeup(isop->isop_socket);
136 sowwakeup(isop->isop_socket);
137}
138
139cltp_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
173cltp_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 *);
c6f34efd
KS
199 up[0] = hdrlen - 1;
200 up[1] = UD_TPDU_type;
201 up[2] = CLTPOVAL_SRC;
cb94d50b
KS
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;
c6f34efd 206 up[0] = CLTPOVAL_DST;
cb94d50b
KS
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;
c6f34efd 217 iso_gen_csum(m, 2 + up - mtod(m, u_char *), len);
cb94d50b 218 }
c6f34efd 219 cltpstat.cltps_opackets++;
cb94d50b
KS
220 return (tpclnp_output(isop, m, len, !docsum));
221bad:
222 m_freem(m);
223 return (error);
224}
225
cb94d50b
KS
226u_long cltp_sendspace = 9216; /* really max datagram size */
227u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso));
228 /* 40 1K datagrams */
229
230
231/*ARGSUSED*/
3483a811 232cltp_usrreq(so, req, m, nam, control)
cb94d50b
KS
233 struct socket *so;
234 int req;
3483a811 235 struct mbuf *m, *nam, *control;
cb94d50b 236{
abd09738 237 register struct isopcb *isop = sotoisopcb(so);
cb94d50b
KS
238 int s, error = 0;
239
240 if (req == PRU_CONTROL)
241 return (iso_control(so, (int)m, (caddr_t)nam,
3483a811 242 (struct ifnet *)control));
a28acf5d
KS
243 if ((isop == NULL && req != PRU_ATTACH) ||
244 (control && control->m_len)) {
cb94d50b
KS
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:
abd09738
KS
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);
cb94d50b
KS
344 break;
345
346 case PRU_PEERADDR:
abd09738
KS
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);
cb94d50b
KS
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 }
373release:
a28acf5d
KS
374 if (control != NULL)
375 m_freem(control);
cb94d50b
KS
376 if (m != NULL)
377 m_freem(m);
378 return (error);
379}