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 #include "uucp.h"
31
32 #include "pk.h"
33 #include <sys/buf.h>
34
35 extern void xlatecntl();
36 extern void pkcntl(), pkoutput(), pkclose(), pkreset(), pkzero(),
37 pkgetpack(), pkxstart();
38 extern int pkread(), pkwrite(), pksack();
39 static int pksize(), chksum(), pkaccept();
40
41 extern int Connodata; /* Continuous No Valid Data Count */
42 extern int xpacksize;
43
44 /*
45 * receive control messages
46 * c -> message type fields
47 * pk -> line control unit
48 */
49 void
pkcntl(c,pk)50 pkcntl(c, pk)
51 int c;
52 struct pack *pk;
53 {
54 int cntl, val;
55
56 val = c & MOD8;
57 cntl = (c>>3) & MOD8;
58
59 if ( ! ISCNTL(c) ) {
60 logent("PK0", "not cntl");
61 return;
62 }
63
64 if (Debug >= 9)
65 xlatecntl(0, c);
66 switch(cntl) {
67
68 case INITB:
69 val++;
70 pk->p_xsize = xpacksize = pksizes[val];
71 pk->p_lpsize = val;
72 pk->p_bits = 1;
73 if (pk->p_state & LIVE) {
74 pk->p_msg |= M_INITC;
75 break;
76 }
77 pk->p_state |= INITb;
78 if ((pk->p_state & INITa)==0) {
79 break;
80 }
81 pk->p_rmsg &= ~M_INITA;
82 pk->p_msg |= M_INITC;
83 break;
84
85 case INITC:
86 if ((pk->p_state&INITab)==INITab) {
87 pk->p_state = LIVE;
88 pk->p_rmsg &= ~M_INITB;
89 } else
90 pk->p_msg |= M_INITB;
91 if (val)
92 pk->p_swindow = val;
93 break;
94 case INITA:
95 if (val==0 && pk->p_state&LIVE) {
96 logent("PK0", "alloc change not implemented");
97 break;
98 }
99 if (val) {
100 pk->p_state |= INITa;
101 pk->p_msg |= M_INITB;
102 pk->p_rmsg |= M_INITB;
103 pk->p_swindow = val;
104 }
105 break;
106 case RJ:
107 pk->p_state |= RXMIT;
108 pk->p_msg |= M_RR;
109 DEBUG(9, "pkcntl: RJ: Connodata=%d\n", Connodata);
110 /* FALLTHRU */
111 case RR:
112 pk->p_rpr = val;
113 (void) pksack(pk);
114 break;
115 case CLOSE:
116 pk->p_state = DOWN+RCLOSE;
117 return;
118 }
119 if (pk->p_msg)
120 pkoutput(pk);
121 }
122
123 static int
pkaccept()124 pkaccept()
125 {
126 struct pack *pk;
127 int x,seq;
128 char m, cntl, *p, imask, **bp;
129 int bad,accept,skip,t,cc;
130 unsigned short sum;
131
132 pk = Pk;
133 bad = accept = skip = 0;
134
135 /*
136 * wait for input
137 */
138 x = next[pk->p_pr];
139 while ((imask=pk->p_imap) == 0 && pk->p_rcount==0) {
140 pkgetpack(pk);
141 }
142 pk->p_imap = 0;
143
144
145 /*
146 * determine input window in m.
147 */
148 t = (~(-1<<pk->p_rwindow)) <<x;
149 m = t;
150 m |= t>>8;
151
152
153 /*
154 * mark newly accepted input buffers
155 */
156 for(x=0; x<8; x++) {
157
158 if ((imask & mask[x]) == 0)
159 continue;
160
161 if (((cntl=pk->p_is[x])&0200)==0) {
162 bad++;
163 free:
164 bp = (char **)pk->p_ib[x];
165 *bp = (char *)pk->p_ipool;
166 pk->p_ipool = bp;
167 pk->p_is[x] = 0;
168 continue;
169 }
170
171 pk->p_is[x] = (char) ~(B_COPY+B_MARK);
172 sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377);
173 sum += pk->p_isum[x];
174 if (sum == CHECK) {
175 seq = (cntl>>3) & MOD8;
176 if (m & mask[seq]) {
177 if (pk->p_is[seq] & (B_COPY | B_MARK)) {
178 dup:
179 pk->p_msg |= M_RR;
180 skip++;
181 goto free;
182 }
183 if (x != seq) {
184 p = pk->p_ib[x];
185 pk->p_ib[x] = pk->p_ib[seq];
186 pk->p_is[x] = pk->p_is[seq];
187 pk->p_ib[seq] = p;
188 }
189 pk->p_is[seq] = B_MARK;
190 accept++;
191 cc = 0;
192 if (cntl&B_SHORT) {
193 pk->p_is[seq] = B_MARK+B_SHORT;
194 p = pk->p_ib[seq];
195 cc = (unsigned)*p++ & 0377;
196 if (cc & 0200) {
197 cc &= 0177;
198 cc |= *p << 7;
199 }
200 }
201 pk->p_isum[seq] = pk->p_rsize - cc;
202 } else {
203 goto dup;
204 }
205 } else {
206 bad++;
207 goto free;
208 }
209 }
210
211 /*
212 * scan window again turning marked buffers into
213 * COPY buffers and looking for missing sequence
214 * numbers.
215 */
216 accept = 0;
217 for(x=next[pk->p_pr],t= -1; m & mask[x]; x = next[x]) {
218 if (pk->p_is[x] & B_MARK)
219 pk->p_is[x] |= B_COPY;
220
221 if (pk->p_is[x] & B_COPY) {
222 if (t >= 0) {
223 bp = (char **)pk->p_ib[x];
224 *bp = (char *)pk->p_ipool;
225 pk->p_ipool = bp;
226 pk->p_is[x] = 0;
227 skip++;
228 } else
229 accept++;
230 } else if (t<0)
231 t = x;
232 }
233
234 if (bad) {
235 pk->p_msg |= M_RJ;
236 }
237
238 if (skip) {
239 pk->p_msg |= M_RR;
240 }
241
242 pk->p_rcount = accept;
243 return(accept);
244 }
245
246
247 int
pkread(ibuf,icount)248 pkread(ibuf, icount)
249 char *ibuf;
250 int icount;
251 {
252 struct pack *pk;
253 int x;
254 int is,cc,xfr,count;
255 char *cp, **bp;
256
257 pk = Pk;
258 xfr = 0;
259 count = 0;
260 while (pkaccept()==0)
261 ;
262 Connodata = 0; /* accecpted a packet -- good data */
263
264
265 while (icount) {
266
267 x = next[pk->p_pr];
268 is = pk->p_is[x];
269
270 if (is & B_COPY) {
271 cc = MIN(pk->p_isum[x], icount);
272 if (cc==0 && xfr) {
273 break;
274 }
275 if (is & B_RESID)
276 cp = pk->p_rptr;
277 else {
278 cp = pk->p_ib[x];
279 if (is & B_SHORT) {
280 if (*cp++ & 0200)
281 cp++;
282 }
283 }
284 if (cc)
285 memcpy(ibuf, cp, cc);
286 ibuf += cc;
287 icount -= cc;
288 count += cc;
289 xfr++;
290 pk->p_isum[x] -= cc;
291 if (pk->p_isum[x] == 0) {
292 pk->p_pr = x;
293 bp = (char **)pk->p_ib[x];
294 *bp = (char *)pk->p_ipool;
295 pk->p_ipool = bp;
296 pk->p_is[x] = 0;
297 pk->p_rcount--;
298 pk->p_msg |= M_RR;
299 } else {
300 pk->p_rptr = cp+cc;
301 pk->p_is[x] |= B_RESID;
302 }
303 if (cc==0)
304 break;
305 } else
306 break;
307 }
308 pkoutput(pk);
309 return(count);
310 }
311
312 /* return number of bytes writtten */
313 int
pkwrite(ibuf,icount)314 pkwrite(ibuf, icount)
315 char *ibuf;
316 int icount;
317 {
318 struct pack *pk;
319 int x;
320 caddr_t cp;
321 int partial;
322 int cc, fc, count;
323
324 pk = Pk;
325 if (pk->p_state&DOWN || !pk->p_state&LIVE) {
326 return(-1);
327 }
328
329 count = icount;
330 do {
331 while (pk->p_xcount>=pk->p_swindow) {
332 pkoutput(pk);
333 pkgetpack(pk);
334 }
335 x = next[pk->p_pscopy];
336 while (pk->p_os[x]!=B_NULL) {
337 pkgetpack(pk);
338 }
339 pk->p_os[x] = B_MARK;
340 pk->p_pscopy = x;
341 pk->p_xcount++;
342
343 cp = pk->p_ob[x] = (caddr_t) malloc((unsigned) pk->p_xsize);
344 partial = 0;
345 if ((int)icount < pk->p_xsize) {
346 cc = icount;
347 fc = pk->p_xsize - cc;
348 *cp = fc&0177;
349 if (fc > 127) {
350 *cp++ |= 0200;
351 *cp++ = fc>>7;
352 } else
353 cp++;
354 partial = B_SHORT;
355 } else
356 cc = pk->p_xsize;
357 memcpy(cp, ibuf, cc);
358 ibuf += cc;
359 icount -= cc;
360 pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize);
361 pk->p_os[x] = B_READY+partial;
362 pkoutput(pk);
363 } while (icount);
364
365 return(count);
366 }
367
368 int
pksack(pk)369 pksack(pk)
370 struct pack *pk;
371 {
372 int x, i;
373
374 i = 0;
375 for(x=pk->p_ps; x!=pk->p_rpr; ) {
376 x = next[x];
377 if (pk->p_os[x]&B_SENT) {
378 i++;
379 Connodata = 0;
380 pk->p_os[x] = B_NULL;
381 pk->p_state &= ~WAITO;
382 pk->p_xcount--;
383 free((char *) pk->p_ob[x]);
384 pk->p_ps = x;
385 }
386 }
387 return(i);
388 }
389
390
391 void
pkoutput(pk)392 pkoutput(pk)
393 struct pack *pk;
394 {
395 int x;
396 char bstate;
397 int i;
398
399 if (pk->p_obusy++) {
400 pk->p_obusy--;
401 return;
402 }
403
404
405 /*
406 * find seq number and buffer state
407 * of next output packet
408 */
409 if (pk->p_state&RXMIT)
410 pk->p_nxtps = next[pk->p_rpr];
411 x = pk->p_nxtps;
412 bstate = pk->p_os[x];
413
414
415 /*
416 * Send control packet if indicated
417 */
418 if (pk->p_msg) {
419 if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) {
420 x = pk->p_msg;
421 for(i=0; i<8; i++)
422 if (x&1)
423 break;
424 else
425 x >>= 1;
426 x = i;
427 x <<= 3;
428 switch(i) {
429 case CLOSE:
430 break;
431 case RJ:
432 case RR:
433 x += pk->p_pr;
434 break;
435 case INITB:
436 x += pksize(pk->p_rsize);
437 break;
438 case INITC:
439 x += pk->p_rwindow;
440 break;
441 case INITA:
442 x += pk->p_rwindow;
443 break;
444 }
445
446 pk->p_msg &= ~mask[i];
447 pkxstart(pk, x, -1);
448 goto out;
449 }
450 }
451
452
453 /*
454 * Don't send data packets if line is marked dead.
455 */
456 if (pk->p_state&DOWN) {
457 goto out;
458 }
459
460 /*
461 * Start transmission (or retransmission) of data packets.
462 */
463 if (bstate & (B_READY|B_SENT)) {
464 char seq;
465
466 bstate |= B_SENT;
467 seq = x;
468 pk->p_nxtps = next[x];
469
470 x = 0200+pk->p_pr+(seq<<3);
471 if (bstate & B_SHORT)
472 x |= 0100;
473 pkxstart(pk, x, seq);
474 pk->p_os[seq] = bstate;
475 pk->p_state &= ~RXMIT;
476 pk->p_nout++;
477 goto out;
478 }
479
480 /*
481 * enable timeout if there's nothing to send
482 * and transmission buffers are languishing
483 */
484 if (pk->p_xcount) {
485 pk->p_timer = 2;
486 pk->p_state |= WAITO;
487 } else
488 pk->p_state &= ~WAITO;
489 out:
490 pk->p_obusy = 0;
491 }
492
493 /*
494 * shut down line by ignoring new input
495 * letting output drain
496 * releasing space
497 */
498 void
pkclose()499 pkclose()
500 {
501 struct pack *pk;
502 int i;
503 int rcheck;
504 char **bp;
505
506 pk = Pk;
507 pk->p_state |= DRAINO;
508
509 /*
510 * try to flush output
511 */
512 i = 0;
513 pk->p_timer = 2;
514 while (pk->p_xcount && pk->p_state&LIVE) {
515 if (pk->p_state&(RCLOSE+DOWN) || ++i > 2)
516 break;
517 pkoutput(pk);
518 }
519 pk->p_timer = 0;
520 pk->p_state |= DOWN;
521
522 /*
523 * try to exchange CLOSE messages
524 */
525 i = 0;
526 while ((pk->p_state&RCLOSE)==0 && i<2) {
527 pk->p_msg = M_CLOSE;
528 pk->p_timer = 2;
529 pkoutput(pk);
530 i++;
531 }
532
533 /*
534 * free space
535 */
536 rcheck = 0;
537 for (i=0;i<8;i++) {
538 if (pk->p_os[i]!=B_NULL) {
539 free((char *) pk->p_ob[i]);
540 pk->p_xcount--;
541 }
542 if (pk->p_is[i]!=B_NULL) {
543 free((char *) pk->p_ib[i]);
544 rcheck++;
545 }
546 }
547 while (pk->p_ipool != NULL) {
548 bp = pk->p_ipool;
549 pk->p_ipool = (char **)*bp;
550 rcheck++;
551 free((char *) bp);
552 }
553 if (rcheck != pk->p_rwindow) {
554 logent("PK0", "pkclose rcheck != p_rwindow");
555 }
556 free((char *) pk);
557 }
558
559
560 void
pkreset(pk)561 pkreset(pk)
562 struct pack *pk;
563 {
564
565 pk->p_ps = pk->p_pr = pk->p_rpr = 0;
566 pk->p_nxtps = 1;
567 }
568
569 static int
chksum(s,n)570 chksum(s,n)
571 char *s;
572 int n;
573 {
574 short sum;
575 unsigned short t;
576 short x;
577
578 sum = -1;
579 x = 0;
580
581 do {
582 if (sum<0) {
583 sum <<= 1;
584 sum++;
585 } else
586 sum <<= 1;
587 t = sum;
588 sum += (unsigned)*s++ & 0377;
589 x += sum^n;
590 if ((unsigned short)sum <= t) {
591 sum ^= x;
592 }
593 } while (--n > 0);
594
595 return(sum);
596 }
597
598 static int
pksize(n)599 pksize(n)
600 int n;
601 {
602 int k;
603
604 n >>= 5;
605 for(k=0; n >>= 1; k++);
606 return(k);
607 }
608