123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- /*
- * Copyright © Coraid, Inc. 2006, 2007. All Rights Reserved.
- * ethernet console for Coraid storage products.
- * simple command line version.
- */
- #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,
- HDRSIZ = 18,
- Eaddrlen = 6,
- };
- typedef struct Shelf Shelf;
- struct Shelf {
- uchar ea[Eaddrlen];
- int shelfno;
- char *str;
- };
- void conn(int);
- void exits0(char *);
- void gettingkilled(int);
- int pickone(void);
- void probe(void);
- void sethdr(Pkt *, int);
- int shelfidx(void);
- extern int errno;
- extern int fd; /* set in netopen */
- Shelf tab[1000];
- int ntab;
- uchar contag;
- int shelf = -1;
- Shelf *connp;
- char esc = '';
- void
- usage(void)
- {
- fprint(2, "usage: cec [-d] [-e esc] [-s shelf] interface\n");
- exits0("usage");
- }
- void
- catch(void*, char *note)
- {
- if(strcmp(note, "alarm") == 0)
- noted(NCONT);
- noted(NDFLT);
- }
- void
- main(int argc, char **argv)
- {
- int r, n;
- ARGBEGIN{
- case 'd':
- debug++;
- break;
- case 's':
- shelf = atoi(EARGF(usage()));
- break;
- case 'e':
- esc = toupper(*(EARGF(usage()))) - 'A' + 1;
- if(esc <= 0 || esc >= ' ')
- usage();
- break;
- default:
- usage();
- }ARGEND
- if(debug)
- fprint(2, "debug is on\n");
- if(argc != 1)
- usage();
- fmtinstall('E', eipfmt);
- 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)
- n = pickone();
- rawon();
- conn(n);
- rawoff();
- if(shelf != -1)
- exits0("shelf not found");
- }
- }
- void
- timewait(int ms) /* arrange for a sig_alarm signal after `ms' milliseconds */
- {
- 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];
- }
- void
- probe(void)
- {
- int n;
- char *sh, *other;
- uchar buf[1500];
- Pkt q;
- Shelf *p;
- ntab = 0;
- memset(buf, 0xff, Eaddrlen);
- 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);
- // fprint(2, "Probing for shelves ... ");
- 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(shelf != -1 && atoi(sh) != shelf)
- continue;
- other = strtok(nil, "\x1");
- p = tab + ntab++;
- memcpy(p->ea, q.src, Eaddrlen);
- p->shelfno = atoi(sh);
- p->str = other? strdup(other): "";
- if(shelf != -1) {
- fprint(2, "shelf %d found.\n", shelf);
- break;
- }
- }
- alarm(0);
- if(ntab == 0) {
- fprint(2, "none found.\n");
- exits0("none found");
- }
- // fprint(2, "done.\n");
- }
- void
- showtable(void)
- {
- int i;
- for(i = 0; i < ntab; i++)
- print("%2d %5d %E %s\n", i,
- tab[i].shelfno, tab[i].ea, tab[i].str);
- }
- 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);
- }
- 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, connp->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);
- connp = 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];
- for(;;){
- fprint(2, ">>> ");
- buf[0] = '.';
- rawoff();
- read(0, buf, sizeof buf-1);
- rawon();
- switch(buf[0]){
- case 'i':
- case 'q':
- case '.':
- return buf[0];
- }
- fprint(2, " (q)uit, (i)nterrupt, (.)continue\n");
- }
- }
- /*
- * this is a bit too agressive. it really needs to replace only \n\r with \n.
- */
- static uchar crbuf[1514];
- 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')
- continue;
- crbuf[j++] = c;
- }
- write(fd, crbuf, j);
- }
- int
- doloop(void)
- {
- int unacked, retries, set[2];
- uchar c, tseq, rseq;
- uchar ea[Eaddrlen];
- Mux * m;
- Pkt tpk, spk;
- memmove(ea, connp->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, HDRSIZ + unacked);
- break;
- case 0:
- 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, HDRSIZ + spk.len);
- break;
- default:
- if (memcmp(spk.src, ea, Eaddrlen) != 0 ||
- ntohs(spk.etype) != Etype)
- continue;
- if (spk.type == Toffer) {
- 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);
- if (0)
- write(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;
- }
- }
- }
- void
- conn(int n)
- {
- do {
- if(connp)
- ethclose();
- connp = &tab[n];
- if(ethopen() < 0){
- fprint(2, "connection failed.\n");
- return;
- }
- } while(doloop());
- }
- void
- exits0(char *s)
- {
- if(connp != nil)
- ethclose();
- rawoff();
- exits(s);
- }
|