|
|
1.1 root 1: static char sccsid[] = "@(#)prot.c 4.1 (Berkeley) 9/12/82";
2:
3: /* Protocol driver, user level, Berkeley network */
4: /*
5: This code is a little complicated because of a number of different
6: protocols used. Here is an explanation:
7:
8: Level Description
9:
10: 0 Normal Case (6 bit with no kernel driver support)
11:
12: 1 Line Discipline -- uses NETLDISP in sgtty.h and ioctl to set the
13: line discipline. At Berkeley this means avoiding interrupting on
14: every character by using a Silo on a DH or DZ board, and (optionally)
15: bypassing the canonicalization in the tty code by putting the charactars
16: directly in a buffer.
17: condition (netd.dp_bnetldis != 0)
18:
19: 2 8-bit TTY protocol -- implies Level 1 and inserts record separators(012)
20: and escapes other occurrences of 012. Since the driver on the other
21: end must interpolate the escapes, this is an asymmetric protocol where
22: the sender puts in the escapes but the receiver at the user level knows
23: they have already been removed.
24: condition (netd.dp_bnetldis != 0 && netd.dp_use8bit != 0)
25:
26: 3 8-bit Block Device protocol -- this is for a DMC-11, it writes fixed
27: length blocks in both directions with no quoting.
28: condition (netd.dp_bnetldis != 0 && netd.dp_usehighspeed != 0)
29:
30: 4 RAND 8-bit protocol -- included for completeness, is not
31: correctly specified here.
32: Specified by an IFDEF.
33:
34: If the daemons are being simulated by pipes, then netd.dp_pipesim != 0
35: and each of the 4 levels (except RAND) are simulated.
36: In this case at level 2 (use8bit) on the receiver end it does the quoting.
37:
38: Timing statistics: We estimate 300 micros for queue/dequeue and then
39: 20 micros per interrupt for 30 cps => 2.5% of system for 9600 Baud line
40:
41: Max packet lengths=> to CSVAX with 1k buffers and 6-bit prot = 758 chars
42: to Ing70 with 512 byte buffers and no NETLDISC, only 182 chars
43:
44: */
45: # include "defs.h"
46:
47: /* global */
48: struct dumpstruc dump;
49: struct daemonparms netd;
50:
51: /* local */
52: static int bufleft;
53: static char retransmit;
54: static jmp_buf env;
55: static short masterseqno, lastseqno;
56: /* writing packet */
57: static char wpack[MAXNBUF];
58:
59: /*
60: one problem has been character loss on
61: overloaded systems due to the daemon
62: taking too long to swap in
63: and losing characters.
64: A high priority process of small size
65: with a pipe would do the job.
66: */
67: alarmint(){
68: errno = 100;
69: signal(SIGALRM,SIG_IGN); /* alarm off */
70: longjmp(env,0); /* ugh */
71: }
72: /* returns number of bytes written, error returns WRITEFAIL (-3) */
73: /* inbuf is buffer of amt chars to be written */
74: xwrite(inbuf,amt)
75: char *inbuf;
76: {
77: register char *p, *b;
78: register int i;
79: int cnt, num, savetime;
80: struct packet *rpp, *xptr;
81:
82: xptr = (struct packet *)wpack;
83: cnt = 0;
84: retransmit = 0;
85: savetime = netd.dp_atime;
86: while(amt > 0){
87: if(retransmit > netd.dp_maxbread){
88: debug("xwrite fail");
89: return(WRITEFAIL);
90: }
91: /* format the packet to send */
92: num = min(netd.dp_datasize,amt);
93: /* set the length down if escapes are being used */
94: if(netd.dp_use8bit)num = min(num,MAXNBUF/2);
95: xptr->pcode = REQUEST;
96: xptr->seqno = masterseqno;
97: xptr->len = num;
98: p = xptr->data;
99: i = num;
100: b = inbuf+cnt;
101: while(i--)*p++ = *b++;
102: /* send it */
103: sendpacket(xptr);
104: rpp = getpacket();
105: if(rpp == NULL){
106: netd.dp_atime += 3; /* wait three more secs */
107: retransmit++;
108: dump.nretrans++;
109: continue;
110: }
111: /* various errors */
112: if(rpp->chksum != 0 || rpp->pcode != ACK
113: || rpp->seqno != xptr->seqno ){
114: if(rpp->seqno == 1 && rpp->pcode == REQUEST){
115: error("collision");
116: return(WRITEFAIL);
117: }
118: if(rpp->chksum != 0)
119: error("chksum %d",rpp->seqno);
120: else if(rpp->pcode != ACK)
121: error("not ack %d %d",rpp->pcode,rpp->seqno);
122: else if(rpp->seqno != xptr ->seqno)
123: error("WRSQNO got %d request %d",rpp->seqno,
124: xptr->seqno);
125: netd.dp_atime += 3;
126: retransmit++;
127: dump.nretrans++;
128: continue;
129: }
130: masterseqno++;
131: retransmit = 0;
132: amt -= num;
133: cnt += num;
134: }
135: netd.dp_atime = savetime;
136: return(cnt);
137: }
138: /* return the number of bytes read, or error = BROKENREAD (-2) */
139: nread(bptr,num)
140: register char *bptr;
141: {
142: register char *p;
143: register struct packet *pp;
144: register char *q;
145: int bcnt = 0;
146: int n,j,cnt;
147: static char savebuf[MAXNBUF];
148:
149: /* first see if theres any left from the last packet */
150: cnt = 0;
151: if(bufleft > 0){
152: p = savebuf;
153: cnt = n = min(bufleft,num);
154: while(n--)*bptr++ = *p++;
155: num -= cnt;
156: bufleft -= cnt;
157: if(bufleft > 0){
158: q = savebuf;
159: n = bufleft;
160: while(n--)*q++ = *p++;
161: }
162: }
163: if(num <= 0)
164: return(cnt);
165: /* now read a packet */
166: retransmit = 0;
167: for(;;){
168: pp = getpacket();
169: if(pp == NULL){
170: if(++bcnt >= netd.dp_maxbread){
171: debug("read timeout");
172: return(BROKENREAD);
173: }
174: continue;
175: }
176: /* various errors */
177: if(pp->chksum != 0){
178: error("chksum %d",pp->seqno);
179: retransmit++;
180: continue;
181: }
182: if(pp->pcode & ~REQUEST){
183: error("pcode %d %d",pp->pcode,pp->seqno);
184: retransmit++;
185: continue;
186: }
187: /* this is the normal case, so we ack it */
188: else { /* else was a REQUEST packet, no chksum errs */
189: /*
190: if(pp->seqno == 1)debug("^R ");
191: */
192: pp->pcode = ACK;
193: n = pp->len;
194: pp->len = 0;
195: sendpacket(pp); /* send ACK */
196: pp->len = n;
197: break;
198: }
199: }
200: /* now process this packet, bptr points to where we left off */
201: retransmit = 0;
202: j = n = min(num,pp->len);
203: cnt += j;
204: p = pp->data;
205: while(n--)*bptr++ = *p++;
206: if(pp->len > num){
207: n = bufleft = pp->len - num;
208: bptr = savebuf;
209: while(n--)*bptr++ = *p++;
210: }
211: return(cnt);
212: }
213: printpacket(pp,dest)
214: char *dest;
215: struct packet *pp; {
216: char *s;
217: int i;
218: char c;
219: dest[0] = 0;
220: if(pp == NULL)return;
221: if(pp->pcode == REQUEST)c='r';
222: else if(pp->pcode == ACK)c = 'a';
223: else if(pp->pcode == PURGE)c = 'p';
224: else c = 'u';
225: sprintf(dest,"p:%d len:%d c:%c d:", pp->seqno, pp->len, c);
226: s = dest + strlen(dest);
227: for(i=0; i<pp->len && pp->data[i]; i++)*s++ = pp->data[i];
228: *s = 0;
229: }
230: /*
231: * A purge can always be sent -
232: * the receiver totally ignores it.
233: * It is used to push the packet terminator
234: * down the wire in case of a crash
235: * leaving the receiver half reading.
236: */
237: sendpurge()
238: {
239: struct packet *xptr;
240: xptr = (struct packet *)wpack;
241: xptr->pcode = PURGE;
242: xptr->seqno = 0;
243: xptr->len = 0;
244: debug("send purge");
245: sendpacket(xptr);
246: }
247: /* init sequence numbers */
248: initseqno(){
249: masterseqno = 1;
250: lastseqno = 0;
251: bufleft = 0; /* if any chars are left in buffer, flush them*/
252: netd.dp_atime = netd.dp_oatime + ((rand()>>8)%15);
253: }
254: /*
255: * Just sends packet pp
256: * Calculates the chksum
257: */
258: sendpacket(pp)
259: struct packet *pp; {
260: register char *q, *p;
261: register int j;
262: char *finalp;
263: static char raw[MAXNBUF];
264: int len, n, i;
265:
266: /* writes the data to be sent in array raw */
267: /* finalp will point to either pp or raw */
268: dump.nbytesent += pp->len;
269: dump.npacksent++;
270: pp->chksum = 0;
271: n = 0;
272: p = (char *)pp;
273: len = ACKLENGTH + pp->len;
274: for(j = 0; j < len; j++)n ^= *p++;
275: pp->chksum = n;
276: # ifdef SWAB
277: switchem(pp);
278: # endif
279: # ifndef RAND
280: if(netd.dp_usehispeed)finalp = (char *)pp;
281: else if(netd.dp_use8bit){
282: if(len >= MAXNBUF){
283: fprintf(stderr,"Packet size too big- error\n");
284: exit(1);
285: }
286: /* add escapes */
287: p = (char *)pp;
288: q = raw;
289: i = len;
290: len = 0;
291: for(j = 0; j < i; j++){
292: if(*p == '\n' || *p == '\\'){
293: *q++ = '\\';
294: *q++ = *p++;
295: len++;
296: len++;
297: }
298: else {
299: *q++ = *p++;
300: len++;
301: }
302: }
303: *q = '\n';
304: len++;
305: finalp = raw;
306: }
307: else {
308: /* now change 8-bit data to 6-bit data */
309: if(((len+2)*4)/3 >= MAXNBUF){
310: fprintf(stderr,"Packet size too big- error\n");
311: exit(1);
312: }
313: p = raw;
314: q = (char *)pp;
315: len = n = (len+2)/3;
316: while(n--){
317: *p++ = (*q & 077) + INCR;
318: j = (*q++ >> 6) &03;
319: *p++ = (((*q << 2) | j) & 077) + INCR;
320: j = (*q++ >> 4) & 017;
321: *p++ = (((*q << 4) | j) & 077) + INCR;
322: *p++ = ((*q++ >> 2) & 077) + INCR;
323: }
324: *p++ = '\n';
325: *p = 0;
326: /* because of bugs in processing around erase and kill in v6 */
327: for(p=raw; *p; p++)
328: if(*p == '\\')*p = '}';
329: len = len * 4 + 1;
330: finalp = raw;
331: }
332: /*
333: debug("send %d <<%s>>",len,raw);
334: */
335: if(netd.dp_usehispeed){
336: if(len > SENDLEN)error("send length too long");
337: len = SENDLEN;
338: }
339: if(netd.dp_pipesim) i = write(netd.dp_pwritefd,finalp,len);
340: else i = write(netd.dp_linefd,finalp,len);
341: dump.braw += i;
342: dump.brawtot += i;
343: # ifdef SWAB
344: switchem(pp);
345: # endif
346: # else
347: /* for RAND */
348: i = write(netd.dp_linefd, (char *)pp,len);
349: # endif
350: /*
351: debug("count %d",i);
352: */
353: }
354:
355: static int tooshort;
356: /*
357: * returns NULL if couldn't get a packet with correct seqno
358: * chksum not checked here
359: * because other programs may want to interrogate checksum
360: */
361: struct packet *getpacket() {
362: register struct packet *gptr;
363: register char *p;
364: register int i;
365: int n, bcnt, len;
366: struct packet *decpacket();
367:
368: bcnt = 0;
369: errno = 0;
370: setjmp(env);
371: alarm(0);
372: signal(SIGALRM,alarmint);
373: for(;;){
374: if(bcnt++ > netd.dp_maxbread)errno = 100; /* give up */
375: if(errno == 100){
376: if(debugflg)putchar('^');
377: return(NULL);
378: }
379: /* decode the buffer, including 6-8 bit conv, etc. */
380: gptr = decpacket();
381: if(gptr == NULL){
382: error("getpacket fails");
383: return(NULL);
384: }
385: if(tooshort || gptr->len < 0 || gptr->len > MAXNBUF){
386: error("too short p:%d l:%d",gptr->seqno,gptr->len);
387: continue;
388: }
389: if(gptr->seqno == 1 && gptr->pcode != ACK){
390: debug("got reset");
391: addtolog(remote,"^R ");
392: }
393: if(gptr->pcode == PURGE){
394: debug("got purge");
395: continue; /* never seen */
396: }
397: if(gptr->seqno == lastseqno){
398: if(retransmit)break;
399: /* send ACK - it was lost first time thru */
400: len = gptr->len;
401: n = gptr->pcode;
402: gptr->len = 0;
403: gptr->pcode = ACK;
404: sendpacket(gptr);
405: gptr->len = len;
406: gptr->pcode = n;
407: error("sendlostack %d",lastseqno);
408: break;
409: }
410: /* this is the correct case */
411: if(gptr->seqno == lastseqno + 1)break;
412: error("Wrong seq no g: %d last: %d",gptr->seqno,
413: lastseqno);
414: }
415: lastseqno = gptr->seqno;
416: n = 0;
417: len = gptr->len + ACKLENGTH;
418: p = (char *)gptr;
419: for(i=0; i < len; i++)n ^= *p++;
420: gptr->chksum = n;
421: if(n != 0)dump.ncksum++;
422: dump.nbytercv += gptr->len;
423: dump.npackrcv++;
424: return(gptr);
425: }
426: /* read in and decode packet */
427: /* as a side effect sets "tooshort" */
428: static struct packet *decpacket()
429: {
430: # ifndef RAND
431: register char *p, *q;
432: register int i,j;
433: int n, len, ch;
434: struct packet *pp;
435: static char cooked[MAXNBUF], raw[MAXNBUF];
436:
437: /* read in chars to raw, if processed then return in cooked, otherwise
438: return in raw */
439: alarm(netd.dp_atime);
440: tooshort = 0;
441: if(netd.dp_pipesim){
442: if(netd.dp_usehispeed)
443: len = read(fileno(netd.dp_rdfile),raw,SENDLEN);
444: else {
445: q = raw;
446: len = 0;
447: for(;;){
448: ch = getc(netd.dp_rdfile);
449: len++;
450: if(ch == '\n'){
451: *q++ = '\n';
452: break;
453: }
454: /* eat up the backslashes */
455: if(ch == '\\' && netd.dp_use8bit)
456: ch = getc(netd.dp_rdfile);
457: *q++ = ch;
458: }
459: if(netd.dp_use8bit)len--;
460: }
461: }
462: else if(netd.dp_usehispeed)
463: len = read(fileno(netd.dp_rdfile),raw,SENDLEN);
464: else len = read(netd.dp_linefd,raw,MAXNBUF);
465: alarm(0);
466: if(len == 0)fprintf(stderr,"eof pip %d\n",fileno(netd.dp_rdfile));
467: if(len <= 0)return(NULL);
468: raw[len] = 0;
469: dump.braw += len;
470: dump.brawtot += len;
471: /*
472: debug("receive %d <<%s>>",len,raw);
473: */
474: /* if 8 bit the all we need to do is return */
475: if(netd.dp_usehispeed)return((struct packet *)raw);
476: if(netd.dp_use8bit){
477: pp = (struct packet *)raw;
478: if(len != ACKLENGTH + pp->len)tooshort = 1;
479: return(pp);
480: }
481: /* remove this loop later */
482: for(p=raw; *p; p++)
483: if(*p == '}')*p = '\\';
484: p = raw;
485: q = cooked;
486: n = (len+3) /4;
487: while(n--){
488: if(*p == '\n')break;
489: if(*p < INCR || *p & 0200)error("bad char %o\n",*p);
490: i = *p++ - INCR;
491: j = *p++ - INCR;
492: *q++ = ((j & 03) << 6) | (i & 077);
493: i = *p++ -INCR;
494: *q++ = ((i & 017) << 4) | ((j >> 2) & 017);
495: j = *p++ - INCR;
496: *q++ = ((j & 077) << 2) | ((i >> 4) & 03);
497: }
498: *q = 0;
499: pp = (struct packet *)cooked;
500: # ifdef SWAB
501: switchem(pp);
502: # endif
503: if(len != ((ACKLENGTH + pp->len + 2)/3)*4 + 1) tooshort = 1;
504: # else
505: /* for RAND */
506: /* not sure of the length computation */
507: if(len != ACKLENGTH + gptr->len) tooshort = 1;
508: # endif
509: return((struct packet *)cooked);
510: }
511:
512: # ifdef SWAB
513: switchem(pp)
514: register struct packet *pp; {
515: register short *p;
516: p = &(pp->seqno);
517: swab(p, p, 2);
518: p = &(pp->len);
519: swab(p, p, 2);
520: }
521: # endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.