cec.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * Copyright © Coraid, Inc. 2006, 2007. All Rights Reserved.
  3. * ethernet console for Coraid storage products.
  4. * simple command line version.
  5. */
  6. #include <u.h>
  7. #include <libc.h>
  8. #include <ip.h> /* really! */
  9. #include <ctype.h>
  10. #include "cec.h"
  11. enum {
  12. Tinita = 0,
  13. Tinitb,
  14. Tinitc,
  15. Tdata,
  16. Tack,
  17. Tdiscover,
  18. Toffer,
  19. Treset,
  20. HDRSIZ = 18,
  21. Eaddrlen = 6,
  22. };
  23. typedef struct Shelf Shelf;
  24. struct Shelf {
  25. uchar ea[Eaddrlen];
  26. int shelfno;
  27. char *str;
  28. };
  29. void conn(int);
  30. void exits0(char *);
  31. void gettingkilled(int);
  32. int pickone(void);
  33. void probe(void);
  34. void sethdr(Pkt *, int);
  35. int shelfidx(void);
  36. extern int errno;
  37. extern int fd; /* set in netopen */
  38. Shelf tab[1000];
  39. int ntab;
  40. uchar contag;
  41. int shelf = -1;
  42. Shelf *connp;
  43. char esc = '';
  44. void
  45. usage(void)
  46. {
  47. fprint(2, "usage: cec [-d] [-e esc] [-s shelf] interface\n");
  48. exits0("usage");
  49. }
  50. void
  51. catch(void*, char *note)
  52. {
  53. if(strcmp(note, "alarm") == 0)
  54. noted(NCONT);
  55. noted(NDFLT);
  56. }
  57. void
  58. main(int argc, char **argv)
  59. {
  60. int r, n;
  61. ARGBEGIN{
  62. case 'd':
  63. debug++;
  64. break;
  65. case 's':
  66. shelf = atoi(EARGF(usage()));
  67. break;
  68. case 'e':
  69. esc = toupper(*(EARGF(usage()))) - 'A' + 1;
  70. if(esc <= 0 || esc >= ' ')
  71. usage();
  72. break;
  73. default:
  74. usage();
  75. }ARGEND
  76. if(debug)
  77. fprint(2, "debug is on\n");
  78. if(argc != 1)
  79. usage();
  80. fmtinstall('E', eipfmt);
  81. r = netopen(*argv);
  82. if(r == -1){
  83. fprint(2, "cec: can't netopen %s\n", *argv);
  84. exits0("open");
  85. }
  86. notify(catch);
  87. probe();
  88. for(;;){
  89. n = 0;
  90. if(shelf == -1)
  91. n = pickone();
  92. rawon();
  93. conn(n);
  94. rawoff();
  95. if(shelf != -1)
  96. exits0("shelf not found");
  97. }
  98. }
  99. void
  100. timewait(int ms) /* arrange for a sig_alarm signal after `ms' milliseconds */
  101. {
  102. alarm(ms);
  103. }
  104. int
  105. didtimeout(void)
  106. {
  107. char buf[ERRMAX];
  108. rerrstr(buf, sizeof buf);
  109. if(strcmp(buf, "interrupted") == 0){
  110. werrstr(buf, 0);
  111. return 1;
  112. }
  113. return 0;
  114. }
  115. ushort
  116. htons(ushort h)
  117. {
  118. ushort n;
  119. uchar *p;
  120. p = (uchar*)&n;
  121. p[0] = h >> 8;
  122. p[1] = h;
  123. return n;
  124. }
  125. ushort
  126. ntohs(int h)
  127. {
  128. ushort n;
  129. uchar *p;
  130. n = h;
  131. p = (uchar*)&n;
  132. return p[0] << 8 | p[1];
  133. }
  134. void
  135. probe(void)
  136. {
  137. int n;
  138. char *sh, *other;
  139. uchar buf[1500];
  140. Pkt q;
  141. Shelf *p;
  142. ntab = 0;
  143. memset(buf, 0xff, Eaddrlen);
  144. memset(q.dst, 0xff, Eaddrlen);
  145. memset(q.src, 0, Eaddrlen);
  146. q.etype = htons(Etype);
  147. q.type = Tdiscover;
  148. q.len = 0;
  149. q.conn = 0;
  150. q.seq = 0;
  151. netsend(&q, 60);
  152. // fprint(2, "Probing for shelves ... ");
  153. timewait(Iowait);
  154. while((n = netget(&q, sizeof q)) >= 0) {
  155. if((n <= 0 && didtimeout()) || ntab == nelem(tab))
  156. break;
  157. if(n < 60 || q.len == 0 || q.type != Toffer)
  158. continue;
  159. q.data[q.len] = 0;
  160. sh = strtok((char *)q.data, " \t");
  161. if(sh == nil)
  162. continue;
  163. if(shelf != -1 && atoi(sh) != shelf)
  164. continue;
  165. other = strtok(nil, "\x1");
  166. p = tab + ntab++;
  167. memcpy(p->ea, q.src, Eaddrlen);
  168. p->shelfno = atoi(sh);
  169. p->str = other? strdup(other): "";
  170. if(shelf != -1) {
  171. fprint(2, "shelf %d found.\n", shelf);
  172. break;
  173. }
  174. }
  175. alarm(0);
  176. if(ntab == 0) {
  177. fprint(2, "none found.\n");
  178. exits0("none found");
  179. }
  180. // fprint(2, "done.\n");
  181. }
  182. void
  183. showtable(void)
  184. {
  185. int i;
  186. for(i = 0; i < ntab; i++)
  187. print("%2d %5d %E %s\n", i,
  188. tab[i].shelfno, tab[i].ea, tab[i].str);
  189. }
  190. int
  191. pickone(void)
  192. {
  193. char buf[80];
  194. int n, i;
  195. for(;;){
  196. showtable();
  197. print("[#qp]: ");
  198. switch(n = read(0, buf, sizeof buf)){
  199. case 1:
  200. if(buf[0] == '\n')
  201. continue;
  202. /* fall through */
  203. case 2:
  204. if(buf[0] == 'p'){
  205. probe();
  206. break;
  207. }
  208. if(buf[0] == 'q')
  209. /* fall through */
  210. case 0:
  211. case -1:
  212. exits0(0);
  213. }
  214. if(isdigit(buf[0])){
  215. buf[n] = 0;
  216. i = atoi(buf);
  217. if(i >= 0 && i < ntab)
  218. break;
  219. }
  220. }
  221. return i;
  222. }
  223. void
  224. sethdr(Pkt *pp, int type)
  225. {
  226. memmove(pp->dst, connp->ea, Eaddrlen);
  227. memset(pp->src, 0, Eaddrlen);
  228. pp->etype = htons(Etype);
  229. pp->type = type;
  230. pp->len = 0;
  231. pp->conn = contag;
  232. }
  233. void
  234. ethclose(void)
  235. {
  236. static Pkt msg;
  237. sethdr(&msg, Treset);
  238. timewait(Iowait);
  239. netsend(&msg, 60);
  240. alarm(0);
  241. connp = 0;
  242. }
  243. int
  244. ethopen(void)
  245. {
  246. Pkt tpk, rpk;
  247. int i, n;
  248. contag = (getpid() >> 8) ^ (getpid() & 0xff);
  249. sethdr(&tpk, Tinita);
  250. sethdr(&rpk, 0);
  251. for(i = 0; i < 3 && rpk.type != Tinitb; i++){
  252. netsend(&tpk, 60);
  253. timewait(Iowait);
  254. n = netget(&rpk, 1000);
  255. alarm(0);
  256. if(n < 0)
  257. return -1;
  258. }
  259. if(rpk.type != Tinitb)
  260. return -1;
  261. sethdr(&tpk, Tinitc);
  262. netsend(&tpk, 60);
  263. return 0;
  264. }
  265. char
  266. escape(void)
  267. {
  268. char buf[64];
  269. for(;;){
  270. fprint(2, ">>> ");
  271. buf[0] = '.';
  272. rawoff();
  273. read(0, buf, sizeof buf-1);
  274. rawon();
  275. switch(buf[0]){
  276. case 'i':
  277. case 'q':
  278. case '.':
  279. return buf[0];
  280. }
  281. fprint(2, " (q)uit, (i)nterrupt, (.)continue\n");
  282. }
  283. }
  284. /*
  285. * this is a bit too agressive. it really needs to replace only \n\r with \n.
  286. */
  287. static uchar crbuf[1514];
  288. void
  289. nocrwrite(int fd, uchar *buf, int n)
  290. {
  291. int i, j, c;
  292. j = 0;
  293. for(i = 0; i < n; i++){
  294. if((c = buf[i]) == '\r')
  295. continue;
  296. crbuf[j++] = c;
  297. }
  298. write(fd, crbuf, j);
  299. }
  300. int
  301. doloop(void)
  302. {
  303. int unacked, retries, set[2];
  304. uchar c, tseq, rseq;
  305. uchar ea[Eaddrlen];
  306. Mux * m;
  307. Pkt tpk, spk;
  308. memmove(ea, connp->ea, Eaddrlen);
  309. retries = 0;
  310. unacked = 0;
  311. tseq = 0;
  312. rseq = -1;
  313. set[0] = 0;
  314. set[1] = fd;
  315. top:
  316. if ((m = mux(set)) == 0)
  317. exits0("mux: %r");
  318. for (; ; )
  319. switch (muxread(m, &spk)) {
  320. case -1:
  321. if (unacked == 0)
  322. break;
  323. if (retries-- == 0) {
  324. fprint(2, "Connection timed out\n");
  325. muxfree(m);
  326. return 0;
  327. }
  328. netsend(&tpk, HDRSIZ + unacked);
  329. break;
  330. case 0:
  331. c = spk.data[0];
  332. if (c == esc) {
  333. muxfree(m);
  334. switch (escape()) {
  335. case 'q':
  336. tpk.len = 0;
  337. tpk.type = Treset;
  338. netsend(&tpk, 60);
  339. return 0;
  340. case '.':
  341. goto top;
  342. case 'i':
  343. if ((m = mux(set)) == 0)
  344. exits0("mux: %r");
  345. break;
  346. }
  347. }
  348. sethdr(&tpk, Tdata);
  349. memcpy(tpk.data, spk.data, spk.len);
  350. tpk.len = spk.len;
  351. tpk.seq = ++tseq;
  352. unacked = spk.len;
  353. retries = 2;
  354. netsend(&tpk, HDRSIZ + spk.len);
  355. break;
  356. default:
  357. if (memcmp(spk.src, ea, Eaddrlen) != 0 ||
  358. ntohs(spk.etype) != Etype)
  359. continue;
  360. if (spk.type == Toffer) {
  361. muxfree(m);
  362. return 1;
  363. }
  364. if (spk.conn != contag)
  365. continue;
  366. switch (spk.type) {
  367. case Tdata:
  368. if (spk.seq == rseq)
  369. break;
  370. nocrwrite(1, spk.data, spk.len);
  371. if (0)
  372. write(1, spk.data, spk.len);
  373. memmove(spk.dst, spk.src, Eaddrlen);
  374. memset(spk.src, 0, Eaddrlen);
  375. spk.type = Tack;
  376. spk.len = 0;
  377. rseq = spk.seq;
  378. netsend(&spk, 60);
  379. break;
  380. case Tack:
  381. if (spk.seq == tseq)
  382. unacked = 0;
  383. break;
  384. case Treset:
  385. muxfree(m);
  386. return 1;
  387. }
  388. }
  389. }
  390. void
  391. conn(int n)
  392. {
  393. do {
  394. if(connp)
  395. ethclose();
  396. connp = &tab[n];
  397. if(ethopen() < 0){
  398. fprint(2, "connection failed.\n");
  399. return;
  400. }
  401. } while(doloop());
  402. }
  403. void
  404. exits0(char *s)
  405. {
  406. if(connp != nil)
  407. ethclose();
  408. rawoff();
  409. exits(s);
  410. }