ampwait.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /*====================================================================*
  2. *
  3. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or
  8. * without modification, are permitted (subject to the limitations
  9. * in the disclaimer below) provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * * Redistributions in binary form must reproduce the above
  16. * copyright notice, this list of conditions and the following
  17. * disclaimer in the documentation and/or other materials
  18. * provided with the distribution.
  19. *
  20. * * Neither the name of Qualcomm Atheros nor the names of
  21. * its contributors may be used to endorse or promote products
  22. * derived from this software without specific prior written
  23. * permission.
  24. *
  25. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
  26. * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
  27. * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  28. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  29. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  31. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  33. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  37. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. *--------------------------------------------------------------------*/
  41. /*====================================================================*"
  42. *
  43. * ampwait.c -
  44. *
  45. *
  46. * Contributor(s):
  47. * Charles Maier
  48. * Nathaniel Houghton
  49. * Werner Henze
  50. *
  51. *--------------------------------------------------------------------*/
  52. /*====================================================================*"
  53. * system header files;
  54. *--------------------------------------------------------------------*/
  55. #include <unistd.h>
  56. #include <stdlib.h>
  57. #include <stdint.h>
  58. #include <limits.h>
  59. #include <sys/time.h>
  60. /*====================================================================*
  61. * custom header files;
  62. *--------------------------------------------------------------------*/
  63. #include "../tools/getoptv.h"
  64. #include "../tools/putoptv.h"
  65. #include "../tools/memory.h"
  66. #include "../tools/number.h"
  67. #include "../tools/symbol.h"
  68. #include "../tools/types.h"
  69. #include "../tools/flags.h"
  70. #include "../tools/files.h"
  71. #include "../tools/timer.h"
  72. #include "../tools/error.h"
  73. #include "../plc/plc.h"
  74. /*====================================================================*
  75. * custom source files;
  76. *--------------------------------------------------------------------*/
  77. #ifndef MAKEFILE
  78. #include "../tools/getoptv.c"
  79. #include "../tools/putoptv.c"
  80. #include "../tools/version.c"
  81. #include "../tools/uintspec.c"
  82. #include "../tools/hexdump.c"
  83. #include "../tools/hexencode.c"
  84. #include "../tools/hexdecode.c"
  85. #include "../tools/todigit.c"
  86. #include "../tools/checkfilename.c"
  87. #include "../tools/synonym.c"
  88. #include "../tools/error.c"
  89. #endif
  90. #ifndef MAKEFILE
  91. #include "../plc/Confirm.c"
  92. #include "../plc/Display.c"
  93. #include "../plc/Failure.c"
  94. #include "../plc/ReadMME.c"
  95. #include "../plc/Request.c"
  96. #include "../plc/SendMME.c"
  97. #include "../plc/Devices.c"
  98. #endif
  99. #ifndef MAKEFILE
  100. #include "../ether/openchannel.c"
  101. #include "../ether/closechannel.c"
  102. #include "../ether/readpacket.c"
  103. #include "../ether/sendpacket.c"
  104. #include "../ether/channel.c"
  105. #endif
  106. #ifndef MAKEFILE
  107. #include "../mme/MMECode.c"
  108. #include "../mme/EthernetHeader.c"
  109. #include "../mme/QualcommHeader.c"
  110. #include "../mme/QualcommHeader1.c"
  111. #include "../mme/UnwantedMessage.c"
  112. #endif
  113. /*====================================================================*
  114. *
  115. * signed ResetAndWait (struct plc * plc);
  116. *
  117. * plc.h
  118. *
  119. * send VS_RS_DEV.REQ messages every channel->timeout milliseconds
  120. * until the device responds to indicate that it is ready to reset;
  121. * return 0 if the device eventually responds within plc->timer
  122. * seconds or -1 if not;
  123. *
  124. * Contributor(s):
  125. * Charles Maier
  126. * Nathaniel Houghton
  127. *
  128. *--------------------------------------------------------------------*/
  129. signed ResetAndWait (struct plc * plc)
  130. {
  131. struct channel * channel = (struct channel *)(plc->channel);
  132. struct message * message = (struct message *)(plc->message);
  133. struct timeval ts;
  134. struct timeval tc;
  135. unsigned timer = 0;
  136. #ifndef __GNUC__
  137. #pragma pack (push,1)
  138. #endif
  139. struct __packed vs_rs_dev_request
  140. {
  141. struct ethernet_hdr ethernet;
  142. struct qualcomm_hdr qualcomm;
  143. }
  144. * request = (struct vs_rs_dev_request *) (message);
  145. struct __packed vs_rs_dev_confirm
  146. {
  147. struct ethernet_hdr ethernet;
  148. struct qualcomm_hdr qualcomm;
  149. uint8_t MSTATUS;
  150. }
  151. * confirm = (struct vs_rs_dev_confirm *) (message);
  152. #ifndef __GNUC__
  153. #pragma pack (pop)
  154. #endif
  155. Request (plc, "Reset when Ready");
  156. if (gettimeofday (&ts, NULL) == -1)
  157. {
  158. error (1, errno, CANT_START_TIMER);
  159. }
  160. for (timer = 0; timer < plc->timer; timer = SECONDS (ts, tc))
  161. {
  162. memset (message, 0, sizeof (* message));
  163. EthernetHeader (&request->ethernet, channel->peer, channel->host, channel->type);
  164. QualcommHeader (&request->qualcomm, 0, (VS_RS_DEV | MMTYPE_REQ));
  165. plc->packetsize = (ETHER_MIN_LEN - ETHER_CRC_LEN);
  166. if (SendMME (plc) <= 0)
  167. {
  168. error (PLC_EXIT (plc), errno, CHANNEL_CANTSEND);
  169. return (-1);
  170. }
  171. if (ReadMME (plc, 0, (VS_RS_DEV | MMTYPE_CNF)) < 0)
  172. {
  173. error (PLC_EXIT (plc), errno, CHANNEL_CANTREAD);
  174. return (-1);
  175. }
  176. if (gettimeofday (&tc, NULL) == -1)
  177. {
  178. error (1, errno, CANT_RESET_TIMER);
  179. }
  180. if (plc->packetsize)
  181. {
  182. if (!confirm->MSTATUS)
  183. {
  184. Confirm (plc, "Resetting ...");
  185. return (0);
  186. }
  187. }
  188. }
  189. return (-1);
  190. }
  191. /*====================================================================*
  192. *
  193. * signed WaitForReset (struct plc * plc, char string [], size_t length);
  194. *
  195. * plc.h
  196. *
  197. * send VS_SW_VER.REQ messages every channel->timeout milliseconds
  198. * until the device stops responding to indicate that it is inactive;
  199. * return 0 if the device eventually stops responding within
  200. * plc->timer seconds or -1 if not;
  201. *
  202. * this function cannot distinguish between a software reset and
  203. * hardware reset;
  204. *
  205. * Contributor(s):
  206. * Charles Maier
  207. * Nathaniel Houghton
  208. * Werner Henze
  209. *
  210. *--------------------------------------------------------------------*/
  211. signed WaitForReset (struct plc * plc)
  212. {
  213. struct channel * channel = (struct channel *)(plc->channel);
  214. struct message * message = (struct message *)(plc->message);
  215. struct timeval ts;
  216. struct timeval tc;
  217. unsigned timer = 0;
  218. #ifndef __GNUC__
  219. #pragma pack (push,1)
  220. #endif
  221. struct __packed vs_sw_ver_request
  222. {
  223. struct ethernet_hdr ethernet;
  224. struct qualcomm_hdr qualcomm;
  225. uint8_t MSTATUS;
  226. uint8_t MDEVICEID;
  227. uint8_t MVERLENGTH;
  228. char MVERSION [PLC_VERSION_STRING];
  229. }
  230. * request = (struct vs_sw_ver_request *) (message);
  231. #ifndef __GNUC__
  232. #pragma pack (pop)
  233. #endif
  234. Request (plc, "Allow %d seconds for Reset", plc->timer);
  235. if (gettimeofday (&ts, NULL) == -1)
  236. {
  237. error (1, errno, CANT_START_TIMER);
  238. }
  239. for (timer = 0; timer < plc->timer; timer = SECONDS (ts, tc))
  240. {
  241. memset (message, 0, sizeof (* message));
  242. EthernetHeader (&request->ethernet, channel->peer, channel->host, channel->type);
  243. QualcommHeader (&request->qualcomm, 0, (VS_SW_VER | MMTYPE_REQ));
  244. plc->packetsize = (ETHER_MIN_LEN - ETHER_CRC_LEN);
  245. if (SendMME (plc) <= 0)
  246. {
  247. error (PLC_EXIT (plc), errno, CHANNEL_CANTSEND);
  248. return (-1);
  249. }
  250. if (ReadMME (plc, 0, (VS_SW_VER | MMTYPE_CNF)) < 0)
  251. {
  252. error (PLC_EXIT (plc), errno, CHANNEL_CANTREAD);
  253. return (-1);
  254. }
  255. if (gettimeofday (&tc, NULL) == -1)
  256. {
  257. error (1, errno, CANT_RESET_TIMER);
  258. }
  259. if (!plc->packetsize)
  260. {
  261. if (_allset (plc->flags, (PLC_WAITFORRESET | PLC_ANALYSE)))
  262. {
  263. Confirm (plc, "Waited %d seconds for Reset", timer);
  264. }
  265. return (0);
  266. }
  267. }
  268. if (_allset (plc->flags, (PLC_WAITFORRESET | PLC_ANALYSE)))
  269. {
  270. Confirm (plc, "Waited %d seconds for Reset", timer);
  271. }
  272. return (-1);
  273. }
  274. /*====================================================================*
  275. *
  276. * signed WaitForStart (struct plc * plc, char string [], size_t length);
  277. *
  278. * plc.h
  279. *
  280. * send VS_SW_VER.REQ messages every channel->timeout milliseconds
  281. * until the device responds to indicate that it is active; return
  282. * 0 if the device eventually responds within plc->timer seconds
  283. * or -1 if not;
  284. *
  285. * Contributor(s):
  286. * Charles Maier
  287. * Nathaniel Houghton
  288. *
  289. *--------------------------------------------------------------------*/
  290. signed WaitForStart (struct plc * plc, char string [], size_t length)
  291. {
  292. struct channel * channel = (struct channel *)(plc->channel);
  293. struct message * message = (struct message *)(plc->message);
  294. struct timeval ts;
  295. struct timeval tc;
  296. unsigned timer = 0;
  297. #ifndef __GNUC__
  298. #pragma pack (push,1)
  299. #endif
  300. struct __packed vs_sw_ver_request
  301. {
  302. struct ethernet_hdr ethernet;
  303. struct qualcomm_hdr qualcomm;
  304. uint8_t MSTATUS;
  305. uint8_t MDEVICEID;
  306. uint8_t MVERLENGTH;
  307. char MVERSION [PLC_VERSION_STRING];
  308. }
  309. * request = (struct vs_sw_ver_request *) (message);
  310. struct __packed vs_sw_ver_confirm
  311. {
  312. struct ethernet_hdr ethernet;
  313. struct qualcomm_hdr qualcomm;
  314. uint8_t MSTATUS;
  315. uint8_t MDEVICEID;
  316. uint8_t MVERLENGTH;
  317. char MVERSION [PLC_VERSION_STRING];
  318. }
  319. * confirm = (struct vs_sw_ver_confirm *) (message);
  320. #ifndef __GNUC__
  321. #pragma pack (pop)
  322. #endif
  323. Request (plc, "Allow %d seconds for Start", plc->timer);
  324. if (gettimeofday (&ts, NULL) == -1)
  325. {
  326. error (1, errno, CANT_START_TIMER);
  327. }
  328. for (timer = 0; timer < plc->timer; timer = SECONDS (ts, tc))
  329. {
  330. memset (message, 0, sizeof (* message));
  331. EthernetHeader (&request->ethernet, channel->peer, channel->host, channel->type);
  332. QualcommHeader (&request->qualcomm, 0, (VS_SW_VER | MMTYPE_REQ));
  333. plc->packetsize = (ETHER_MIN_LEN - ETHER_CRC_LEN);
  334. if (SendMME (plc) <= 0)
  335. {
  336. error (PLC_EXIT (plc), errno, CHANNEL_CANTSEND);
  337. return (-1);
  338. }
  339. if (ReadMME (plc, 0, (VS_SW_VER | MMTYPE_CNF)) < 0)
  340. {
  341. error (PLC_EXIT (plc), errno, CHANNEL_CANTREAD);
  342. return (-1);
  343. }
  344. if (gettimeofday (&tc, NULL) == -1)
  345. {
  346. error (1, errno, CANT_RESET_TIMER);
  347. }
  348. if (plc->packetsize)
  349. {
  350. if (confirm->MSTATUS)
  351. {
  352. Failure (plc, PLC_WONTDOIT);
  353. return (-1);
  354. }
  355. if (_allset (plc->flags, (PLC_WAITFORSTART | PLC_ANALYSE)))
  356. {
  357. Confirm (plc, "Waited %d seconds for Start", timer);
  358. }
  359. strncpy (string, confirm->MVERSION, length);
  360. return (0);
  361. }
  362. }
  363. if (_allset (plc->flags, (PLC_WAITFORSTART | PLC_ANALYSE)))
  364. {
  365. Confirm (plc, "Waited %d seconds for Start", timer);
  366. }
  367. return (-1);
  368. }
  369. /*====================================================================*
  370. *
  371. * signed WaitForAssoc (struct plc * plc);
  372. *
  373. * plc.h
  374. *
  375. * send VS_NW_INFO.REQ messages every channel->timeout milliseconds
  376. * until the device reports that a network has formed; return 0 if a
  377. * network forms within plc->timer seconds or -1 if not;
  378. *
  379. * Contributor(s):
  380. * Charles Maier
  381. * Nathaniel Houghton
  382. *
  383. *--------------------------------------------------------------------*/
  384. signed WaitForAssoc (struct plc * plc)
  385. {
  386. extern const uint8_t broadcast [ETHER_ADDR_LEN];
  387. struct channel * channel = (struct channel *)(plc->channel);
  388. struct message * message = (struct message *)(plc->message);
  389. struct timeval ts;
  390. struct timeval tc;
  391. unsigned timer = 0;
  392. #ifndef __GNUC__
  393. #pragma pack (push,1)
  394. #endif
  395. struct __packed vs_nw_info_request
  396. {
  397. struct ethernet_hdr ethernet;
  398. struct qualcomm_fmi qualcomm;
  399. }
  400. * request = (struct vs_nw_info_request *)(message);
  401. struct __packed vs_nw_info_confirm
  402. {
  403. struct ethernet_hdr ethernet;
  404. struct qualcomm_fmi qualcomm;
  405. uint8_t SUB_VERSION;
  406. uint8_t Reserved;
  407. uint16_t DATA_LEN;
  408. uint8_t DATA [1];
  409. }
  410. * confirm = (struct vs_nw_info_confirm *)(message);
  411. struct __packed station
  412. {
  413. uint8_t MAC [ETHER_ADDR_LEN];
  414. uint8_t TEI;
  415. uint8_t Reserved [3];
  416. uint8_t BDA [ETHER_ADDR_LEN];
  417. uint16_t AVGTX;
  418. uint8_t COUPLING;
  419. uint8_t Reserved3;
  420. uint16_t AVGRX;
  421. uint16_t Reserved4;
  422. }
  423. * station;
  424. struct __packed network
  425. {
  426. uint8_t NID [7];
  427. uint8_t Reserved1 [2];
  428. uint8_t SNID;
  429. uint8_t TEI;
  430. uint8_t Reserved2 [4];
  431. uint8_t ROLE;
  432. uint8_t CCO_MAC [ETHER_ADDR_LEN];
  433. uint8_t CCO_TEI;
  434. uint8_t Reserved3 [3];
  435. uint8_t NUMSTAS;
  436. uint8_t Reserved4 [5];
  437. struct station stations [1];
  438. }
  439. * network;
  440. struct __packed networks
  441. {
  442. uint8_t Reserved;
  443. uint8_t NUMAVLNS;
  444. struct network networks [1];
  445. }
  446. * networks = (struct networks *) (confirm->DATA);
  447. #ifndef __GNUC__
  448. #pragma pack (pop)
  449. #endif
  450. Request (plc, "Allow %d seconds for Assoc", plc->timer);
  451. if (gettimeofday (&ts, NULL) == -1)
  452. {
  453. error (1, errno, CANT_START_TIMER);
  454. }
  455. for (timer = 0; timer < plc->timer; timer = SECONDS (ts, tc))
  456. {
  457. memset (message, 0, sizeof (* message));
  458. EthernetHeader (&request->ethernet, channel->peer, channel->host, channel->type);
  459. QualcommHeader1 (&request->qualcomm, 1, (VS_NW_INFO | MMTYPE_REQ));
  460. plc->packetsize = (ETHER_MIN_LEN - ETHER_CRC_LEN);
  461. if (SendMME (plc) <= 0)
  462. {
  463. error (PLC_EXIT (plc), errno, CHANNEL_CANTSEND);
  464. return (-1);
  465. }
  466. if (ReadMME (plc, 1, (VS_NW_INFO | MMTYPE_CNF)) < 0)
  467. {
  468. error (PLC_EXIT (plc), errno, CHANNEL_CANTREAD);
  469. return (-1);
  470. }
  471. if (gettimeofday (&tc, NULL) == -1)
  472. {
  473. error (1, errno, CANT_RESET_TIMER);
  474. }
  475. if (plc->packetsize)
  476. {
  477. network = (struct network *)(&networks->networks);
  478. while (networks->NUMAVLNS--)
  479. {
  480. station = (struct station *)(&network->stations);
  481. while (network->NUMSTAS--)
  482. {
  483. if (memcmp (station->MAC, broadcast, sizeof (broadcast)))
  484. {
  485. if (_allset (plc->flags, (PLC_WAITFORASSOC | PLC_ANALYSE)))
  486. {
  487. Confirm (plc, "Waited %d seconds for Assoc", timer);
  488. }
  489. return (0);
  490. }
  491. station++;
  492. }
  493. network = (struct network *)(station);
  494. }
  495. }
  496. }
  497. if (_allset (plc->flags, (PLC_WAITFORASSOC | PLC_ANALYSE)))
  498. {
  499. Confirm (plc, "Waited %d seconds for Assoc", timer);
  500. }
  501. return (-1);
  502. }
  503. /*====================================================================*
  504. *
  505. * void function (struct plc * plc, char const * firmware);
  506. *
  507. * perform operations in a logical order;
  508. *
  509. *
  510. *--------------------------------------------------------------------*/
  511. static void function (struct plc * plc, char const * firmware)
  512. {
  513. char string [PLC_VERSION_STRING];
  514. if (_anyset (plc->flags, PLC_RESET_DEVICE))
  515. {
  516. if (ResetAndWait (plc))
  517. {
  518. Failure (plc, "Device did not Reset.");
  519. }
  520. }
  521. if (_anyset (plc->flags, PLC_WAITFORRESET))
  522. {
  523. if (WaitForReset (plc))
  524. {
  525. Failure (plc, "Device did not Reset.");
  526. }
  527. }
  528. if (_anyset (plc->flags, PLC_WAITFORSTART))
  529. {
  530. if (WaitForStart (plc, string, sizeof (string)))
  531. {
  532. Failure (plc, "Device did not Start.");
  533. }
  534. if ((firmware) && (*firmware) && strcmp (firmware, string))
  535. {
  536. Failure (plc, "Started wrong firmware");
  537. }
  538. }
  539. if (_anyset (plc->flags, PLC_WAITFORASSOC))
  540. {
  541. if (WaitForAssoc (plc))
  542. {
  543. Failure (plc, "Device did not Assoc.");
  544. }
  545. }
  546. if (plc->sleep)
  547. {
  548. Request (plc, "Pause %d seconds", plc->sleep);
  549. sleep (plc->sleep);
  550. }
  551. return;
  552. }
  553. /*====================================================================*
  554. *
  555. * int main (int argc, char const * argv[]);
  556. *
  557. * parse command line, populate plc structure and perform selected
  558. * operations; show help summary if asked; see getoptv and putoptv
  559. * to understand command line parsing and help summary display; see
  560. * plc.h for the definition of struct plc;
  561. *
  562. * the command line accepts multiple MAC addresses and the program
  563. * performs the specified operations on each address, in turn; the
  564. * address order is significant but the option order is not; the
  565. * default address is a local broadcast that causes all devices on
  566. * the local H1 interface to respond but not those at the remote
  567. * end of the powerline;
  568. *
  569. * the default address is 00:B0:52:00:00:01; omitting the address
  570. * will automatically address the local device; some options will
  571. * cancel themselves if this makes no sense;
  572. *
  573. * the default interface is eth1 because most people use eth0 as
  574. * their principle network connection; you can specify another
  575. * interface with -i or define environment string PLC to make
  576. * that the default interface and save typing;
  577. *
  578. *
  579. *--------------------------------------------------------------------*/
  580. int main (int argc, char const * argv [])
  581. {
  582. extern struct channel channel;
  583. static char const * optv [] =
  584. {
  585. "aef:i:p:qrRstvw:xy",
  586. "device [device] [...] [> stdout]",
  587. "Qualcomm Atheros Powerline Procrastinator",
  588. "a\twait for device assoc",
  589. "e\tredirect stderr to stdout",
  590. "f s\tconfirm firmware is revision s",
  591. #if defined (WINPCAP) || defined (LIBPCAP)
  592. "i n\thost interface is (n) [" LITERAL (CHANNEL_ETHNUMBER) "]",
  593. #else
  594. "i s\thost interface is (s) [" LITERAL (CHANNEL_ETHDEVICE) "]",
  595. #endif
  596. "p n\tpause (n) seconds",
  597. "q\tquiet mode",
  598. "r\twait for device reset",
  599. "R\treset device and wait",
  600. "s\twait for device start",
  601. "t n\tchannel timeout is (n) milliseconds [" LITERAL (CHANNEL_TIMEOUT) "]",
  602. "v\tverbose mode",
  603. "w n\twait up to (n) seconds for action [" LITERAL (PLC_TIMER) "]",
  604. "x\texit on error",
  605. "y\treport failure times",
  606. (char const *) (0)
  607. };
  608. #include "../plc/plc.c"
  609. char const * firmware = "";
  610. signed c;
  611. if (getenv (PLCDEVICE))
  612. {
  613. #if defined (WINPCAP) || defined (LIBPCAP)
  614. channel.ifindex = atoi (getenv (PLCDEVICE));
  615. #else
  616. channel.ifname = strdup (getenv (PLCDEVICE));
  617. #endif
  618. }
  619. optind = 1;
  620. while ((c = getoptv (argc, argv, optv)) != -1)
  621. {
  622. switch (c)
  623. {
  624. case 'a':
  625. _setbits (plc.flags, PLC_WAITFORASSOC);
  626. break;
  627. case 'e':
  628. dup2 (STDOUT_FILENO, STDERR_FILENO);
  629. break;
  630. case 'f':
  631. firmware = optarg;
  632. break;
  633. case 'i':
  634. #if defined (WINPCAP) || defined (LIBPCAP)
  635. channel.ifindex = atoi (optarg);
  636. #else
  637. channel.ifname = optarg;
  638. #endif
  639. break;
  640. case 'p':
  641. plc.sleep = (unsigned)(uintspec (optarg, 0, 3600));
  642. break;
  643. case 'q':
  644. _setbits (channel.flags, CHANNEL_SILENCE);
  645. _setbits (plc.flags, PLC_SILENCE);
  646. break;
  647. case 'r':
  648. _setbits (plc.flags, PLC_WAITFORRESET);
  649. break;
  650. case 'R':
  651. _setbits (plc.flags, PLC_RESET_DEVICE);
  652. break;
  653. case 's':
  654. _setbits (plc.flags, PLC_WAITFORSTART);
  655. break;
  656. case 't':
  657. channel.timeout = (signed)(uintspec (optarg, 0, UINT_MAX));
  658. break;
  659. case 'v':
  660. _setbits (channel.flags, CHANNEL_VERBOSE);
  661. _setbits (plc.flags, PLC_VERBOSE);
  662. break;
  663. case 'w':
  664. plc.timer = (unsigned)(uintspec (optarg, 0, 86400));
  665. break;
  666. case 'x':
  667. _setbits (plc.flags, PLC_BAILOUT);
  668. break;
  669. case 'y':
  670. _setbits (plc.flags, PLC_ANALYSE);
  671. break;
  672. default:
  673. break;
  674. }
  675. }
  676. argc -= optind;
  677. argv += optind;
  678. openchannel (&channel);
  679. if (!(plc.message = malloc (sizeof (* plc.message))))
  680. {
  681. error (1, errno, PLC_NOMEMORY);
  682. }
  683. if (!argc)
  684. {
  685. function (&plc, firmware);
  686. }
  687. while ((argc) && (* argv))
  688. {
  689. if (!hexencode (channel.peer, sizeof (channel.peer), synonym (* argv, devices, SIZEOF (devices))))
  690. {
  691. error (1, errno, PLC_BAD_MAC, * argv);
  692. }
  693. function (&plc, firmware);
  694. argv++;
  695. argc--;
  696. }
  697. free (plc.message);
  698. closechannel (&channel);
  699. exit (0);
  700. }