ampinit2.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*====================================================================*
  2. *
  3. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  4. *
  5. * All rights reserved.
  6. *
  7. *====================================================================*/
  8. /*====================================================================*
  9. * system header files;
  10. *--------------------------------------------------------------------*/
  11. #include <unistd.h>
  12. #include <stdlib.h>
  13. #include <stdint.h>
  14. #include <limits.h>
  15. /*====================================================================*
  16. * custom header files;
  17. *--------------------------------------------------------------------*/
  18. #include "../tools/getoptv.h"
  19. #include "../tools/putoptv.h"
  20. #include "../tools/memory.h"
  21. #include "../tools/number.h"
  22. #include "../tools/symbol.h"
  23. #include "../tools/types.h"
  24. #include "../tools/flags.h"
  25. #include "../tools/files.h"
  26. #include "../tools/error.h"
  27. #include "../key/HPAVKey.h"
  28. #include "../key/keys.h"
  29. #include "../ram/sdram.h"
  30. #include "../pib/pib.h"
  31. #include "../nvm/nvm.h"
  32. #include "../plc/plc.h"
  33. #include "../nda/nda.h"
  34. /*====================================================================*
  35. * custom source files;
  36. *--------------------------------------------------------------------*/
  37. #ifndef MAKEFILE
  38. #include "../plc/Attributes1.c"
  39. #include "../plc/chipset.c"
  40. #include "../plc/Confirm.c"
  41. #include "../plc/Devices.c"
  42. #include "../plc/Display.c"
  43. #include "../plc/FactoryDefaults.c"
  44. #include "../plc/Failure.c"
  45. #include "../plc/HostActionResponse.c"
  46. #include "../plc/Identity1.c"
  47. #include "../plc/NVRAMInfo.c"
  48. #include "../plc/PushButton.c"
  49. #include "../plc/ReadFirmware1.c"
  50. #include "../plc/ReadParameters1.c"
  51. #include "../plc/Request.c"
  52. #include "../plc/ReadMME.c"
  53. #include "../plc/ReadMFG.c"
  54. #include "../plc/RemoteHosts.c"
  55. #include "../plc/SendMME.c"
  56. #include "../plc/SetNMK.c"
  57. #include "../plc/SDRAMInfo.c"
  58. #include "../plc/StationRole.c"
  59. #include "../plc/WaitForReset.c"
  60. #include "../plc/WaitForRestart.c"
  61. #include "../plc/WaitForStart.c"
  62. #include "../plc/WriteCFG.c"
  63. #include "../plc/WatchdogReport.c"
  64. #include "../plc/ResetDevice.c"
  65. #include "../plc/NetInfo2.c"
  66. #include "../plc/VersionInfo1.c"
  67. #include "../plc/ModuleSpec.c"
  68. #include "../plc/ModuleSession.c"
  69. #include "../plc/ModuleRead.c"
  70. #include "../plc/ModuleWrite.c"
  71. #include "../plc/ModuleCommit.c"
  72. #include "../plc/FlashDevice2.c"
  73. #include "../plc/FlashSoftloader.c"
  74. #include "../plc/FlashFirmware.c"
  75. #include "../plc/FlashParameters.c"
  76. #endif
  77. #ifndef MAKEFILE
  78. #include "../nda/AccessLevelPTS.c"
  79. #include "../nda/EraseFlashMemory2.c"
  80. #include "../nda/ReadFlashMemory2.c"
  81. #include "../nda/ReadFlashFirmware.c"
  82. #include "../nda/ReadFlashParameters.c"
  83. #include "../nda/ModuleErase.c"
  84. #endif
  85. #ifndef MAKEFILE
  86. #include "../tools/getoptv.c"
  87. #include "../tools/putoptv.c"
  88. #include "../tools/version.c"
  89. #include "../tools/basespec.c"
  90. #include "../tools/uintspec.c"
  91. #include "../tools/hexdump.c"
  92. #include "../tools/hexencode.c"
  93. #include "../tools/hexdecode.c"
  94. #include "../tools/hexstring.c"
  95. #include "../tools/hexout.c"
  96. #include "../tools/todigit.c"
  97. #include "../tools/checkfilename.c"
  98. #include "../tools/checksum32.c"
  99. #include "../tools/fdchecksum32.c"
  100. #include "../tools/error.c"
  101. #include "../tools/strfbits.c"
  102. #include "../tools/synonym.c"
  103. #include "../tools/typename.c"
  104. #endif
  105. #ifndef MAKEFILE
  106. #include "../ether/openchannel.c"
  107. #include "../ether/closechannel.c"
  108. #include "../ether/readpacket.c"
  109. #include "../ether/sendpacket.c"
  110. #include "../ether/channel.c"
  111. #endif
  112. #ifndef MAKEFILE
  113. #include "../ram/nvram.c"
  114. #include "../ram/sdramfile.c"
  115. #include "../ram/sdrampeek.c"
  116. #endif
  117. #ifndef MAKEFILE
  118. #include "../nvm/lightning_nvm_file.c"
  119. #endif
  120. #ifndef MAKEFILE
  121. #include "../pib/lightning_pib_file.c"
  122. #include "../pib/lightning_pib_peek.c"
  123. #endif
  124. #ifndef MAKEFILE
  125. #include "../mme/EthernetHeader.c"
  126. #include "../mme/QualcommHeader.c"
  127. #include "../mme/QualcommHeader1.c"
  128. #include "../mme/UnwantedMessage.c"
  129. #include "../mme/MMECode.c"
  130. #endif
  131. #ifndef MAKEFILE
  132. #include "../key/keys.c"
  133. #endif
  134. /*====================================================================*
  135. * program constants;
  136. *--------------------------------------------------------------------*/
  137. #define DEFAULT_LOOP 1
  138. #define DEFAULT_WAIT 0
  139. /*====================================================================*
  140. * program variables;
  141. *--------------------------------------------------------------------*/
  142. static const struct _term_ modules [] =
  143. {
  144. {
  145. "nvm",
  146. "1"
  147. },
  148. {
  149. "pib",
  150. "2"
  151. },
  152. {
  153. "both",
  154. "3"
  155. }
  156. };
  157. static const struct _term_ buttons [] =
  158. {
  159. {
  160. "join",
  161. "1"
  162. },
  163. {
  164. "leave",
  165. "2"
  166. },
  167. {
  168. "reset",
  169. "4"
  170. },
  171. {
  172. "status",
  173. "3"
  174. }
  175. };
  176. /*====================================================================*
  177. *
  178. * void manager (struct plc * plc, signed loop, signed wait);
  179. *
  180. * perform operations in logical order despite any order specfied
  181. * on the command line; for example, read PIB before writing PIB;
  182. *
  183. * operation order is controlled by the order of "if" statements
  184. * shown here; the entire operation sequence can be repeated with
  185. * an optional pause between each iteration;
  186. *
  187. *--------------------------------------------------------------------*/
  188. static void manager (struct plc * plc, signed loop, signed wait)
  189. {
  190. while (loop-- > 0)
  191. {
  192. if (_anyset (plc->flags, PLC_VERSION))
  193. {
  194. VersionInfo1 (plc);
  195. }
  196. if (_anyset (plc->flags, PLC_ATTRIBUTES))
  197. {
  198. Attributes1 (plc);
  199. }
  200. if (_anyset (plc->flags, PLC_WATCHDOG_REPORT))
  201. {
  202. WatchdogReport (plc);
  203. }
  204. if (_anyset (plc->flags, PLC_NVRAM_INFO))
  205. {
  206. NVRAMInfo (plc);
  207. }
  208. if (_anyset (plc->flags, PLC_SDRAM_INFO))
  209. {
  210. SDRAMInfo (plc);
  211. }
  212. if (_anyset (plc->flags, PLC_READ_IDENTITY))
  213. {
  214. Identity1 (plc);
  215. }
  216. if (_anyset (plc->flags, PLC_REMOTEHOSTS))
  217. {
  218. RemoteHosts (plc);
  219. }
  220. if (_anyset (plc->flags, PLC_NETWORK))
  221. {
  222. NetInfo2 (plc);
  223. }
  224. if (_anyset (plc->flags, PLC_HOST_ACTION))
  225. {
  226. HostActionResponse (plc);
  227. }
  228. if (_anyset (plc->flags, PLC_PUSH_BUTTON))
  229. {
  230. PushButton (plc);
  231. }
  232. if (_anyset (plc->flags, (PLC_SETLOCALKEY | PLC_SETREMOTEKEY)))
  233. {
  234. SetNMK (plc);
  235. }
  236. if (_anyset (plc->flags, PLC_FACTORY_DEFAULTS))
  237. {
  238. FactoryDefaults (plc);
  239. }
  240. if (_anyset (plc->flags, PLC_READ_PIB))
  241. {
  242. if (AccessLevelPTS (plc) != -1)
  243. {
  244. ModuleRead (plc, & plc->pib, PLC_MOD_OP_READ_FLASH, PLC_MODULEID_PARAMETERS, 0);
  245. }
  246. }
  247. if (_anyset (plc->flags, PLC_READ_MAC))
  248. {
  249. if (AccessLevelPTS (plc) != -1)
  250. {
  251. ModuleRead (plc, & plc->nvm, PLC_MOD_OP_READ_FLASH, PLC_MODULEID_FIRMWARE, 0);
  252. }
  253. }
  254. if (_anyset (plc->flags, PLC_READ_ALL))
  255. {
  256. if (AccessLevelPTS (plc) != -1)
  257. {
  258. ReadFlashMemory2 (plc);
  259. }
  260. }
  261. if (_anyset (plc->flags, PLC_ERASE_DEVICE))
  262. {
  263. if (AccessLevelPTS (plc) != -1)
  264. {
  265. EraseFlashMemory2 (plc);
  266. }
  267. }
  268. if (_anyset (plc->flags, PLC_FLASH_DEVICE))
  269. {
  270. if (AccessLevelPTS (plc) != -1)
  271. {
  272. FlashDevice2 (plc, (PLC_COMMIT_FORCE | PLC_COMMIT_NORESET | PLC_COMMIT_FACTPIB));
  273. }
  274. }
  275. if (_anyset (plc->flags, PLC_RESET_DEVICE))
  276. {
  277. ResetDevice (plc);
  278. }
  279. sleep (wait);
  280. }
  281. return;
  282. }
  283. /*====================================================================*
  284. *
  285. * int main (int argc, char const * argv[]);
  286. *
  287. * parse command line, populate int6k structure and perform selected
  288. * operations; show help summary if asked; see getoptv and putoptv
  289. * to understand command line parsing and help summary display; see
  290. * plc.h for the definition of struct plc;
  291. *
  292. * the command line accepts multiple MAC addresses and the program
  293. * performs the specified operations on each address, in turn; the
  294. * address order is significant but the option order is not; the
  295. * default address is a local broadcast that causes all devices on
  296. * the local H1 interface to respond but not those at the remote
  297. * end of the powerline;
  298. *
  299. * the default address is 00:B0:52:00:00:01; omitting the address
  300. * will automatically address the local device; some options will
  301. * cancel themselves if this makes no sense;
  302. *
  303. * the default interface is eth1 because most people use eth0 as
  304. * their principle network connection; you can specify another
  305. * interface with -i or define environment string PLC to make
  306. * that the default interface and save typing;
  307. *
  308. *--------------------------------------------------------------------*/
  309. int main (int argc, char const * argv [])
  310. {
  311. extern struct channel channel;
  312. extern struct _term_ const devices [];
  313. extern struct _term_ const daks [];
  314. extern struct _term_ const nmks [];
  315. static char const * optv [] =
  316. {
  317. "aAbB:C:d:D:eEfFHi:IJ:K:l:mMn:N:op:P:qQrRst:TvW:w:x12",
  318. "device [device] [...]",
  319. "Qualcomm Atheros AR7450 Powerline Device Manager",
  320. "a\tread Device Attributes using VS_OP_ATTRIBUTES",
  321. "A\trandomize hardware address using VS_RANDOM_ADDR",
  322. "b\tread device enumeration ID table using VS_EM_ID_TABLE",
  323. "B n\tperform pushbutton action (n) using MS_PB_ENC [1|2|3|4|'join'|'leave'|'status'|'reset']",
  324. "C n\tflash NVRAM with module (n) using VS_MOD_NVM [1|2|3|'nvm'|'pib'|'both']",
  325. "d f\tdump and clear watchdog report to file (f) using VS_WD_RPT",
  326. "D x\tset Device Access Key (DAK) to (x) for option -E, -F and -J [" DAK1 "]",
  327. "e\tredirect stderr messages to stdout",
  328. "E\terase NVRAM then reset using VS_PTS_NVM",
  329. "f\tread NVRAM Configuration using VS_GET_NVM",
  330. "F[F]\tflash [force] NVRAM with firmware and PIB using VS_PTS_NVM",
  331. #if defined (WINPCAP) || defined (LIBPCAP)
  332. "i n\thost interface is (n) [" LITERAL (CHANNEL_ETHNUMBER) "]",
  333. #else
  334. "i s\thost interface is (s) [" LITERAL (CHANNEL_ETHDEVICE) "]",
  335. #endif
  336. "H\tstop host action requests using VS_HOST_ACTION.IND",
  337. "I\tread device identity using VS_RD_MOD",
  338. "J\tchange Network Membership Key (NMK) on remote device using VS_SET_KEY (see -D and -K)",
  339. "K x\tset Network Membership Key (NMK) to (x) for options -J or -M [" NMK1 "]",
  340. "l n\tloop (n) times [" LITERAL (DEFAULT_LOOP) "]",
  341. "m\tread network membership information using VS_NW_INFO",
  342. "M\tchange Network Membership Key (NMK) on local device using VS_SET_KEY (see -K)",
  343. "n f\tread NVM from SDRAM to file (f) using VS_RD_MOD",
  344. "N f\twrite NVM file (f) to SDRAM using VS_WR_MOD",
  345. "o\tread flash memory using VS_MODULE_OPERATION",
  346. "p f\tread PIB from SDRAM to file (f) using VS_RD_MOD",
  347. "P f\twrite PIB file (f) to SDRAM using VS_WR_MOD",
  348. "q\tquiet mode",
  349. "Q\tquick flash",
  350. "r\tread hardware and firmware revision using VS_SW_VER",
  351. "R\treset device using VS_RS_DEV",
  352. "s\tread SDRAM Configuration using VS_RD_CBLOCK",
  353. "t n\tread timeout is (n) milliseconds [" LITERAL (CHANNEL_TIMEOUT) "]",
  354. "T\treset factory defaults using VS_FAC_DEFAULTS",
  355. "v\tverbose mode",
  356. "w n\tpause (n) seconds [" LITERAL (DEFAULT_WAIT) "]",
  357. "x\texit on error",
  358. "1\tsuppress confirm MME when resetting device [option -R only]",
  359. "2\tboot from host after reset [option -R only]",
  360. (char const *) (0)
  361. };
  362. #include "../plc/plc.c"
  363. signed loop = DEFAULT_LOOP;
  364. signed wait = DEFAULT_WAIT;
  365. signed c;
  366. if (getenv (PLCDEVICE))
  367. {
  368. #if defined (WINPCAP) || defined (LIBPCAP)
  369. channel.ifindex = atoi (getenv (PLCDEVICE));
  370. #else
  371. channel.ifname = strdup (getenv (PLCDEVICE));
  372. #endif
  373. }
  374. optind = 1;
  375. while (~ (c = getoptv (argc, argv, optv)))
  376. {
  377. switch (c)
  378. {
  379. case 'A':
  380. _setbits (plc.flags, PLC_RANDOM_ADDR);
  381. break;
  382. case 'a':
  383. _setbits (plc.flags, PLC_ATTRIBUTES);
  384. break;
  385. case 'B':
  386. _setbits (plc.flags, PLC_PUSH_BUTTON);
  387. plc.pushbutton = (unsigned) (uintspec (synonym (optarg, buttons, SIZEOF (buttons)), 0, UCHAR_MAX));
  388. break;
  389. case 'b':
  390. _setbits (plc.flags, PLC_REMOTEHOSTS);
  391. break;
  392. case 'C':
  393. _setbits (plc.flags, PLC_FLASH_DEVICE);
  394. plc.module = (unsigned) (uintspec (synonym (optarg, modules, SIZEOF (modules)), 0, UCHAR_MAX));
  395. break;
  396. case 'd':
  397. _setbits (plc.flags, PLC_WATCHDOG_REPORT);
  398. if (! checkfilename (optarg))
  399. {
  400. error (1, EINVAL, "%s", optarg);
  401. }
  402. if ((plc.rpt.file = open (plc.rpt.name = optarg, O_BINARY | O_CREAT | O_RDWR | O_TRUNC, FILE_FILEMODE)) == -1)
  403. {
  404. error (1, errno, "%s", optarg);
  405. }
  406. #ifndef WIN32
  407. chown (optarg, getuid (), getgid ());
  408. #endif
  409. plc.readaction = 3;
  410. break;
  411. case 'D':
  412. if (! hexencode (plc.DAK, sizeof (plc.DAK), synonym (optarg, daks, SIZEOF (daks))))
  413. {
  414. error (1, errno, PLC_BAD_DAK, optarg);
  415. }
  416. break;
  417. case 'e':
  418. dup2 (STDOUT_FILENO, STDERR_FILENO);
  419. break;
  420. case 'E':
  421. _clrbits (plc.flags, PLC_FLASH_DEVICE);
  422. _setbits (plc.flags, PLC_ERASE_DEVICE);
  423. plc.module = 0x0C;
  424. break;
  425. case 'f':
  426. if (_anyset (plc.flags, PLC_NVRAM_INFO))
  427. {
  428. _setbits (plc.flags, PLC_READ_ALL);
  429. }
  430. _setbits (plc.flags, PLC_NVRAM_INFO);
  431. break;
  432. case 'F':
  433. _setbits (plc.module, (VS_MODULE_MAC | VS_MODULE_PIB));
  434. if (_anyset (plc.flags, PLC_FLASH_DEVICE))
  435. {
  436. _setbits (plc.module, VS_MODULE_FORCE);
  437. }
  438. _clrbits (plc.flags, PLC_ERASE_DEVICE);
  439. _setbits (plc.flags, PLC_FLASH_DEVICE);
  440. break;
  441. case 'H':
  442. _setbits (plc.flags, PLC_HOST_ACTION);
  443. break;
  444. case 'I':
  445. _setbits (plc.flags, PLC_READ_IDENTITY);
  446. break;
  447. case 'i':
  448. #if defined (WINPCAP) || defined (LIBPCAP)
  449. channel.ifindex = atoi (optarg);
  450. #else
  451. channel.ifname = optarg;
  452. #endif
  453. break;
  454. case 'J':
  455. if (! hexencode (plc.RDA, sizeof (plc.RDA), (char const *) (optarg)))
  456. {
  457. error (1, errno, PLC_BAD_MAC, optarg);
  458. }
  459. _setbits (plc.flags, PLC_SETREMOTEKEY);
  460. break;
  461. case 'K':
  462. if (! hexencode (plc.NMK, sizeof (plc.NMK), synonym (optarg, nmks, SIZEOF (nmks))))
  463. {
  464. error (1, errno, PLC_BAD_NMK, optarg);
  465. }
  466. break;
  467. case 'M':
  468. _setbits (plc.flags, PLC_SETLOCALKEY);
  469. break;
  470. case 'l':
  471. loop = (unsigned) (uintspec (optarg, 0, UINT_MAX));
  472. break;
  473. case 'm':
  474. _setbits (plc.flags, PLC_NETWORK);
  475. break;
  476. case 'N':
  477. if (! checkfilename (optarg))
  478. {
  479. error (1, EINVAL, "%s", optarg);
  480. }
  481. if ((plc.NVM.file = open (plc.NVM.name = optarg, O_BINARY | O_RDONLY)) == -1)
  482. {
  483. error (1, errno, "%s", optarg);
  484. }
  485. if (lightning_nvm_file (& plc.NVM))
  486. {
  487. error (1, errno, "Bad lightning image file: %s", plc.NVM.name);
  488. }
  489. _setbits (plc.flags, PLC_WRITE_MAC);
  490. break;
  491. case 'n':
  492. if (! checkfilename (optarg))
  493. {
  494. error (1, EINVAL, "%s", optarg);
  495. }
  496. if ((plc.nvm.file = open (plc.nvm.name = optarg, O_BINARY | O_CREAT | O_RDWR | O_TRUNC, FILE_FILEMODE)) == -1)
  497. {
  498. error (1, errno, "%s", optarg);
  499. }
  500. #ifndef WIN32
  501. chown (optarg, getuid (), getgid ());
  502. #endif
  503. _setbits (plc.flags, PLC_READ_MAC);
  504. break;
  505. case 'P':
  506. if (! checkfilename (optarg))
  507. {
  508. error (1, EINVAL, "%s", optarg);
  509. }
  510. if ((plc.PIB.file = open (plc.PIB.name = optarg, O_BINARY | O_RDONLY)) == -1)
  511. {
  512. error (1, errno, "%s", optarg);
  513. }
  514. if (lightning_pib_file (& plc.PIB))
  515. {
  516. error (1, errno, "Bad lightning parameter file: %s", plc.PIB.name);
  517. }
  518. _setbits (plc.flags, PLC_WRITE_PIB);
  519. break;
  520. case 'p':
  521. if (! checkfilename (optarg))
  522. {
  523. error (1, EINVAL, "%s", optarg);
  524. }
  525. if ((plc.pib.file = open (plc.pib.name = optarg, O_BINARY | O_CREAT | O_RDWR | O_TRUNC, FILE_FILEMODE)) == -1)
  526. {
  527. error (1, errno, "%s", optarg);
  528. }
  529. #ifndef WIN32
  530. chown (optarg, getuid (), getgid ());
  531. #endif
  532. _setbits (plc.flags, PLC_READ_PIB);
  533. break;
  534. case 'Q':
  535. _setbits (plc.flags, PLC_QUICK_FLASH);
  536. break;
  537. case 'q':
  538. _setbits (channel.flags, CHANNEL_SILENCE);
  539. _setbits (plc.flags, PLC_SILENCE);
  540. break;
  541. case 'R':
  542. _setbits (plc.flags, PLC_RESET_DEVICE);
  543. break;
  544. case 'r':
  545. _setbits (plc.flags, PLC_VERSION);
  546. break;
  547. case 's':
  548. _setbits (plc.flags, PLC_SDRAM_INFO);
  549. break;
  550. case 't':
  551. channel.timeout = (signed) (uintspec (optarg, 0, UINT_MAX));
  552. break;
  553. case 'T':
  554. _setbits (plc.flags, PLC_FACTORY_DEFAULTS);
  555. break;
  556. case 'v':
  557. _setbits (channel.flags, CHANNEL_VERBOSE);
  558. _setbits (plc.flags, PLC_VERBOSE);
  559. break;
  560. case 'w':
  561. wait = (unsigned) (uintspec (optarg, 0, 3600));
  562. break;
  563. case 'x':
  564. _setbits (plc.flags, PLC_BAILOUT);
  565. break;
  566. case '1':
  567. _setbits (plc.flag2, PLC_FLAG2_CFM_ACT);
  568. break;
  569. case '2':
  570. _setbits (plc.flag2, PLC_FLAG2_BT_SRC);
  571. break;
  572. default:
  573. break;
  574. }
  575. }
  576. argc -= optind;
  577. argv += optind;
  578. if (argc != 1)
  579. {
  580. if (plc.nvm.file != -1)
  581. {
  582. error (1, ECANCELED, PLC_NODEVICE);
  583. }
  584. if (plc.pib.file != -1)
  585. {
  586. error (1, ECANCELED, PLC_NODEVICE);
  587. }
  588. if (plc.rpt.file != -1)
  589. {
  590. error (1, ECANCELED, PLC_NODEVICE);
  591. }
  592. }
  593. openchannel (& channel);
  594. if (! (plc.message = malloc (sizeof (* plc.message))))
  595. {
  596. error (1, errno, PLC_NOMEMORY);
  597. }
  598. if (! argc)
  599. {
  600. manager (& plc, loop, wait);
  601. }
  602. while ((argc) && (* argv))
  603. {
  604. if (! hexencode (channel.peer, sizeof (channel.peer), synonym (* argv, devices, SIZEOF (devices))))
  605. {
  606. error (1, errno, PLC_BAD_MAC, * argv);
  607. }
  608. manager (& plc, loop, wait);
  609. argc--;
  610. argv++;
  611. }
  612. free (plc.message);
  613. closechannel (& channel);
  614. exit (0);
  615. }