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