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

Defined functions

alarmint defined in line 67; used 1 times
decpacket defined in line 428; used 2 times
getpacket defined in line 361; used 4 times
initseqno defined in line 248; never used
printpacket defined in line 213; used 2 times
sendpacket defined in line 258; used 5 times
sendpurge defined in line 237; used 1 times
switchem defined in line 513; used 3 times

Defined variables

bufleft defined in line 52; used 7 times
dump defined in line 48; used 11 times
env defined in line 54; used 2 times
lastseqno defined in line 55; used 6 times
masterseqno defined in line 55; used 3 times
netd defined in line 49; used 32 times
retransmit defined in line 53; used 10 times
sccsid defined in line 1; never used
tooshort defined in line 355; used 5 times
wpack defined in line 57; used 2 times
Last modified: 1982-09-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1301
Valid CSS Valid XHTML 1.0 Strict