123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- /*
- * cec — coraid ethernet console
- * Copyright © Coraid, Inc. 2006-2008.
- * All Rights Reserved.
- */
- #include <u.h>
- #include <libc.h>
- #include <ip.h> /* really! */
- #include <ctype.h>
- #include "cec.h"
- enum {
- Tinita = 0,
- Tinitb,
- Tinitc,
- Tdata,
- Tack,
- Tdiscover,
- Toffer,
- Treset,
- Hdrsz = 18,
- Eaddrlen = 6,
- };
- typedef struct{
- uchar ea[Eaddrlen];
- int major;
- char name[28];
- } Shelf;
- int conn(int);
- void gettingkilled(int);
- int pickone(void);
- void probe(void);
- void sethdr(Pkt *, int);
- int shelfidx(void);
- Shelf *con;
- Shelf tab[1000];
- char *host;
- char *srv;
- char *svc;
- char pflag;
- int ntab;
- int shelf = -1;
- uchar bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- uchar contag;
- uchar esc = '';
- uchar ea[Eaddrlen];
- uchar unsetea[Eaddrlen];
- extern int fd; /* set in netopen */
- void
- post(char *srv, int fd)
- {
- char buf[32];
- int f;
- if((f = create(srv, OWRITE, 0666)) == -1)
- sysfatal("create %s: %r", srv);
- snprint(buf, sizeof buf, "%d", fd);
- if(write(f, buf, strlen(buf)) != strlen(buf))
- sysfatal("write %s: %r", srv);
- close(f);
- }
- void
- dosrv(char *s)
- {
- int p[2];
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
- if (srv[0] != '/')
- svc = smprint("/srv/%s", s);
- else
- svc = smprint("%s", s);
- post(svc, p[0]);
- close(p[0]);
- dup(p[1], 0);
- dup(p[1], 1);
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
- case -1:
- sysfatal("fork: %r");
- case 0:
- break;
- default:
- exits("");
- }
- close(2);
- }
- void
- usage(void)
- {
- fprint(2, "usage: cec [-dp] [-c esc] [-e ea] [-h host] [-s shelf] "
- "[-S srv] interface\n");
- exits0("usage");
- }
- void
- catch(void*, char *note)
- {
- if(strcmp(note, "alarm") == 0)
- noted(NCONT);
- noted(NDFLT);
- }
- int
- nilea(uchar *ea)
- {
- return memcmp(ea, unsetea, Eaddrlen) == 0;
- }
- void
- main(int argc, char **argv)
- {
- int r, n;
- ARGBEGIN{
- case 'S':
- srv = EARGF(usage());
- break;
- case 'c':
- esc = tolower(*(EARGF(usage()))) - 'a' + 1;
- if(esc == 0 || esc >= ' ')
- usage();
- break;
- case 'd':
- debug++;
- break;
- case 'e':
- if(parseether(ea, EARGF(usage())) == -1)
- usage();
- pflag = 1;
- break;
- case 'h':
- host = EARGF(usage());
- break;
- case 'p':
- pflag = 1;
- break;
- case 's':
- shelf = atoi(EARGF(usage()));
- break;
- default:
- usage();
- }ARGEND
- if(argc == 0)
- *argv = "/net/ether0";
- else if(argc != 1)
- usage();
- fmtinstall('E', eipfmt);
- if(srv != nil)
- dosrv(srv);
- r = netopen(*argv);
- if(r == -1){
- fprint(2, "cec: can't netopen %s\n", *argv);
- exits0("open");
- }
- notify(catch);
- probe();
- for(;;){
- n = 0;
- if(shelf == -1 && host == 0 && nilea(ea))
- n = pickone();
- rawon();
- conn(n);
- rawoff();
- if(pflag == 0){
- if(shelf != -1)
- exits0("shelf not found");
- if(host)
- exits0("host not found");
- if(!nilea(ea))
- exits0("ea not found");
- } else if(shelf != -1 || host || !nilea(ea))
- exits0("");
- }
- }
- void
- timewait(int ms)
- {
- alarm(ms);
- }
- int
- didtimeout(void)
- {
- char buf[ERRMAX];
- rerrstr(buf, sizeof buf);
- if(strcmp(buf, "interrupted") == 0){
- werrstr(buf, 0);
- return 1;
- }
- return 0;
- }
- ushort
- htons(ushort h)
- {
- ushort n;
- uchar *p;
- p = (uchar*)&n;
- p[0] = h >> 8;
- p[1] = h;
- return n;
- }
- ushort
- ntohs(int h)
- {
- ushort n;
- uchar *p;
- n = h;
- p = (uchar*)&n;
- return p[0] << 8 | p[1];
- }
- int
- tcmp(void *a, void *b)
- {
- Shelf *s, *t;
- int d;
- s = a;
- t = b;
- d = s->major - t->major;
- if(d == 0)
- d = strcmp(s->name, t->name);
- if(d == 0)
- d = memcmp(s->ea, t->ea, Eaddrlen);
- return d;
- }
- void
- probe(void)
- {
- char *sh, *other;
- int n;
- Pkt q;
- Shelf *p;
- do {
- ntab = 0;
- memset(q.dst, 0xff, Eaddrlen);
- memset(q.src, 0, Eaddrlen);
- q.etype = htons(Etype);
- q.type = Tdiscover;
- q.len = 0;
- q.conn = 0;
- q.seq = 0;
- netsend(&q, 60);
- timewait(Iowait);
- while((n = netget(&q, sizeof q)) >= 0){
- if((n <= 0 && didtimeout()) || ntab == nelem(tab))
- break;
- if(n < 60 || q.len == 0 || q.type != Toffer)
- continue;
- q.data[q.len] = 0;
- sh = strtok((char *)q.data, " \t");
- if(sh == nil)
- continue;
- if(!nilea(ea) && memcmp(ea, q.src, Eaddrlen) != 0)
- continue;
- if(shelf != -1 && atoi(sh) != shelf)
- continue;
- other = strtok(nil, "\x1");
- if(other == 0)
- other = "";
- if(host && strcmp(host, other) != 0)
- continue;
- p = tab + ntab++;
- memcpy(p->ea, q.src, Eaddrlen);
- p->major = atoi(sh);
- p->name[0] = 0;
- if(p->name)
- snprint(p->name, sizeof p->name, "%s", other);
- }
- alarm(0);
- } while (ntab == 0 && pflag);
- if(ntab == 0){
- fprint(2, "none found.\n");
- exits0("none found");
- }
- qsort(tab, ntab, sizeof tab[0], tcmp);
- }
- void
- showtable(void)
- {
- int i;
- for(i = 0; i < ntab; i++)
- print("%2d %5d %E %s\n", i, tab[i].major, tab[i].ea, tab[i].name);
- }
- int
- pickone(void)
- {
- char buf[80];
- int n, i;
- for(;;){
- showtable();
- print("[#qp]: ");
- switch(n = read(0, buf, sizeof buf)){
- case 1:
- if(buf[0] == '\n')
- continue;
- /* fall through */
- case 2:
- if(buf[0] == 'p'){
- probe();
- break;
- }
- if(buf[0] == 'q')
- /* fall through */
- case 0:
- case -1:
- exits0(0);
- break;
- }
- if(isdigit(buf[0])){
- buf[n] = 0;
- i = atoi(buf);
- if(i >= 0 && i < ntab)
- break;
- }
- }
- return i;
- }
- void
- sethdr(Pkt *pp, int type)
- {
- memmove(pp->dst, con->ea, Eaddrlen);
- memset(pp->src, 0, Eaddrlen);
- pp->etype = htons(Etype);
- pp->type = type;
- pp->len = 0;
- pp->conn = contag;
- }
- void
- ethclose(void)
- {
- static Pkt msg;
- sethdr(&msg, Treset);
- timewait(Iowait);
- netsend(&msg, 60);
- alarm(0);
- con = 0;
- }
- int
- ethopen(void)
- {
- Pkt tpk, rpk;
- int i, n;
- contag = (getpid() >> 8) ^ (getpid() & 0xff);
- sethdr(&tpk, Tinita);
- sethdr(&rpk, 0);
- for(i = 0; i < 3 && rpk.type != Tinitb; i++){
- netsend(&tpk, 60);
- timewait(Iowait);
- n = netget(&rpk, 1000);
- alarm(0);
- if(n < 0)
- return -1;
- }
- if(rpk.type != Tinitb)
- return -1;
- sethdr(&tpk, Tinitc);
- netsend(&tpk, 60);
- return 0;
- }
- char
- escape(void)
- {
- char buf[64];
- int r;
- for(;;){
- fprint(2, ">>> ");
- buf[0] = '.';
- rawoff();
- r = read(0, buf, sizeof buf - 1);
- rawon();
- if(r == -1)
- exits0("kbd: %r");
- switch(buf[0]){
- case 'i':
- case 'q':
- case '.':
- return buf[0];
- }
- fprint(2, " (q)uit, (i)nterrupt, (.)continue\n");
- }
- }
- /*
- * this is a bit too aggressive. it really needs to replace only \n\r with \n.
- */
- static uchar crbuf[256];
- void
- nocrwrite(int fd, uchar *buf, int n)
- {
- int i, j, c;
- j = 0;
- for(i = 0; i < n; i++)
- if((c = buf[i]) != '\r')
- crbuf[j++] = c;
- write(fd, crbuf, j);
- }
- int
- doloop(void)
- {
- int unacked, retries, set[2];
- uchar c, tseq, rseq;
- uchar ea[Eaddrlen];
- Pkt tpk, spk;
- Mux *m;
- memmove(ea, con->ea, Eaddrlen);
- retries = 0;
- unacked = 0;
- tseq = 0;
- rseq = -1;
- set[0] = 0;
- set[1] = fd;
- top:
- if ((m = mux(set)) == 0)
- exits0("mux: %r");
- for (; ; )
- switch (muxread(m, &spk)) {
- case -1:
- if (unacked == 0)
- break;
- if (retries-- == 0) {
- fprint(2, "Connection timed out\n");
- muxfree(m);
- return 0;
- }
- netsend(&tpk, Hdrsz + unacked);
- break;
- case Fkbd:
- c = spk.data[0];
- if (c == esc) {
- muxfree(m);
- switch (escape()) {
- case 'q':
- tpk.len = 0;
- tpk.type = Treset;
- netsend(&tpk, 60);
- return 0;
- case '.':
- goto top;
- case 'i':
- if ((m = mux(set)) == 0)
- exits0("mux: %r");
- break;
- }
- }
- sethdr(&tpk, Tdata);
- memcpy(tpk.data, spk.data, spk.len);
- tpk.len = spk.len;
- tpk.seq = ++tseq;
- unacked = spk.len;
- retries = 2;
- netsend(&tpk, Hdrsz + spk.len);
- break;
- case Fcec:
- if (memcmp(spk.src, ea, Eaddrlen) != 0 ||
- ntohs(spk.etype) != Etype)
- continue;
- if (spk.type == Toffer &&
- memcmp(spk.dst, bcast, Eaddrlen) != 0) {
- muxfree(m);
- return 1;
- }
- if (spk.conn != contag)
- continue;
- switch (spk.type) {
- case Tdata:
- if (spk.seq == rseq)
- break;
- nocrwrite(1, spk.data, spk.len);
- memmove(spk.dst, spk.src, Eaddrlen);
- memset(spk.src, 0, Eaddrlen);
- spk.type = Tack;
- spk.len = 0;
- rseq = spk.seq;
- netsend(&spk, 60);
- break;
- case Tack:
- if (spk.seq == tseq)
- unacked = 0;
- break;
- case Treset:
- muxfree(m);
- return 1;
- }
- break;
- case Ffatal:
- muxfree(m);
- fprint(2, "kbd read error\n");
- exits0("fatal");
- }
- }
- int
- conn(int n)
- {
- int r;
- for(;;){
- if(con)
- ethclose();
- con = tab + n;
- if(ethopen() < 0){
- fprint(2, "connection failed\n");
- return 0;
- }
- r = doloop();
- if(r <= 0)
- return r;
- }
- }
- void
- exits0(char *s)
- {
- if(con != nil)
- ethclose();
- rawoff();
- if(svc != nil)
- remove(svc);
- exits(s);
- }
|