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