cec.c 8.3 KB

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