|
|
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.