1 /*
2 * CDDL HEADER START
3 *
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.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32
33 #include "uucp.h"
34
35 #include "pk.h"
36 #include <sys/buf.h>
37
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();
43
44 extern int Connodata; /* Continuous No Valid Data Count */
45 extern int xpacksize;
46
47 /*
48 * receive control messages
49 * c -> message type fields
50 * pk -> line control unit
51 */
52 void
pkcntl(c,pk)53 pkcntl(c, pk)
54 int c;
55 struct pack *pk;
56 {
57 int cntl, val;
58
59 val = c & MOD8;
60 cntl = (c>>3) & MOD8;
61
62 if ( ! ISCNTL(c) ) {
63 logent("PK0", "not cntl");
64 return;
65 }
66
67 if (Debug >= 9)
68 xlatecntl(0, c);
69 switch(cntl) {
70
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;
79 }
80 pk->p_state |= INITb;
81 if ((pk->p_state & INITa)==0) {
82 break;
83 }
84 pk->p_rmsg &= ~M_INITA;
85 pk->p_msg |= M_INITC;
86 break;
87
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;
101 }
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;
107 }
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;
121 }
122 if (pk->p_msg)
123 pkoutput(pk);
124 }
125
126 static int
pkaccept()127 pkaccept()
128 {
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;
134
135 pk = Pk;
136 bad = accept = skip = 0;
137
138 /*
139 * wait for input
140 */
141 x = next[pk->p_pr];
142 while ((imask=pk->p_imap) == 0 && pk->p_rcount==0) {
143 pkgetpack(pk);
144 }
145 pk->p_imap = 0;
146
147
148 /*
149 * determine input window in m.
150 */
151 t = (~(-1<<pk->p_rwindow)) <<x;
152 m = t;
153 m |= t>>8;
154
155
156 /*
157 * mark newly accepted input buffers
158 */
159 for(x=0; x<8; x++) {
160
161 if ((imask & mask[x]) == 0)
162 continue;
163
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;
172 }
173
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;
185 }
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;
191 }
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;
202 }
203 }
204 pk->p_isum[seq] = pk->p_rsize - cc;
205 } else {
206 goto dup;
207 }
208 } else {
209 bad++;
210 goto free;
211 }
212 }
213
214 /*
215 * scan window again turning marked buffers into
216 * COPY buffers and looking for missing sequence
217 * numbers.
218 */
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;
223
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;
235 }
236
237 if (bad) {
238 pk->p_msg |= M_RJ;
239 }
240
241 if (skip) {
242 pk->p_msg |= M_RR;
243 }
244
245 pk->p_rcount = accept;
246 return(accept);
247 }
248
249
250 int
pkread(ibuf,icount)251 pkread(ibuf, icount)
252 char *ibuf;
253 int icount;
254 {
255 struct pack *pk;
256 int x;
257 int is,cc,xfr,count;
258 char *cp, **bp;
259
260 pk = Pk;
261 xfr = 0;
262 count = 0;
263 while (pkaccept()==0)
264 ;
265 Connodata = 0; /* accecpted a packet -- good data */
266
267
268 while (icount) {
269
270 x = next[pk->p_pr];
271 is = pk->p_is[x];
272
273 if (is & B_COPY) {
274 cc = MIN(pk->p_isum[x], icount);
275 if (cc==0 && xfr) {
276 break;
277 }
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++;
285 }
286 }
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;
305 }
306 if (cc==0)
307 break;
308 } else
309 break;
310 }
311 pkoutput(pk);
312 return(count);
313 }
314
315 /* return number of bytes writtten */
316 int
pkwrite(ibuf,icount)317 pkwrite(ibuf, icount)
318 char *ibuf;
319 int icount;
320 {
321 struct pack *pk;
322 int x;
323 caddr_t cp;
324 int partial;
325 int cc, fc, count;
326
327 pk = Pk;
328 if (pk->p_state&DOWN || !pk->p_state&LIVE) {
329 return(-1);
330 }
331
332 count = icount;
333 do {
334 while (pk->p_xcount>=pk->p_swindow) {
335 pkoutput(pk);
336 pkgetpack(pk);
337 }
338 x = next[pk->p_pscopy];
339 while (pk->p_os[x]!=B_NULL) {
340 pkgetpack(pk);
341 }
342 pk->p_os[x] = B_MARK;
343 pk->p_pscopy = x;
344 pk->p_xcount++;
345
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);
367
368 return(count);
369 }
370
371 int
pksack(pk)372 pksack(pk)
373 struct pack *pk;
374 {
375 int x, i;
376
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;
388 }
389 }
390 return(i);
391 }
392
393
394 void
pkoutput(pk)395 pkoutput(pk)
396 struct pack *pk;
397 {
398 int x;
399 char bstate;
400 int i;
401
402 if (pk->p_obusy++) {
403 pk->p_obusy--;
404 return;
405 }
406
407
408 /*
409 * find seq number and buffer state
410 * of next output packet
411 */
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];
416
417
418 /*
419 * Send control packet if indicated
420 */
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;
447 }
448
449 pk->p_msg &= ~mask[i];
450 pkxstart(pk, x, -1);
451 goto out;
452 }
453 }
454
455
456 /*
457 * Don't send data packets if line is marked dead.
458 */
459 if (pk->p_state&DOWN) {
460 goto out;
461 }
462
463 /*
464 * Start transmission (or retransmission) of data packets.
465 */
466 if (bstate & (B_READY|B_SENT)) {
467 char seq;
468
469 bstate |= B_SENT;
470 seq = x;
471 pk->p_nxtps = next[x];
472
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;
481 }
482
483 /*
484 * enable timeout if there's nothing to send
485 * and transmission buffers are languishing
486 */
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;
494 }
495
496 /*
497 * shut down line by ignoring new input
498 * letting output drain
499 * releasing space
500 */
501 void
pkclose()502 pkclose()
503 {
504 struct pack *pk;
505 int i;
506 int rcheck;
507 char **bp;
508
509 pk = Pk;
510 pk->p_state |= DRAINO;
511
512 /*
513 * try to flush output
514 */
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);
521 }
522 pk->p_timer = 0;
523 pk->p_state |= DOWN;
524
525 /*
526 * try to exchange CLOSE messages
527 */
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++;
534 }
535
536 /*
537 * free space
538 */
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--;
544 }
545 if (pk->p_is[i]!=B_NULL) {
546 free((char *) pk->p_ib[i]);
547 rcheck++;
548 }
549 }
550 while (pk->p_ipool != NULL) {
551 bp = pk->p_ipool;
552 pk->p_ipool = (char **)*bp;
553 rcheck++;
554 free((char *) bp);
555 }
556 if (rcheck != pk->p_rwindow) {
557 logent("PK0", "pkclose rcheck != p_rwindow");
558 }
559 free((char *) pk);
560 }
561
562
563 void
pkreset(pk)564 pkreset(pk)
565 struct pack *pk;
566 {
567
568 pk->p_ps = pk->p_pr = pk->p_rpr = 0;
569 pk->p_nxtps = 1;
570 }
571
572 static int
chksum(s,n)573 chksum(s,n)
574 char *s;
575 int n;
576 {
577 short sum;
578 unsigned short t;
579 short x;
580
581 sum = -1;
582 x = 0;
583
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;
595 }
596 } while (--n > 0);
597
598 return(sum);
599 }
600
601 static int
pksize(n)602 pksize(n)
603 int n;
604 {
605 int k;
606
607 n >>= 5;
608 for(k=0; n >>= 1; k++);
609 return(k);
610 }
611