|
|
1.1 root 1: /*
2: * Packet protocol processor
3: */
4:
5: #include "../h/param.h"
6: #include "../h/stream.h"
7: #include "../h/conf.h"
8: #include "../h/ioctl.h"
9: #include "../h/ttyld.h"
10: #include "pk.h"
11:
12: struct pack {
13: u_char istate;
14: u_char ostate;
15: u_char xlogseg; /* code for xmit segment size */
16: u_char S; /* current output seqno */
17: u_char SN; /* next output seqno */
18: u_char XW; /* size of output window */
19: u_char R; /* current input seqno */
20: u_char timer;
21: short xsegment; /* output segment size */
22: short iwant; /* # chars needed before i q enable */
23: struct block *xpacks[8]; /* waiting output blocks */
24: struct {
25: u_char k; /* packet size */
26: u_char c0; /* low checksum byte */
27: u_char c1; /* high checksum byte */
28: u_char C; /* control byte */
29: u_char x; /* header check */
30: } hdr; /* copy of header of received segment */
31: struct queue *rdq; /* associated read queue */
32: };
33:
34: #define PK_TYPE 0xC0
35: #define PKCNTL 0x00
36: #define PKDATA 0x80
37: #define PKSDATA 0xC0
38:
39: #define PK_CLOSE 010
40: #define PK_RJ 020
41: #define PK_RR 040
42: #define PK_INITC 050
43: #define PK_INITB 060
44: #define PK_INITA 070
45:
46: #define CHECK 0125252
47:
48: #define WDATA 01
49: #define PKDELIM 02
50: #define PKREJ 04
51:
52: #define SYN 020 /* sic */
53:
54: #define SINITA 1
55: #define SINITB 2
56: #define SINITC 3
57: #define OPEN 4
58: #define LCLOSE 5
59: #define RCLOSE 6
60:
61: #define PKPRI 28
62: #define DKDATA 0400
63:
64: #define RWINSIZE 3
65: #define RSEGSIZE 1 /* 64 bytes */
66:
67: #define PKTIME 5
68:
69: struct pack packs[NPK];
70: short pksizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
71: u_short pkc_sum;
72: u_short pkc_x;
73: int pkc_size;
74:
75: int pkiput(), pkisrv(), pkoput(), pkosrv(), pkopen(), pkclose();
76: static struct qinit pkrinit = { pkiput, pkisrv, pkopen, pkclose, 512, 64 };
77: static struct qinit pkwinit = { pkoput, pkosrv, pkopen, pkclose, 128, 65 };
78: struct streamtab pkinfo = { &pkrinit, &pkwinit };
79:
80: pkopen(q)
81: register struct queue *q;
82: {
83: register struct pack *pkp;
84: register s;
85: static timer = 0;
86: int pktimer();
87:
88: if (q->ptr) {
89: pkp = (struct pack *)q->ptr;
90: if (pkp->ostate != OPEN)
91: return(0); /* don't reopen half-open chans */
92: return(1);
93: } else {
94: for (pkp = packs; pkp->ostate!=0; pkp++)
95: if (pkp >= &packs[NPK])
96: return(0);
97: pkp->rdq = q;
98: q->ptr = (caddr_t)pkp;
99: WR(q)->ptr = (caddr_t)pkp;
100: pkp->S = 1;
101: pkp->SN = 1;
102: pkp->R = 0;
103: putctl(q->next, M_FLUSH);
104: pkp->ostate = SINITA;
105: pkp->istate = 0;
106: pkp->timer = 2;
107: pkscntl(pkp, PK_INITA+RWINSIZE);
108: }
109: if (timer == 0) {
110: timer = 1;
111: timeout(pktimer, (caddr_t)NULL, 60);
112: }
113: s = spl5();
114: while (pkp->ostate != OPEN) {
115: switch (tsleep((caddr_t)pkp, PKPRI, 15)) {
116: case TS_OK:
117: continue;
118: case TS_SIG:
119: case TS_TIME:
120: pkp->ostate = 0;
121: splx(s);
122: return(0);
123: }
124: }
125: q->flag |= QDELIM;
126: splx(s);
127: return(1);
128: }
129:
130: /*
131: * Shut it down.
132: * The problem is to dispose of unacked stuff in the window.
133: * -- no real solution; the receiver might hang on for hours.
134: * Give it 15 seconds.
135: */
136: pkclose(q)
137: register struct queue *q;
138: {
139: register struct pack *pkp;
140: register s = spl5();
141: register i;
142:
143: pkp = (struct pack *)q->ptr;
144: pkp->ostate = LCLOSE;
145: flushq(q, 1);
146: for (i=0; pkp->S < pkp->SN && i<15; i++)
147: tsleep((caddr_t)pkp, PKPRI, 1);
148: splx(s);
149: flushq(WR(q), 1);
150: pkrack(pkp, pkp->SN-1, 0);
151: pkscntl(pkp, PK_CLOSE);
152: pkp->ostate = 0;
153: }
154:
155:
156: /*
157: * Process a bunch of input
158: */
159: pkisrv(q)
160: register struct queue *q;
161: {
162: register struct pack *pkp = (struct pack *)q->ptr;
163: register struct block *bp;
164: register segsize, msgsize;
165: int R, OK;
166: u_char c;
167:
168: more:
169: while ((pkp->istate & WDATA) == 0) {
170: if (pkwant(pkp, 6)==0)
171: return;
172: pkgetb(q, &c, 1);
173: if (c != SYN)
174: continue;
175: pkgetb(q, (u_char *)&pkp->hdr, 5);
176: if (pkp->hdr.x != (pkp->hdr.k ^ pkp->hdr.c0 ^
177: pkp->hdr.c1 ^ pkp->hdr.C)) { /* bad header? */
178: continue;
179: }
180: switch (pkp->hdr.C & PK_TYPE) {
181: case PKCNTL:
182: pkp->istate &= ~PKREJ;
183: pkcntl(pkp);
184: continue;
185:
186: case PKDATA:
187: case PKSDATA:
188: if (pkp->ostate==SINITC) {
189: pkp->ostate = OPEN;
190: wakeup((caddr_t)pkp);
191: }
192: if (pkp->S != pkp->SN) /* if need an ack */
193: pkrack(pkp, pkp->hdr.C&07, 0);
194: if (pkp->hdr.k<1 || pkp->hdr.k>8) {
195: continue;
196: }
197: pkp->istate |= WDATA;
198: break;
199:
200: default:
201: continue;
202: }
203: break;
204: }
205: if (q->next->flag&QFULL)
206: return;
207: msgsize = segsize = pksizes[pkp->hdr.k];
208: if (pkwant(pkp, segsize) == 0)
209: return;
210: /*
211: * Now have a segment's worth of data; if in window, compute checksum
212: * and accept if all is OK
213: */
214: R = (pkp->hdr.C>>3) & 07;
215: if (R <= pkp->R)
216: R += 8;
217: /* compute checksum */
218: OK = 0;
219: pkc_sum = -1;
220: pkc_x = 0;
221: pkc_size = segsize;
222: for (bp = q->first; segsize>0; bp = bp->next) {
223: register sz = bp->wptr - bp->rptr;
224: pkcksum(bp->rptr, sz);
225: segsize -= sz;
226: }
227: segsize = msgsize;
228: pkc_sum ^= pkp->hdr.C;
229: pkc_sum += (pkp->hdr.c1<<8) + pkp->hdr.c0;
230: if (pkc_sum != CHECK || R != pkp->R+1) { /* Bad? */
231: if (R < pkp->R+RWINSIZE) {
232: flushq(q, 0);
233: if ((pkp->istate & PKREJ) == 0)
234: pkscntl(pkp, PK_RJ+pkp->R);
235: pkp->istate &= ~WDATA;
236: pkp->istate |= PKREJ;
237: goto more;
238: }
239: msgsize = -1; /* duplicate; just ignore */
240: } else { /* It's good */
241: pkp->R = (pkp->R+1)&07;
242: OK = 1;
243: if ((pkp->hdr.C&PK_TYPE) == PKSDATA) {
244: pkgetb(q, &c, 1);
245: msgsize -= c & 0x7F;
246: segsize -= 1;
247: if (c&0x80) {
248: pkgetb(q, &c, 1);
249: msgsize -= c << 7;
250: segsize -= 1;
251: }
252: }
253: }
254: pkp->istate &= ~PKREJ;
255: pkscntl(pkp, PK_RR+pkp->R);
256: while (segsize > 0) {
257: register i;
258: bp = getq(q);
259: i = bp->wptr - bp->rptr;
260: if (i <= msgsize) {
261: (*q->next->qinfo->putp)(q->next, bp);
262: msgsize -= i;
263: segsize -= i;
264: continue;
265: }
266: if (msgsize>0) {
267: register struct block *bp1 = allocb(msgsize);
268: if (bp1) {
269: bcopy(bp->rptr, bp1->wptr, msgsize);
270: bp->rptr += msgsize;
271: bp1->wptr += msgsize;
272: (*q->next->qinfo->putp)(q->next, bp1);
273: segsize -= msgsize;
274: msgsize = 0;
275: putbq(q, bp);
276: continue;
277: } else
278: panic("pk alloc\n");
279: }
280: if (i <= segsize) {
281: freeb(bp);
282: segsize -= i;
283: continue;
284: }
285: bp->rptr += segsize;
286: putbq(q, bp);
287: break;
288: }
289: if (OK)
290: putctl(q->next, M_DELIM);
291: pkp->istate &= ~WDATA;
292: goto more;
293: }
294:
295: /*
296: * Packet arrives.
297: */
298: pkiput(q, bp)
299: struct queue *q;
300: register struct block *bp;
301: {
302: register struct pack *pkp;
303: register c;
304:
305: if ((pkp = (struct pack *)q->ptr)==NULL || pkp->ostate==LCLOSE) {
306: freeb(bp);
307: return;
308: }
309: switch (bp->type) {
310:
311: case M_DATA:
312: if (q->flag&QFULL) {
313: freeb(bp);
314: return;
315: }
316: if ((pkp->iwant -= bp->wptr - bp->rptr) <= 0) {
317: pkp->iwant = 0;
318: qenable(q);
319: }
320: putq(q, bp);
321: return;
322:
323: case M_HANGUP:
324: pkp->ostate = RCLOSE;
325: flushq(WR(q), 0);
326: pkrack(pkp, pkp->SN-1, 0);
327: qenable(q);
328: freeb(bp);
329: return;
330:
331: case M_IOCACK:
332: case M_IOCNAK:
333: (*q->next->qinfo->putp)(q->next, bp);
334: return;
335:
336: default:
337: freeb(bp);
338: return;
339: }
340: }
341:
342: /*
343: * --- Output processor
344: */
345:
346: /*
347: * accept data from writer
348: * -- handle all non-data messages
349: */
350: pkoput(q, bp)
351: register struct queue *q;
352: register struct block *bp;
353: {
354: register struct pack *pkp = (struct pack *)q->ptr;
355: register union stmsg *sp;
356:
357: if (pkp->ostate == RCLOSE) {
358: freeb(bp);
359: return;
360: }
361: switch (bp->type) {
362:
363: case M_DELIM:
364: if (pkp->istate & PKDELIM)
365: goto isdata;
366: pkp->istate |= PKDELIM;
367: /* flow through */
368: case M_FLUSH:
369: freeb(bp);
370: return;
371:
372: case M_IOCTL:
373: sp = (union stmsg *)bp->rptr;
374: switch (sp->ioc0.com) {
375:
376: case TIOCGETP:
377: sp->ioc1.sb.sg_erase = 0;
378: sp->ioc1.sb.sg_kill = 0;
379: sp->ioc1.sb.sg_flags = RAW;
380: bp->wptr = bp->rptr+sizeof(struct ioc1);
381: bp->type = M_IOCACK;
382: qreply(q, bp);
383: break;
384:
385: default:
386: (*q->next->qinfo->putp)(q->next, bp);
387: break;
388: }
389: return;
390:
391: default:
392: freeb(bp);
393: return;
394:
395: case M_DATA:
396: pkp->istate &= ~PKDELIM;
397: isdata:
398: putq(q, bp);
399: if (pkp->SN < pkp->S + pkp->XW)
400: qenable(q);
401: return;
402: }
403: }
404:
405: /*
406: * PK out server:
407: * if space in window, process queue
408: * take care of splitting packets bigger than segment size
409: * if timer has expired, retransmit
410: */
411: pkosrv(q)
412: register struct queue *q;
413: {
414: register struct pack *pkp = (struct pack *)q->ptr;
415: register struct block *bp, *xbp;
416:
417: if (pkp->timer==0 && pkp->S != pkp->SN)
418: pkxmit(q, pkp->xpacks[pkp->S], pkp->S);
419: while (pkp->SN < pkp->S + pkp->XW) {
420: if ((bp = getq(q)) == NULL)
421: break;
422: if (bp->wptr-bp->rptr > pkp->xsegment) {
423: if ((xbp = allocb(pkp->xsegment)) == NULL) {
424: putbq(q, bp);
425: return;
426: }
427: bcopy(bp->rptr, xbp->wptr, pkp->xsegment);
428: bp->rptr += pkp->xsegment;
429: xbp->wptr += pkp->xsegment;
430: putbq(q, bp);
431: bp = xbp;
432: }
433: bp->type = M_DATA; /* M_DELIM -> 0-length write */
434: pkp->xpacks[pkp->SN & 07] = bp;
435: pkxmit(q, bp, pkp->SN);
436: pkp->SN++;
437: }
438: }
439:
440: /*
441: * Send out a packet, with header.
442: * -- only a "pointer" to the data is sent; the original
443: * is kept.
444: */
445: pkxmit(q, bp, pkno)
446: struct queue *q;
447: register struct block *bp;
448: unsigned pkno;
449: {
450: register struct block *hbp;
451: register size;
452: register seg;
453: register struct pack *pkp = (struct pack *)q->ptr;
454: register struct block *sbp = NULL;
455: register sizeadjust = 0;
456: static u_char zero[64];
457:
458: if (bp == (struct block *)NULL) {
459: printf("0 bp in pkxmit\n");
460: return;
461: }
462: pkp->timer = PKTIME;
463: if ((hbp = allocb(8)) == NULL)
464: return; /* hope timeouts will recover */
465: pkno &= 07;
466: size = bp->wptr - bp->rptr;
467: /* compute header */
468: hbp->wptr += 6; /* header size */
469: hbp->rptr[0] = SYN;
470: hbp->rptr[1] = pkp->xlogseg;
471: seg = pkp->xsegment;
472: pkc_sum = -1;
473: pkc_x = 0;
474: pkc_size = seg;
475: if (size < seg) {
476: hbp->rptr[4] = PKSDATA | (pkno << 3) | pkp->R;
477: if ((sbp = allocb(2)) == NULL) {
478: freeb(hbp);
479: return;
480: }
481: /* hack in the size bytes */
482: if ((seg - size) <= 127) {
483: *sbp->wptr++ = seg - size;
484: sizeadjust = 1;
485: } else {
486: *sbp->wptr++ = 0x80 + ((seg - size) & 0x7F);
487: *sbp->wptr++ = (seg - size) >> 7;
488: sizeadjust = 2;
489: }
490: pkcksum(sbp->rptr, sizeadjust);
491: pkcksum(bp->rptr, size);
492: seg -= size;
493: while (seg>0) {
494: pkcksum(zero, 64);
495: seg -= 64;
496: }
497: } else {
498: if (size > seg) {
499: printf("pk size botch\n");
500: return;
501: }
502: hbp->rptr[4] = PKDATA | (pkno<<3) | pkp->R;
503: pkcksum(bp->rptr, size);
504: }
505: pkc_sum = CHECK - (pkc_sum ^ hbp->rptr[4]);
506: hbp->rptr[2] = pkc_sum;
507: hbp->rptr[3] = pkc_sum>>8;
508: hbp->rptr[5] = hbp->rptr[1]^hbp->rptr[2]^hbp->rptr[3]^hbp->rptr[4];
509: /* send header */
510: (*q->next->qinfo->putp)(q->next, hbp);
511: /* send size */
512: if (sbp)
513: (*q->next->qinfo->putp)(q->next, sbp);
514: /* send data ptr */
515: if (hbp = allocb(0)) { /* if fail, pray for timeout */
516: hbp->rptr = bp->rptr; /* copy ptrs */
517: hbp->wptr = bp->wptr;
518: (*q->next->qinfo->putp)(q->next, hbp); /* send data */
519: }
520: /* send padding */
521: seg = pkp->xsegment - sizeadjust;
522: while (size < seg) {
523: register deficit = seg - size;
524: if (deficit > 64)
525: deficit = 64;
526: if (hbp = allocb(deficit)) {
527: hbp->rptr = zero;
528: hbp->wptr = zero + deficit;
529: (*q->next->qinfo->putp)(q->next, hbp);
530: }
531: size += deficit;
532: }
533: }
534:
535: /*
536: * Receive an ack for a transmitted packet.
537: * Advance the window. Retransmit stacked up stuff if required.
538: */
539: pkrack(pkp, packno, rxmit)
540: register unsigned packno;
541: register struct pack *pkp;
542: {
543: register struct block **bpp;
544: register s = spl5();
545:
546: packno &= 07;
547: if (packno < pkp->S)
548: packno += 8;
549: pkp->timer = PKTIME;
550: if (packno < pkp->SN)
551: while (pkp->S <= packno) {
552: bpp = &pkp->xpacks[pkp->S & 07];
553: if (*bpp) {
554: freeb(*bpp);
555: *bpp = NULL;
556: }
557: pkp->S++;
558: }
559: if (WR(pkp->rdq)->count)
560: qenable(WR(pkp->rdq));
561: if (rxmit) {
562: for (packno = pkp->S; packno < pkp->SN; packno++)
563: pkxmit(WR(pkp->rdq), pkp->xpacks[packno&07], packno);
564: }
565: if (pkp->S >= 8) {
566: pkp->S -= 8;
567: pkp->SN -= 8;
568: }
569: splx(s);
570: }
571:
572: /*
573: * If n bytes are available, return 1, else 0.
574: */
575: pkwant(pkp, n)
576: register n;
577: register struct pack *pkp;
578: {
579: register int navail = 0;
580: register struct block *bp;
581: int s = spl5();
582:
583: for (bp = pkp->rdq->first; bp; bp = bp->next) {
584: navail += bp->wptr - bp->rptr;
585: if (navail >= n) {
586: splx(s);
587: return(1);
588: }
589: }
590: if (pkp->ostate==RCLOSE)
591: putctl(pkp->rdq->next, M_HANGUP);
592: pkp->iwant = n - navail;
593: splx(s);
594: return(0);
595: }
596:
597: /*
598: * Copy n bytes from the front of the queue.
599: */
600: pkgetb(q, cp, n)
601: register struct queue *q;
602: register u_char *cp;
603: register n;
604: {
605: register struct block *bp;
606:
607: while (n) {
608: if ((bp = q->first) == NULL) {
609: printf("pkgetb fail\n");
610: return;
611: }
612: if (bp->rptr >= bp->wptr) {
613: freeb(getq(q));
614: continue;
615: }
616: *cp++ = *bp->rptr++;
617: --n;
618: }
619: if (bp->rptr >= bp->wptr)
620: freeb(getq(q));
621: }
622:
623: /*
624: * The very strange checksum
625: */
626: pkcksum(cp, nbytes)
627: register u_char *cp;
628: register nbytes;
629: {
630: register sum, t, x;
631:
632: if (nbytes > pkc_size)
633: nbytes = pkc_size;
634: sum = pkc_sum;
635: x = pkc_x;
636: while (--nbytes >= 0) {
637: sum <<= 1;
638: if (sum & 0x10000)
639: sum++;
640: t = sum & 0xFFFF;
641: sum += *cp++;
642: sum &= 0xFFFF;
643: x += sum ^ pkc_size;
644: pkc_size--;
645: if (sum <= t)
646: sum ^= x;
647: }
648: pkc_x = x;
649: pkc_sum = sum;
650: }
651:
652: /*
653: * Send a control packet
654: */
655: pkscntl(pkp, cmd)
656: struct pack *pkp;
657: {
658: register struct block *bp;
659: register u_char *cp;
660: register struct queue *q;
661:
662: if ((bp = allocb(6)) == NULL)
663: return; /* what else to do? */
664: bp->wptr += 6;
665: cp = bp->rptr;
666: *cp++ = SYN;
667: *cp++ = 9; /* ctl pack marker */
668: *cp++ = cmd;
669: *cp++ = 0;
670: *cp++ = cmd;
671: *cp++ = 9; /* xor of hdr[1..4] */
672: q = WR(pkp->rdq);
673: (*q->next->qinfo->putp)(q->next, bp);
674: }
675:
676: /*
677: * Receive a control packet
678: */
679: pkcntl(pkp)
680: register struct pack *pkp;
681: {
682: register val;
683: register reject = 0;
684:
685: if (pkp->hdr.k != 9) {
686: return;
687: }
688: val = pkp->hdr.C & 07;
689: switch (pkp->hdr.C & 0370) {
690:
691: case PK_INITA:
692: pkp->timer = 2;
693: pkp->XW = val;
694: if (pkp->ostate==SINITA || pkp->ostate==SINITB) {
695: pkscntl(pkp, PK_INITA+RWINSIZE);
696: pkscntl(pkp, PK_INITB+RSEGSIZE);
697: pkp->ostate = SINITB;
698: return;
699: }
700: return;
701:
702: case PK_INITB:
703: pkp->timer = 2;
704: pkp->xsegment = pksizes[val+1];
705: pkp->xlogseg = val + 1;
706: if (pkp->ostate==SINITB) {
707: pkp->ostate = SINITC;
708: pkscntl(pkp, PK_INITB+RSEGSIZE);
709: pkscntl(pkp, PK_INITC+RWINSIZE);
710: return;
711: }
712: return;
713:
714: case PK_INITC:
715: if (pkp->ostate>=SINITB) {
716: if (pkp->ostate==SINITB)
717: pkscntl(pkp, PK_INITC+RWINSIZE);
718: pkp->ostate = OPEN;
719: wakeup((caddr_t)pkp);
720: return;
721: }
722: return;
723:
724: case PK_RJ:
725: reject = 1;
726: case PK_RR:
727: pkrack(pkp, val, reject);
728: return;
729:
730: case PK_CLOSE:
731: pkp->ostate = RCLOSE;
732: flushq(WR(pkp->rdq), 0);
733: pkrack(pkp, pkp->SN-1, 0);
734: qenable(pkp->rdq);
735: return;
736:
737: default:
738: return;
739: }
740: }
741:
742: pktimer()
743: {
744: register struct pack *pkp;
745:
746: for (pkp = packs; pkp < &packs[NPK]; pkp++) {
747: if (pkp->timer) {
748: pkp->timer--;
749: continue;
750: }
751: switch (pkp->ostate) {
752:
753: case 0:
754: continue;
755:
756: case OPEN:
757: case LCLOSE:
758: qenable(WR(pkp->rdq));
759: continue;
760:
761: case SINITA:
762: pkscntl(pkp, PK_INITA+RWINSIZE);
763: pkp->timer = 2;
764: continue;
765:
766: case SINITB:
767: pkscntl(pkp, PK_INITA+RWINSIZE);
768: pkscntl(pkp, PK_INITB+RSEGSIZE);
769: pkp->timer = 2;
770: continue;
771: }
772: }
773: timeout(pktimer, (caddr_t)NULL, 60);
774: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.