Merge branch 'less_closed'
[unleashed.git] / usr / src / cmd / bnu / pk0.c
blob9d96a954efdcfbf4317d1616a39ec18ebe35d1a6
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include "uucp.h"
35 #include "pk.h"
36 #include <sys/buf.h>
38 extern void xlatecntl();
39 extern void pkcntl(), pkoutput(), pkclose(), pkreset(), pkzero(),
40 pkgetpack(), pkxstart();
41 extern int pkread(), pkwrite(), pksack();
42 static int pksize(), chksum(), pkaccept();
44 extern int Connodata; /* Continuous No Valid Data Count */
45 extern int xpacksize;
48 * receive control messages
49 * c -> message type fields
50 * pk -> line control unit
52 void
53 pkcntl(c, pk)
54 int c;
55 struct pack *pk;
57 int cntl, val;
59 val = c & MOD8;
60 cntl = (c>>3) & MOD8;
62 if ( ! ISCNTL(c) ) {
63 logent("PK0", "not cntl");
64 return;
67 if (Debug >= 9)
68 xlatecntl(0, c);
69 switch(cntl) {
71 case INITB:
72 val++;
73 pk->p_xsize = xpacksize = pksizes[val];
74 pk->p_lpsize = val;
75 pk->p_bits = 1;
76 if (pk->p_state & LIVE) {
77 pk->p_msg |= M_INITC;
78 break;
80 pk->p_state |= INITb;
81 if ((pk->p_state & INITa)==0) {
82 break;
84 pk->p_rmsg &= ~M_INITA;
85 pk->p_msg |= M_INITC;
86 break;
88 case INITC:
89 if ((pk->p_state&INITab)==INITab) {
90 pk->p_state = LIVE;
91 pk->p_rmsg &= ~M_INITB;
92 } else
93 pk->p_msg |= M_INITB;
94 if (val)
95 pk->p_swindow = val;
96 break;
97 case INITA:
98 if (val==0 && pk->p_state&LIVE) {
99 logent("PK0", "alloc change not implemented");
100 break;
102 if (val) {
103 pk->p_state |= INITa;
104 pk->p_msg |= M_INITB;
105 pk->p_rmsg |= M_INITB;
106 pk->p_swindow = val;
108 break;
109 case RJ:
110 pk->p_state |= RXMIT;
111 pk->p_msg |= M_RR;
112 DEBUG(9, "pkcntl: RJ: Connodata=%d\n", Connodata);
113 /* FALLTHRU */
114 case RR:
115 pk->p_rpr = val;
116 (void) pksack(pk);
117 break;
118 case CLOSE:
119 pk->p_state = DOWN+RCLOSE;
120 return;
122 if (pk->p_msg)
123 pkoutput(pk);
126 static int
127 pkaccept()
129 struct pack *pk;
130 int x,seq;
131 char m, cntl, *p, imask, **bp;
132 int bad,accept,skip,t,cc;
133 unsigned short sum;
135 pk = Pk;
136 bad = accept = skip = 0;
139 * wait for input
141 x = next[pk->p_pr];
142 while ((imask=pk->p_imap) == 0 && pk->p_rcount==0) {
143 pkgetpack(pk);
145 pk->p_imap = 0;
149 * determine input window in m.
151 t = (~(-1<<pk->p_rwindow)) <<x;
152 m = t;
153 m |= t>>8;
157 * mark newly accepted input buffers
159 for(x=0; x<8; x++) {
161 if ((imask & mask[x]) == 0)
162 continue;
164 if (((cntl=pk->p_is[x])&0200)==0) {
165 bad++;
166 free:
167 bp = (char **)pk->p_ib[x];
168 *bp = (char *)pk->p_ipool;
169 pk->p_ipool = bp;
170 pk->p_is[x] = 0;
171 continue;
174 pk->p_is[x] = (char) ~(B_COPY+B_MARK);
175 sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377);
176 sum += pk->p_isum[x];
177 if (sum == CHECK) {
178 seq = (cntl>>3) & MOD8;
179 if (m & mask[seq]) {
180 if (pk->p_is[seq] & (B_COPY | B_MARK)) {
181 dup:
182 pk->p_msg |= M_RR;
183 skip++;
184 goto free;
186 if (x != seq) {
187 p = pk->p_ib[x];
188 pk->p_ib[x] = pk->p_ib[seq];
189 pk->p_is[x] = pk->p_is[seq];
190 pk->p_ib[seq] = p;
192 pk->p_is[seq] = B_MARK;
193 accept++;
194 cc = 0;
195 if (cntl&B_SHORT) {
196 pk->p_is[seq] = B_MARK+B_SHORT;
197 p = pk->p_ib[seq];
198 cc = (unsigned)*p++ & 0377;
199 if (cc & 0200) {
200 cc &= 0177;
201 cc |= *p << 7;
204 pk->p_isum[seq] = pk->p_rsize - cc;
205 } else {
206 goto dup;
208 } else {
209 bad++;
210 goto free;
215 * scan window again turning marked buffers into
216 * COPY buffers and looking for missing sequence
217 * numbers.
219 accept = 0;
220 for(x=next[pk->p_pr],t= -1; m & mask[x]; x = next[x]) {
221 if (pk->p_is[x] & B_MARK)
222 pk->p_is[x] |= B_COPY;
224 if (pk->p_is[x] & B_COPY) {
225 if (t >= 0) {
226 bp = (char **)pk->p_ib[x];
227 *bp = (char *)pk->p_ipool;
228 pk->p_ipool = bp;
229 pk->p_is[x] = 0;
230 skip++;
231 } else
232 accept++;
233 } else if (t<0)
234 t = x;
237 if (bad) {
238 pk->p_msg |= M_RJ;
241 if (skip) {
242 pk->p_msg |= M_RR;
245 pk->p_rcount = accept;
246 return(accept);
251 pkread(ibuf, icount)
252 char *ibuf;
253 int icount;
255 struct pack *pk;
256 int x;
257 int is,cc,xfr,count;
258 char *cp, **bp;
260 pk = Pk;
261 xfr = 0;
262 count = 0;
263 while (pkaccept()==0)
265 Connodata = 0; /* accecpted a packet -- good data */
268 while (icount) {
270 x = next[pk->p_pr];
271 is = pk->p_is[x];
273 if (is & B_COPY) {
274 cc = MIN(pk->p_isum[x], icount);
275 if (cc==0 && xfr) {
276 break;
278 if (is & B_RESID)
279 cp = pk->p_rptr;
280 else {
281 cp = pk->p_ib[x];
282 if (is & B_SHORT) {
283 if (*cp++ & 0200)
284 cp++;
287 if (cc)
288 memcpy(ibuf, cp, cc);
289 ibuf += cc;
290 icount -= cc;
291 count += cc;
292 xfr++;
293 pk->p_isum[x] -= cc;
294 if (pk->p_isum[x] == 0) {
295 pk->p_pr = x;
296 bp = (char **)pk->p_ib[x];
297 *bp = (char *)pk->p_ipool;
298 pk->p_ipool = bp;
299 pk->p_is[x] = 0;
300 pk->p_rcount--;
301 pk->p_msg |= M_RR;
302 } else {
303 pk->p_rptr = cp+cc;
304 pk->p_is[x] |= B_RESID;
306 if (cc==0)
307 break;
308 } else
309 break;
311 pkoutput(pk);
312 return(count);
315 /* return number of bytes writtten */
317 pkwrite(ibuf, icount)
318 char *ibuf;
319 int icount;
321 struct pack *pk;
322 int x;
323 caddr_t cp;
324 int partial;
325 int cc, fc, count;
327 pk = Pk;
328 if (pk->p_state&DOWN || !pk->p_state&LIVE) {
329 return(-1);
332 count = icount;
333 do {
334 while (pk->p_xcount>=pk->p_swindow) {
335 pkoutput(pk);
336 pkgetpack(pk);
338 x = next[pk->p_pscopy];
339 while (pk->p_os[x]!=B_NULL) {
340 pkgetpack(pk);
342 pk->p_os[x] = B_MARK;
343 pk->p_pscopy = x;
344 pk->p_xcount++;
346 cp = pk->p_ob[x] = (caddr_t) malloc((unsigned) pk->p_xsize);
347 partial = 0;
348 if ((int)icount < pk->p_xsize) {
349 cc = icount;
350 fc = pk->p_xsize - cc;
351 *cp = fc&0177;
352 if (fc > 127) {
353 *cp++ |= 0200;
354 *cp++ = fc>>7;
355 } else
356 cp++;
357 partial = B_SHORT;
358 } else
359 cc = pk->p_xsize;
360 memcpy(cp, ibuf, cc);
361 ibuf += cc;
362 icount -= cc;
363 pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize);
364 pk->p_os[x] = B_READY+partial;
365 pkoutput(pk);
366 } while (icount);
368 return(count);
372 pksack(pk)
373 struct pack *pk;
375 int x, i;
377 i = 0;
378 for(x=pk->p_ps; x!=pk->p_rpr; ) {
379 x = next[x];
380 if (pk->p_os[x]&B_SENT) {
381 i++;
382 Connodata = 0;
383 pk->p_os[x] = B_NULL;
384 pk->p_state &= ~WAITO;
385 pk->p_xcount--;
386 free((char *) pk->p_ob[x]);
387 pk->p_ps = x;
390 return(i);
394 void
395 pkoutput(pk)
396 struct pack *pk;
398 int x;
399 char bstate;
400 int i;
402 if (pk->p_obusy++) {
403 pk->p_obusy--;
404 return;
409 * find seq number and buffer state
410 * of next output packet
412 if (pk->p_state&RXMIT)
413 pk->p_nxtps = next[pk->p_rpr];
414 x = pk->p_nxtps;
415 bstate = pk->p_os[x];
419 * Send control packet if indicated
421 if (pk->p_msg) {
422 if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) {
423 x = pk->p_msg;
424 for(i=0; i<8; i++)
425 if (x&1)
426 break;
427 else
428 x >>= 1;
429 x = i;
430 x <<= 3;
431 switch(i) {
432 case CLOSE:
433 break;
434 case RJ:
435 case RR:
436 x += pk->p_pr;
437 break;
438 case INITB:
439 x += pksize(pk->p_rsize);
440 break;
441 case INITC:
442 x += pk->p_rwindow;
443 break;
444 case INITA:
445 x += pk->p_rwindow;
446 break;
449 pk->p_msg &= ~mask[i];
450 pkxstart(pk, x, -1);
451 goto out;
457 * Don't send data packets if line is marked dead.
459 if (pk->p_state&DOWN) {
460 goto out;
464 * Start transmission (or retransmission) of data packets.
466 if (bstate & (B_READY|B_SENT)) {
467 char seq;
469 bstate |= B_SENT;
470 seq = x;
471 pk->p_nxtps = next[x];
473 x = 0200+pk->p_pr+(seq<<3);
474 if (bstate & B_SHORT)
475 x |= 0100;
476 pkxstart(pk, x, seq);
477 pk->p_os[seq] = bstate;
478 pk->p_state &= ~RXMIT;
479 pk->p_nout++;
480 goto out;
484 * enable timeout if there's nothing to send
485 * and transmission buffers are languishing
487 if (pk->p_xcount) {
488 pk->p_timer = 2;
489 pk->p_state |= WAITO;
490 } else
491 pk->p_state &= ~WAITO;
492 out:
493 pk->p_obusy = 0;
497 * shut down line by ignoring new input
498 * letting output drain
499 * releasing space
501 void
502 pkclose()
504 struct pack *pk;
505 int i;
506 int rcheck;
507 char **bp;
509 pk = Pk;
510 pk->p_state |= DRAINO;
513 * try to flush output
515 i = 0;
516 pk->p_timer = 2;
517 while (pk->p_xcount && pk->p_state&LIVE) {
518 if (pk->p_state&(RCLOSE+DOWN) || ++i > 2)
519 break;
520 pkoutput(pk);
522 pk->p_timer = 0;
523 pk->p_state |= DOWN;
526 * try to exchange CLOSE messages
528 i = 0;
529 while ((pk->p_state&RCLOSE)==0 && i<2) {
530 pk->p_msg = M_CLOSE;
531 pk->p_timer = 2;
532 pkoutput(pk);
533 i++;
537 * free space
539 rcheck = 0;
540 for (i=0;i<8;i++) {
541 if (pk->p_os[i]!=B_NULL) {
542 free((char *) pk->p_ob[i]);
543 pk->p_xcount--;
545 if (pk->p_is[i]!=B_NULL) {
546 free((char *) pk->p_ib[i]);
547 rcheck++;
550 while (pk->p_ipool != NULL) {
551 bp = pk->p_ipool;
552 pk->p_ipool = (char **)*bp;
553 rcheck++;
554 free((char *) bp);
556 if (rcheck != pk->p_rwindow) {
557 logent("PK0", "pkclose rcheck != p_rwindow");
559 free((char *) pk);
563 void
564 pkreset(pk)
565 struct pack *pk;
568 pk->p_ps = pk->p_pr = pk->p_rpr = 0;
569 pk->p_nxtps = 1;
572 static int
573 chksum(s,n)
574 char *s;
575 int n;
577 short sum;
578 unsigned short t;
579 short x;
581 sum = -1;
582 x = 0;
584 do {
585 if (sum<0) {
586 sum <<= 1;
587 sum++;
588 } else
589 sum <<= 1;
590 t = sum;
591 sum += (unsigned)*s++ & 0377;
592 x += sum^n;
593 if ((unsigned short)sum <= t) {
594 sum ^= x;
596 } while (--n > 0);
598 return(sum);
601 static int
602 pksize(n)
603 int n;
605 int k;
607 n >>= 5;
608 for(k=0; n >>= 1; k++);
609 return(k);