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