xref: /plan9/sys/src/cmd/cec/cec.c (revision 68de9c9388a1b0174f2979e40f3c4361793bf05a)
1eba00c11SDavid du Colombier /*
2*68de9c93SDavid du Colombier  * cec — coraid ethernet console
3*68de9c93SDavid du Colombier  * Copyright © Coraid, Inc. 2006-2008.
4*68de9c93SDavid du Colombier  * All Rights Reserved.
5eba00c11SDavid du Colombier  */
6eba00c11SDavid du Colombier #include <u.h>
7eba00c11SDavid du Colombier #include <libc.h>
8eba00c11SDavid du Colombier #include <ip.h>		/* really! */
9eba00c11SDavid du Colombier #include <ctype.h>
10eba00c11SDavid du Colombier #include "cec.h"
11eba00c11SDavid du Colombier 
12eba00c11SDavid du Colombier enum {
13eba00c11SDavid du Colombier 	Tinita		= 0,
14eba00c11SDavid du Colombier 	Tinitb,
15eba00c11SDavid du Colombier 	Tinitc,
16eba00c11SDavid du Colombier 	Tdata,
17eba00c11SDavid du Colombier 	Tack,
18eba00c11SDavid du Colombier 	Tdiscover,
19eba00c11SDavid du Colombier 	Toffer,
20eba00c11SDavid du Colombier 	Treset,
21eba00c11SDavid du Colombier 
22*68de9c93SDavid du Colombier 	Hdrsz		= 18,
23eba00c11SDavid du Colombier 	Eaddrlen	= 6,
24eba00c11SDavid du Colombier };
25eba00c11SDavid du Colombier 
26*68de9c93SDavid du Colombier typedef struct{
27eba00c11SDavid du Colombier 	uchar	ea[Eaddrlen];
28*68de9c93SDavid du Colombier 	int	major;
29*68de9c93SDavid du Colombier 	char	name[28];
30*68de9c93SDavid du Colombier } Shelf;
31eba00c11SDavid du Colombier 
32*68de9c93SDavid du Colombier int 	conn(int);
33eba00c11SDavid du Colombier void 	gettingkilled(int);
34eba00c11SDavid du Colombier int 	pickone(void);
35eba00c11SDavid du Colombier void 	probe(void);
36eba00c11SDavid du Colombier void	sethdr(Pkt *, int);
37eba00c11SDavid du Colombier int	shelfidx(void);
38eba00c11SDavid du Colombier 
39*68de9c93SDavid du Colombier Shelf	*con;
40*68de9c93SDavid du Colombier Shelf	tab[1000];
41*68de9c93SDavid du Colombier 
42*68de9c93SDavid du Colombier char	*host;
43*68de9c93SDavid du Colombier char	*srv;
44*68de9c93SDavid du Colombier char	*svc;
45*68de9c93SDavid du Colombier 
46*68de9c93SDavid du Colombier char	pflag;
47*68de9c93SDavid du Colombier 
48*68de9c93SDavid du Colombier int	ntab;
49*68de9c93SDavid du Colombier int	shelf = -1;
50*68de9c93SDavid du Colombier 
51*68de9c93SDavid du Colombier uchar	bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
52*68de9c93SDavid du Colombier uchar	contag;
53*68de9c93SDavid du Colombier uchar 	esc = '';
54*68de9c93SDavid du Colombier uchar	ea[Eaddrlen];
55*68de9c93SDavid du Colombier uchar	unsetea[Eaddrlen];
56*68de9c93SDavid du Colombier 
57eba00c11SDavid du Colombier extern 	int fd;		/* set in netopen */
58eba00c11SDavid du Colombier 
59*68de9c93SDavid du Colombier void
post(char * srv,int fd)60*68de9c93SDavid du Colombier post(char *srv, int fd)
61*68de9c93SDavid du Colombier {
62*68de9c93SDavid du Colombier 	char buf[32];
63*68de9c93SDavid du Colombier 	int f;
64*68de9c93SDavid du Colombier 
65*68de9c93SDavid du Colombier 	if((f = create(srv, OWRITE, 0666)) == -1)
66*68de9c93SDavid du Colombier 		sysfatal("create %s: %r", srv);
67*68de9c93SDavid du Colombier 	snprint(buf, sizeof buf, "%d", fd);
68*68de9c93SDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
69*68de9c93SDavid du Colombier 		sysfatal("write %s: %r", srv);
70*68de9c93SDavid du Colombier 	close(f);
71*68de9c93SDavid du Colombier }
72*68de9c93SDavid du Colombier 
73*68de9c93SDavid du Colombier void
dosrv(char * s)74*68de9c93SDavid du Colombier dosrv(char *s)
75*68de9c93SDavid du Colombier {
76*68de9c93SDavid du Colombier 	int p[2];
77*68de9c93SDavid du Colombier 
78*68de9c93SDavid du Colombier 	if(pipe(p) < 0)
79*68de9c93SDavid du Colombier 		sysfatal("pipe: %r");
80*68de9c93SDavid du Colombier 	if (srv[0] != '/')
81*68de9c93SDavid du Colombier 		svc = smprint("/srv/%s", s);
82*68de9c93SDavid du Colombier 	else
83*68de9c93SDavid du Colombier 		svc = smprint("%s", s);
84*68de9c93SDavid du Colombier 	post(svc, p[0]);
85*68de9c93SDavid du Colombier 	close(p[0]);
86*68de9c93SDavid du Colombier 	dup(p[1], 0);
87*68de9c93SDavid du Colombier 	dup(p[1], 1);
88*68de9c93SDavid du Colombier 
89*68de9c93SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
90*68de9c93SDavid du Colombier 	case -1:
91*68de9c93SDavid du Colombier 		sysfatal("fork: %r");
92*68de9c93SDavid du Colombier 	case 0:
93*68de9c93SDavid du Colombier 		break;
94*68de9c93SDavid du Colombier 	default:
95*68de9c93SDavid du Colombier 		exits("");
96*68de9c93SDavid du Colombier 	}
97*68de9c93SDavid du Colombier 	close(2);
98*68de9c93SDavid du Colombier }
99eba00c11SDavid du Colombier 
100eba00c11SDavid du Colombier void
usage(void)101eba00c11SDavid du Colombier usage(void)
102eba00c11SDavid du Colombier {
103*68de9c93SDavid du Colombier 	fprint(2, "usage: cec [-dp] [-c esc] [-e ea] [-h host] [-s shelf] "
104*68de9c93SDavid du Colombier 		"[-S srv] interface\n");
105eba00c11SDavid du Colombier 	exits0("usage");
106eba00c11SDavid du Colombier }
107eba00c11SDavid du Colombier 
108eba00c11SDavid du Colombier void
catch(void *,char * note)109eba00c11SDavid du Colombier catch(void*, char *note)
110eba00c11SDavid du Colombier {
111eba00c11SDavid du Colombier 	if(strcmp(note, "alarm") == 0)
112eba00c11SDavid du Colombier 		noted(NCONT);
113eba00c11SDavid du Colombier 	noted(NDFLT);
114eba00c11SDavid du Colombier }
115eba00c11SDavid du Colombier 
116*68de9c93SDavid du Colombier int
nilea(uchar * ea)117*68de9c93SDavid du Colombier nilea(uchar *ea)
118*68de9c93SDavid du Colombier {
119*68de9c93SDavid du Colombier 	return memcmp(ea, unsetea, Eaddrlen) == 0;
120*68de9c93SDavid du Colombier }
121*68de9c93SDavid du Colombier 
122eba00c11SDavid du Colombier void
main(int argc,char ** argv)123eba00c11SDavid du Colombier main(int argc, char **argv)
124eba00c11SDavid du Colombier {
125eba00c11SDavid du Colombier 	int r, n;
126eba00c11SDavid du Colombier 
127eba00c11SDavid du Colombier 	ARGBEGIN{
128*68de9c93SDavid du Colombier 	case 'S':
129*68de9c93SDavid du Colombier 		srv = EARGF(usage());
130*68de9c93SDavid du Colombier 		break;
131*68de9c93SDavid du Colombier 	case 'c':
132*68de9c93SDavid du Colombier 		esc = tolower(*(EARGF(usage()))) - 'a' + 1;
133*68de9c93SDavid du Colombier 		if(esc == 0 || esc >= ' ')
134*68de9c93SDavid du Colombier 			usage();
135*68de9c93SDavid du Colombier 		break;
136eba00c11SDavid du Colombier 	case 'd':
137eba00c11SDavid du Colombier 		debug++;
138eba00c11SDavid du Colombier 		break;
139*68de9c93SDavid du Colombier 	case 'e':
140*68de9c93SDavid du Colombier 		if(parseether(ea, EARGF(usage())) == -1)
141*68de9c93SDavid du Colombier 			usage();
142*68de9c93SDavid du Colombier 		pflag = 1;
143*68de9c93SDavid du Colombier 		break;
144*68de9c93SDavid du Colombier 	case 'h':
145*68de9c93SDavid du Colombier 		host = EARGF(usage());
146*68de9c93SDavid du Colombier 		break;
147*68de9c93SDavid du Colombier 	case 'p':
148*68de9c93SDavid du Colombier 		pflag = 1;
149*68de9c93SDavid du Colombier 		break;
150eba00c11SDavid du Colombier 	case 's':
151eba00c11SDavid du Colombier 		shelf = atoi(EARGF(usage()));
152eba00c11SDavid du Colombier 		break;
153eba00c11SDavid du Colombier 	default:
154eba00c11SDavid du Colombier 		usage();
155eba00c11SDavid du Colombier 	}ARGEND
156*68de9c93SDavid du Colombier 	if(argc == 0)
157*68de9c93SDavid du Colombier 		*argv = "/net/ether0";
158*68de9c93SDavid du Colombier 	else if(argc != 1)
159eba00c11SDavid du Colombier 		usage();
160eba00c11SDavid du Colombier 
161eba00c11SDavid du Colombier 	fmtinstall('E', eipfmt);
162*68de9c93SDavid du Colombier 	if(srv != nil)
163*68de9c93SDavid du Colombier 		dosrv(srv);
164eba00c11SDavid du Colombier 	r = netopen(*argv);
165eba00c11SDavid du Colombier 	if(r == -1){
166eba00c11SDavid du Colombier 		fprint(2, "cec: can't netopen %s\n", *argv);
167eba00c11SDavid du Colombier 		exits0("open");
168eba00c11SDavid du Colombier 	}
169eba00c11SDavid du Colombier 	notify(catch);
170eba00c11SDavid du Colombier 	probe();
171eba00c11SDavid du Colombier 	for(;;){
172eba00c11SDavid du Colombier 		n = 0;
173*68de9c93SDavid du Colombier 		if(shelf == -1 && host == 0 && nilea(ea))
174eba00c11SDavid du Colombier 			n = pickone();
175eba00c11SDavid du Colombier 		rawon();
176eba00c11SDavid du Colombier 		conn(n);
177eba00c11SDavid du Colombier 		rawoff();
178*68de9c93SDavid du Colombier 		if(pflag == 0){
179eba00c11SDavid du Colombier 			if(shelf != -1)
180eba00c11SDavid du Colombier 				exits0("shelf not found");
181*68de9c93SDavid du Colombier 			if(host)
182*68de9c93SDavid du Colombier 				exits0("host not found");
183*68de9c93SDavid du Colombier 			if(!nilea(ea))
184*68de9c93SDavid du Colombier 				exits0("ea not found");
185*68de9c93SDavid du Colombier 		} else if(shelf != -1 || host || !nilea(ea))
186*68de9c93SDavid du Colombier 			exits0("");
187eba00c11SDavid du Colombier 	}
188eba00c11SDavid du Colombier }
189eba00c11SDavid du Colombier 
190eba00c11SDavid du Colombier void
timewait(int ms)191*68de9c93SDavid du Colombier timewait(int ms)
192eba00c11SDavid du Colombier {
193eba00c11SDavid du Colombier 	alarm(ms);
194eba00c11SDavid du Colombier }
195eba00c11SDavid du Colombier 
196eba00c11SDavid du Colombier int
didtimeout(void)197eba00c11SDavid du Colombier didtimeout(void)
198eba00c11SDavid du Colombier {
199eba00c11SDavid du Colombier 	char buf[ERRMAX];
200eba00c11SDavid du Colombier 
201eba00c11SDavid du Colombier 	rerrstr(buf, sizeof buf);
202eba00c11SDavid du Colombier 	if(strcmp(buf, "interrupted") == 0){
203eba00c11SDavid du Colombier 		werrstr(buf, 0);
204eba00c11SDavid du Colombier 		return 1;
205eba00c11SDavid du Colombier 	}
206eba00c11SDavid du Colombier 	return 0;
207eba00c11SDavid du Colombier }
208eba00c11SDavid du Colombier 
209eba00c11SDavid du Colombier ushort
htons(ushort h)210eba00c11SDavid du Colombier htons(ushort h)
211eba00c11SDavid du Colombier {
212eba00c11SDavid du Colombier 	ushort n;
213eba00c11SDavid du Colombier 	uchar *p;
214eba00c11SDavid du Colombier 
215eba00c11SDavid du Colombier 	p = (uchar*)&n;
216eba00c11SDavid du Colombier 	p[0] = h >> 8;
217eba00c11SDavid du Colombier 	p[1] = h;
218eba00c11SDavid du Colombier 	return n;
219eba00c11SDavid du Colombier }
220eba00c11SDavid du Colombier 
221eba00c11SDavid du Colombier ushort
ntohs(int h)222eba00c11SDavid du Colombier ntohs(int h)
223eba00c11SDavid du Colombier {
224eba00c11SDavid du Colombier 	ushort n;
225eba00c11SDavid du Colombier 	uchar *p;
226eba00c11SDavid du Colombier 
227eba00c11SDavid du Colombier 	n = h;
228eba00c11SDavid du Colombier 	p = (uchar*)&n;
229eba00c11SDavid du Colombier 	return p[0] << 8 | p[1];
230eba00c11SDavid du Colombier }
231eba00c11SDavid du Colombier 
232*68de9c93SDavid du Colombier int
tcmp(void * a,void * b)233*68de9c93SDavid du Colombier tcmp(void *a, void *b)
234*68de9c93SDavid du Colombier {
235*68de9c93SDavid du Colombier 	Shelf *s, *t;
236*68de9c93SDavid du Colombier 	int d;
237*68de9c93SDavid du Colombier 
238*68de9c93SDavid du Colombier 	s = a;
239*68de9c93SDavid du Colombier 	t = b;
240*68de9c93SDavid du Colombier 	d = s->major - t->major;
241*68de9c93SDavid du Colombier 	if(d == 0)
242*68de9c93SDavid du Colombier 		d = strcmp(s->name, t->name);
243*68de9c93SDavid du Colombier 	if(d == 0)
244*68de9c93SDavid du Colombier 		d = memcmp(s->ea, t->ea, Eaddrlen);
245*68de9c93SDavid du Colombier 	return d;
246*68de9c93SDavid du Colombier }
247*68de9c93SDavid du Colombier 
248eba00c11SDavid du Colombier void
probe(void)249eba00c11SDavid du Colombier probe(void)
250eba00c11SDavid du Colombier {
251eba00c11SDavid du Colombier 	char *sh, *other;
252*68de9c93SDavid du Colombier 	int n;
253eba00c11SDavid du Colombier 	Pkt q;
254eba00c11SDavid du Colombier 	Shelf *p;
255eba00c11SDavid du Colombier 
256*68de9c93SDavid du Colombier 	do {
257eba00c11SDavid du Colombier 		ntab = 0;
258eba00c11SDavid du Colombier 		memset(q.dst, 0xff, Eaddrlen);
259eba00c11SDavid du Colombier 		memset(q.src, 0, Eaddrlen);
260eba00c11SDavid du Colombier 		q.etype = htons(Etype);
261eba00c11SDavid du Colombier 		q.type = Tdiscover;
262eba00c11SDavid du Colombier 		q.len = 0;
263eba00c11SDavid du Colombier 		q.conn = 0;
264eba00c11SDavid du Colombier 		q.seq = 0;
265eba00c11SDavid du Colombier 		netsend(&q, 60);
266eba00c11SDavid du Colombier 		timewait(Iowait);
267eba00c11SDavid du Colombier 		while((n = netget(&q, sizeof q)) >= 0){
268eba00c11SDavid du Colombier 			if((n <= 0 && didtimeout()) || ntab == nelem(tab))
269eba00c11SDavid du Colombier 				break;
270eba00c11SDavid du Colombier 			if(n < 60 || q.len == 0 || q.type != Toffer)
271eba00c11SDavid du Colombier 				continue;
272eba00c11SDavid du Colombier 			q.data[q.len] = 0;
273eba00c11SDavid du Colombier 			sh = strtok((char *)q.data, " \t");
274eba00c11SDavid du Colombier 			if(sh == nil)
275eba00c11SDavid du Colombier 				continue;
276*68de9c93SDavid du Colombier 			if(!nilea(ea) && memcmp(ea, q.src, Eaddrlen) != 0)
277*68de9c93SDavid du Colombier 				continue;
278eba00c11SDavid du Colombier 			if(shelf != -1 && atoi(sh) != shelf)
279eba00c11SDavid du Colombier 				continue;
280eba00c11SDavid du Colombier 			other = strtok(nil, "\x1");
281*68de9c93SDavid du Colombier 			if(other == 0)
282*68de9c93SDavid du Colombier 				other = "";
283*68de9c93SDavid du Colombier 			if(host && strcmp(host, other) != 0)
284*68de9c93SDavid du Colombier 				continue;
285eba00c11SDavid du Colombier 			p = tab + ntab++;
286eba00c11SDavid du Colombier 			memcpy(p->ea, q.src, Eaddrlen);
287*68de9c93SDavid du Colombier 			p->major = atoi(sh);
288*68de9c93SDavid du Colombier 			p->name[0] = 0;
289*68de9c93SDavid du Colombier 			if(p->name)
290*68de9c93SDavid du Colombier 				snprint(p->name, sizeof p->name, "%s", other);
291eba00c11SDavid du Colombier 		}
292eba00c11SDavid du Colombier 		alarm(0);
293*68de9c93SDavid du Colombier 	} while (ntab == 0 && pflag);
294eba00c11SDavid du Colombier 	if(ntab == 0){
295eba00c11SDavid du Colombier 		fprint(2, "none found.\n");
296eba00c11SDavid du Colombier 		exits0("none found");
297eba00c11SDavid du Colombier 	}
298*68de9c93SDavid du Colombier 	qsort(tab, ntab, sizeof tab[0], tcmp);
299eba00c11SDavid du Colombier }
300eba00c11SDavid du Colombier 
301eba00c11SDavid du Colombier void
showtable(void)302eba00c11SDavid du Colombier showtable(void)
303eba00c11SDavid du Colombier {
304eba00c11SDavid du Colombier 	int i;
305eba00c11SDavid du Colombier 
306eba00c11SDavid du Colombier 	for(i = 0; i < ntab; i++)
307*68de9c93SDavid du Colombier 		print("%2d   %5d %E %s\n", i, tab[i].major, tab[i].ea, tab[i].name);
308eba00c11SDavid du Colombier }
309eba00c11SDavid du Colombier 
310eba00c11SDavid du Colombier int
pickone(void)311eba00c11SDavid du Colombier pickone(void)
312eba00c11SDavid du Colombier {
313eba00c11SDavid du Colombier 	char buf[80];
314eba00c11SDavid du Colombier 	int n, i;
315eba00c11SDavid du Colombier 
316eba00c11SDavid du Colombier 	for(;;){
317eba00c11SDavid du Colombier 		showtable();
318eba00c11SDavid du Colombier 		print("[#qp]: ");
319eba00c11SDavid du Colombier 		switch(n = read(0, buf, sizeof buf)){
320eba00c11SDavid du Colombier 		case 1:
321eba00c11SDavid du Colombier 			if(buf[0] == '\n')
322eba00c11SDavid du Colombier 				continue;
323eba00c11SDavid du Colombier 			/* fall through */
324eba00c11SDavid du Colombier 		case 2:
325eba00c11SDavid du Colombier 			if(buf[0] == 'p'){
326eba00c11SDavid du Colombier 				probe();
327eba00c11SDavid du Colombier 				break;
328eba00c11SDavid du Colombier 			}
329eba00c11SDavid du Colombier 			if(buf[0] == 'q')
330eba00c11SDavid du Colombier 				/* fall through */
331eba00c11SDavid du Colombier 		case 0:
332eba00c11SDavid du Colombier 		case -1:
333eba00c11SDavid du Colombier 				exits0(0);
334*68de9c93SDavid du Colombier 			break;
335eba00c11SDavid du Colombier 		}
336eba00c11SDavid du Colombier 		if(isdigit(buf[0])){
337eba00c11SDavid du Colombier 			buf[n] = 0;
338eba00c11SDavid du Colombier 			i = atoi(buf);
339eba00c11SDavid du Colombier 			if(i >= 0 && i < ntab)
340eba00c11SDavid du Colombier 				break;
341eba00c11SDavid du Colombier 		}
342eba00c11SDavid du Colombier 	}
343eba00c11SDavid du Colombier 	return i;
344eba00c11SDavid du Colombier }
345eba00c11SDavid du Colombier 
346eba00c11SDavid du Colombier void
sethdr(Pkt * pp,int type)347eba00c11SDavid du Colombier sethdr(Pkt *pp, int type)
348eba00c11SDavid du Colombier {
349*68de9c93SDavid du Colombier 	memmove(pp->dst, con->ea, Eaddrlen);
350eba00c11SDavid du Colombier 	memset(pp->src, 0, Eaddrlen);
351eba00c11SDavid du Colombier 	pp->etype = htons(Etype);
352eba00c11SDavid du Colombier 	pp->type = type;
353eba00c11SDavid du Colombier 	pp->len = 0;
354eba00c11SDavid du Colombier 	pp->conn = contag;
355eba00c11SDavid du Colombier }
356eba00c11SDavid du Colombier 
357eba00c11SDavid du Colombier void
ethclose(void)358eba00c11SDavid du Colombier ethclose(void)
359eba00c11SDavid du Colombier {
360eba00c11SDavid du Colombier 	static Pkt msg;
361eba00c11SDavid du Colombier 
362eba00c11SDavid du Colombier 	sethdr(&msg, Treset);
363eba00c11SDavid du Colombier 	timewait(Iowait);
364eba00c11SDavid du Colombier 	netsend(&msg, 60);
365eba00c11SDavid du Colombier 	alarm(0);
366*68de9c93SDavid du Colombier 	con = 0;
367eba00c11SDavid du Colombier }
368eba00c11SDavid du Colombier 
369eba00c11SDavid du Colombier int
ethopen(void)370eba00c11SDavid du Colombier ethopen(void)
371eba00c11SDavid du Colombier {
372eba00c11SDavid du Colombier 	Pkt tpk, rpk;
373eba00c11SDavid du Colombier 	int i, n;
374eba00c11SDavid du Colombier 
375eba00c11SDavid du Colombier 	contag = (getpid() >> 8) ^ (getpid() & 0xff);
376eba00c11SDavid du Colombier 	sethdr(&tpk, Tinita);
377eba00c11SDavid du Colombier 	sethdr(&rpk, 0);
378eba00c11SDavid du Colombier 	for(i = 0; i < 3 && rpk.type != Tinitb; i++){
379eba00c11SDavid du Colombier 		netsend(&tpk, 60);
380eba00c11SDavid du Colombier 		timewait(Iowait);
381eba00c11SDavid du Colombier 		n = netget(&rpk, 1000);
382eba00c11SDavid du Colombier 		alarm(0);
383eba00c11SDavid du Colombier 		if(n < 0)
384eba00c11SDavid du Colombier 			return -1;
385eba00c11SDavid du Colombier 	}
386eba00c11SDavid du Colombier 	if(rpk.type != Tinitb)
387eba00c11SDavid du Colombier 		return -1;
388eba00c11SDavid du Colombier 	sethdr(&tpk, Tinitc);
389eba00c11SDavid du Colombier 	netsend(&tpk, 60);
390eba00c11SDavid du Colombier 	return 0;
391eba00c11SDavid du Colombier }
392eba00c11SDavid du Colombier 
393eba00c11SDavid du Colombier char
escape(void)394eba00c11SDavid du Colombier escape(void)
395eba00c11SDavid du Colombier {
396eba00c11SDavid du Colombier 	char buf[64];
397*68de9c93SDavid du Colombier 	int r;
398eba00c11SDavid du Colombier 
399eba00c11SDavid du Colombier 	for(;;){
400eba00c11SDavid du Colombier 		fprint(2, ">>> ");
401eba00c11SDavid du Colombier 		buf[0] = '.';
402eba00c11SDavid du Colombier 		rawoff();
403*68de9c93SDavid du Colombier 		r = read(0, buf, sizeof buf - 1);
404eba00c11SDavid du Colombier 		rawon();
405*68de9c93SDavid du Colombier 		if(r == -1)
406*68de9c93SDavid du Colombier 			exits0("kbd: %r");
407eba00c11SDavid du Colombier 		switch(buf[0]){
408eba00c11SDavid du Colombier 		case 'i':
409eba00c11SDavid du Colombier 		case 'q':
410eba00c11SDavid du Colombier 		case '.':
411eba00c11SDavid du Colombier 			return buf[0];
412eba00c11SDavid du Colombier 		}
413eba00c11SDavid du Colombier 		fprint(2, "	(q)uit, (i)nterrupt, (.)continue\n");
414eba00c11SDavid du Colombier 	}
415eba00c11SDavid du Colombier }
416eba00c11SDavid du Colombier 
417eba00c11SDavid du Colombier /*
418*68de9c93SDavid du Colombier  * this is a bit too aggressive.  it really needs to replace only \n\r with \n.
419eba00c11SDavid du Colombier  */
420*68de9c93SDavid du Colombier static uchar crbuf[256];
421eba00c11SDavid du Colombier 
422eba00c11SDavid du Colombier void
nocrwrite(int fd,uchar * buf,int n)423eba00c11SDavid du Colombier nocrwrite(int fd, uchar *buf, int n)
424eba00c11SDavid du Colombier {
425eba00c11SDavid du Colombier 	int i, j, c;
426eba00c11SDavid du Colombier 
427eba00c11SDavid du Colombier 	j = 0;
428*68de9c93SDavid du Colombier 	for(i = 0; i < n; i++)
429*68de9c93SDavid du Colombier 		if((c = buf[i]) != '\r')
430eba00c11SDavid du Colombier 			crbuf[j++] = c;
431eba00c11SDavid du Colombier 	write(fd, crbuf, j);
432eba00c11SDavid du Colombier }
433eba00c11SDavid du Colombier 
434eba00c11SDavid du Colombier int
doloop(void)435eba00c11SDavid du Colombier doloop(void)
436eba00c11SDavid du Colombier {
437eba00c11SDavid du Colombier 	int unacked, retries, set[2];
438eba00c11SDavid du Colombier 	uchar c, tseq, rseq;
439eba00c11SDavid du Colombier 	uchar ea[Eaddrlen];
440eba00c11SDavid du Colombier 	Pkt tpk, spk;
441*68de9c93SDavid du Colombier 	Mux *m;
442eba00c11SDavid du Colombier 
443*68de9c93SDavid du Colombier 	memmove(ea, con->ea, Eaddrlen);
444eba00c11SDavid du Colombier 	retries = 0;
445eba00c11SDavid du Colombier 	unacked = 0;
446eba00c11SDavid du Colombier 	tseq = 0;
447eba00c11SDavid du Colombier 	rseq = -1;
448eba00c11SDavid du Colombier 	set[0] = 0;
449eba00c11SDavid du Colombier 	set[1] = fd;
450eba00c11SDavid du Colombier top:
451eba00c11SDavid du Colombier 	if ((m = mux(set)) == 0)
452eba00c11SDavid du Colombier 		exits0("mux: %r");
453eba00c11SDavid du Colombier 	for (; ; )
454eba00c11SDavid du Colombier 		switch (muxread(m, &spk)) {
455eba00c11SDavid du Colombier 		case -1:
456eba00c11SDavid du Colombier 			if (unacked == 0)
457eba00c11SDavid du Colombier 				break;
458eba00c11SDavid du Colombier 			if (retries-- == 0) {
459eba00c11SDavid du Colombier 				fprint(2, "Connection timed out\n");
460eba00c11SDavid du Colombier 				muxfree(m);
461eba00c11SDavid du Colombier 				return 0;
462eba00c11SDavid du Colombier 			}
463*68de9c93SDavid du Colombier 			netsend(&tpk, Hdrsz + unacked);
464eba00c11SDavid du Colombier 			break;
465*68de9c93SDavid du Colombier 		case Fkbd:
466eba00c11SDavid du Colombier 			c = spk.data[0];
467eba00c11SDavid du Colombier 			if (c == esc) {
468eba00c11SDavid du Colombier 				muxfree(m);
469eba00c11SDavid du Colombier 				switch (escape()) {
470eba00c11SDavid du Colombier 				case 'q':
471eba00c11SDavid du Colombier 					tpk.len = 0;
472eba00c11SDavid du Colombier 					tpk.type = Treset;
473eba00c11SDavid du Colombier 					netsend(&tpk, 60);
474eba00c11SDavid du Colombier 					return 0;
475eba00c11SDavid du Colombier 				case '.':
476eba00c11SDavid du Colombier 					goto top;
477eba00c11SDavid du Colombier 				case 'i':
478eba00c11SDavid du Colombier 					if ((m = mux(set)) == 0)
479eba00c11SDavid du Colombier 						exits0("mux: %r");
480eba00c11SDavid du Colombier 					break;
481eba00c11SDavid du Colombier 				}
482eba00c11SDavid du Colombier 			}
483eba00c11SDavid du Colombier 			sethdr(&tpk, Tdata);
484eba00c11SDavid du Colombier 			memcpy(tpk.data, spk.data, spk.len);
485eba00c11SDavid du Colombier 			tpk.len = spk.len;
486eba00c11SDavid du Colombier 			tpk.seq = ++tseq;
487eba00c11SDavid du Colombier 			unacked = spk.len;
488eba00c11SDavid du Colombier 			retries = 2;
489*68de9c93SDavid du Colombier 			netsend(&tpk, Hdrsz + spk.len);
490eba00c11SDavid du Colombier 			break;
491*68de9c93SDavid du Colombier 		case Fcec:
492eba00c11SDavid du Colombier 			if (memcmp(spk.src, ea, Eaddrlen) != 0 ||
493eba00c11SDavid du Colombier 			    ntohs(spk.etype) != Etype)
494eba00c11SDavid du Colombier 				continue;
495*68de9c93SDavid du Colombier 			if (spk.type == Toffer &&
496*68de9c93SDavid du Colombier 			    memcmp(spk.dst, bcast, Eaddrlen) != 0) {
497eba00c11SDavid du Colombier 				muxfree(m);
498eba00c11SDavid du Colombier 				return 1;
499eba00c11SDavid du Colombier 			}
500eba00c11SDavid du Colombier 			if (spk.conn != contag)
501eba00c11SDavid du Colombier 				continue;
502eba00c11SDavid du Colombier 			switch (spk.type) {
503eba00c11SDavid du Colombier 			case Tdata:
504eba00c11SDavid du Colombier 				if (spk.seq == rseq)
505eba00c11SDavid du Colombier 					break;
506eba00c11SDavid du Colombier 				nocrwrite(1, spk.data, spk.len);
507eba00c11SDavid du Colombier 				memmove(spk.dst, spk.src, Eaddrlen);
508eba00c11SDavid du Colombier 				memset(spk.src, 0, Eaddrlen);
509eba00c11SDavid du Colombier 				spk.type = Tack;
510eba00c11SDavid du Colombier 				spk.len = 0;
511eba00c11SDavid du Colombier 				rseq = spk.seq;
512eba00c11SDavid du Colombier 				netsend(&spk, 60);
513eba00c11SDavid du Colombier 				break;
514eba00c11SDavid du Colombier 			case Tack:
515eba00c11SDavid du Colombier 				if (spk.seq == tseq)
516eba00c11SDavid du Colombier 					unacked = 0;
517eba00c11SDavid du Colombier 				break;
518eba00c11SDavid du Colombier 			case Treset:
519eba00c11SDavid du Colombier 				muxfree(m);
520eba00c11SDavid du Colombier 				return 1;
521eba00c11SDavid du Colombier 			}
522*68de9c93SDavid du Colombier 			break;
523*68de9c93SDavid du Colombier 		case Ffatal:
524*68de9c93SDavid du Colombier 			muxfree(m);
525*68de9c93SDavid du Colombier 			fprint(2, "kbd read error\n");
526*68de9c93SDavid du Colombier 			exits0("fatal");
527eba00c11SDavid du Colombier 		}
528eba00c11SDavid du Colombier }
529eba00c11SDavid du Colombier 
530*68de9c93SDavid du Colombier int
conn(int n)531eba00c11SDavid du Colombier conn(int n)
532eba00c11SDavid du Colombier {
533*68de9c93SDavid du Colombier 	int r;
534*68de9c93SDavid du Colombier 
535*68de9c93SDavid du Colombier 	for(;;){
536*68de9c93SDavid du Colombier 		if(con)
537eba00c11SDavid du Colombier 			ethclose();
538*68de9c93SDavid du Colombier 		con = tab + n;
539eba00c11SDavid du Colombier 		if(ethopen() < 0){
540*68de9c93SDavid du Colombier 			fprint(2, "connection failed\n");
541*68de9c93SDavid du Colombier 			return 0;
542eba00c11SDavid du Colombier 		}
543*68de9c93SDavid du Colombier 		r = doloop();
544*68de9c93SDavid du Colombier 		if(r <= 0)
545*68de9c93SDavid du Colombier 			return r;
546*68de9c93SDavid du Colombier 	}
547eba00c11SDavid du Colombier }
548eba00c11SDavid du Colombier 
549eba00c11SDavid du Colombier void
exits0(char * s)550eba00c11SDavid du Colombier exits0(char *s)
551eba00c11SDavid du Colombier {
552*68de9c93SDavid du Colombier 	if(con != nil)
553eba00c11SDavid du Colombier 		ethclose();
554eba00c11SDavid du Colombier 	rawoff();
555*68de9c93SDavid du Colombier 	if(svc != nil)
556*68de9c93SDavid du Colombier 		remove(svc);
557eba00c11SDavid du Colombier 	exits(s);
558eba00c11SDavid du Colombier }
559