fixes for range locking
[unix-history] / usr / src / old / berknet / prot.c
CommitLineData
f22be67b
KM
1static char sccsid[] = "@(#)prot.c 4.1 (Berkeley) %G%";
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
8Level Description
9
100 Normal Case (6 bit with no kernel driver support)
11
121 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
192 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
263 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
304 RAND 8-bit protocol -- included for completeness, is not
31 correctly specified here.
32 Specified by an IFDEF.
33
34If the daemons are being simulated by pipes, then netd.dp_pipesim != 0
35and each of the 4 levels (except RAND) are simulated.
36In this case at level 2 (use8bit) on the receiver end it does the quoting.
37
38Timing 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
41Max 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 */
48struct dumpstruc dump;
49struct daemonparms netd;
50
51/* local */
52static int bufleft;
53static char retransmit;
54static jmp_buf env;
55static short masterseqno, lastseqno;
56/* writing packet */
57static 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*/
67alarmint(){
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 */
74xwrite(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) */
139nread(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 }
213printpacket(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 */
237sendpurge()
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 */
248initseqno(){
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 */
258sendpacket(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
355static 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 */
361struct 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" */
428static 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
513switchem(pp)
514register 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