jacd.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. /*
  2. * Copyright (c) 2011 EIA Electronics
  3. *
  4. * Authors:
  5. * Kurt Van Dijck <kurt.van.dijck@eia.be>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the version 2 of the GNU General Public License
  9. * as published by the Free Software Foundation
  10. */
  11. #include <signal.h>
  12. #include <time.h>
  13. #include <inttypes.h>
  14. #include <errno.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <getopt.h>
  20. #include <error.h>
  21. #include <sys/time.h>
  22. #include <sys/socket.h>
  23. #include <net/if.h>
  24. #include <linux/can.h>
  25. #include <linux/can/j1939.h>
  26. #include "libj1939.h"
  27. static const char help_msg[] =
  28. "jacd: An SAE J1939 address claiming daemon" "\n"
  29. "Usage: jacd [options] NAME [INTF]" "\n"
  30. "\n"
  31. " -v, --verbose Increase verbosity" "\n"
  32. " -r, --range=RANGE Ranges of source addresses" "\n"
  33. " e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
  34. " -c, --cache=FILE Cache file to save/restore the source address" "\n"
  35. " -a, --address=ADDRESS Start with Source Address ADDRESS" "\n"
  36. " -p, --prefix=STR Prefix to use when logging" "\n"
  37. "\n"
  38. "NAME is the 64bit nodename" "\n"
  39. "\n"
  40. "Example:" "\n"
  41. "jacd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
  42. ;
  43. #ifdef _GNU_SOURCE
  44. static struct option long_opts[] = {
  45. { "help", no_argument, NULL, '?', },
  46. { "verbose", no_argument, NULL, 'v', },
  47. { "range", required_argument, NULL, 'r', },
  48. { "cache", required_argument, NULL, 'c', },
  49. { "address", required_argument, NULL, 'a', },
  50. { "prefix", required_argument, NULL, 'p', },
  51. { },
  52. };
  53. #else
  54. #define getopt_long(argc, argv, optstring, longopts, longindex) \
  55. getopt((argc), (argv), (optstring))
  56. #endif
  57. static const char optstring[] = "vr:c:a:p:?";
  58. /* byte swap functions */
  59. static inline int host_is_little_endian(void)
  60. {
  61. static const uint16_t endian_test = 1;
  62. return *(const uint8_t *)&endian_test;
  63. }
  64. static __attribute__((unused)) void bswap(void *vptr, int size)
  65. {
  66. uint8_t *p0, *pe;
  67. uint8_t tmp;
  68. p0 = vptr;
  69. pe = &p0[size-1];
  70. for (; p0 < pe; ++p0, --pe) {
  71. tmp = *p0;
  72. *p0 = *pe;
  73. *pe = tmp;
  74. }
  75. }
  76. /* rate-limiting for errors */
  77. static inline int must_warn(int ret)
  78. {
  79. if (ret >= 0)
  80. return 0;
  81. switch (errno) {
  82. case EINTR:
  83. case ENOBUFS:
  84. return 0;
  85. }
  86. return 1;
  87. }
  88. /* global variables */
  89. static char default_range[] = "0x80-0xfd";
  90. static const char default_intf[] = "can0";
  91. static struct {
  92. int verbose;
  93. const char *cachefile;
  94. const char *intf;
  95. char *ranges;
  96. uint64_t name;
  97. uint8_t current_sa;
  98. uint8_t last_sa;
  99. int sig_term;
  100. int sig_alrm;
  101. int sig_usr1;
  102. int state;
  103. #define STATE_INITIAL 0
  104. #define STATE_REQ_SENT 1
  105. #define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */
  106. #define STATE_OPERATIONAL 3
  107. } s = {
  108. .intf = default_intf,
  109. .ranges = default_range,
  110. .current_sa = J1939_IDLE_ADDR,
  111. .last_sa = J1939_NO_ADDR,
  112. };
  113. struct {
  114. uint64_t name;
  115. int flags;
  116. #define F_USE 0x01
  117. #define F_SEEN 0x02
  118. } addr[J1939_IDLE_ADDR /* =254 */];
  119. /* lookup by name */
  120. static int lookup_name(uint64_t name)
  121. {
  122. int j;
  123. for (j = 0; j < J1939_IDLE_ADDR; ++j) {
  124. if (addr[j].name == name)
  125. return j;
  126. }
  127. return J1939_IDLE_ADDR;
  128. }
  129. /* parse address range */
  130. static int parse_range(char *str)
  131. {
  132. char *tok, *endp;
  133. int a0, ae;
  134. int j, cnt;
  135. cnt = 0;
  136. for (tok = strtok(str, ",;"); tok; tok = strtok(NULL, ",;")) {
  137. a0 = ae = strtoul(tok, &endp, 0);
  138. if (endp <= tok)
  139. error(1, 0, "parsing range '%s'", tok);
  140. if (*endp == '-') {
  141. tok = endp+1;
  142. ae = strtoul(tok, &endp, 0);
  143. if (endp <= tok)
  144. error(1, 0, "parsing addr '%s'", tok);
  145. if (ae < a0)
  146. ae = a0;
  147. }
  148. for (j = a0; j <= ae; ++j, ++cnt) {
  149. if (j == J1939_IDLE_ADDR)
  150. break;
  151. addr[j].flags |= F_USE;
  152. }
  153. }
  154. return cnt;
  155. }
  156. /* j1939 socket */
  157. static const struct j1939_filter filt[] = {
  158. {
  159. .pgn = 0x0ee00,
  160. .pgn_mask = 0x3ff00,
  161. }, {
  162. .pgn = 0x0ea00,
  163. .pgn_mask = 0x3ff00,
  164. }, {
  165. .pgn = 0x0fed8,
  166. .pgn_mask = 0x3ffff,
  167. },
  168. };
  169. static int open_socket(const char *device, uint64_t name)
  170. {
  171. int ret, sock;
  172. int value;
  173. struct sockaddr_can saddr = {
  174. .can_family = AF_CAN,
  175. .can_addr.j1939 = {
  176. .name = name,
  177. .addr = J1939_IDLE_ADDR,
  178. .pgn = 0x0ee00,
  179. },
  180. .can_ifindex = if_nametoindex(s.intf),
  181. };
  182. if (s.verbose)
  183. fprintf(stderr, "- socket(PF_CAN, SOCK_DGRAM, CAN_J1939);\n");
  184. sock = ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
  185. if (ret < 0)
  186. error(1, errno, "socket(j1939)");
  187. if (s.verbose)
  188. fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BINDTODEVICE, %s, %zd);\n", device, strlen(device));
  189. ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
  190. device, strlen(device));
  191. if (ret < 0)
  192. error(1, errno, "bindtodevice %s", device);
  193. if (s.verbose)
  194. fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_FILTER, <filter>, %zd);\n", sizeof(filt));
  195. ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER,
  196. &filt, sizeof(filt));
  197. if (ret < 0)
  198. error(1, errno, "setsockopt filter");
  199. value = 1;
  200. if (s.verbose)
  201. fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_RECV_OWN, %d, %zd);\n", value, sizeof(value));
  202. ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_RECV_OWN,
  203. &value, sizeof(value));
  204. if (ret < 0)
  205. error(1, errno, "setsockopt receive own msgs");
  206. if (s.verbose)
  207. fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&saddr), sizeof(saddr));
  208. ret = bind(sock, (void *)&saddr, sizeof(saddr));
  209. if (ret < 0)
  210. error(1, errno, "bind()");
  211. return sock;
  212. }
  213. /* real IO function */
  214. static int repeat_address(int sock, uint64_t name)
  215. {
  216. int ret;
  217. uint8_t dat[8];
  218. memcpy(dat, &name, 8);
  219. if (!host_is_little_endian())
  220. bswap(dat, 8);
  221. if (s.verbose)
  222. fprintf(stderr, "- send(, %" PRId64 ", 8, 0);\n", name);
  223. ret = send(sock, dat, 8, 0);
  224. if (must_warn(ret))
  225. error(1, errno, "send address claim for 0x%02x", s.last_sa);
  226. return ret;
  227. }
  228. static int claim_address(int sock, uint64_t name, int sa)
  229. {
  230. int ret;
  231. struct sockaddr_can saddr = {
  232. .can_family = AF_CAN,
  233. .can_addr.j1939 = {
  234. .name = name,
  235. .addr = sa,
  236. .pgn = 0x0ee00,
  237. },
  238. .can_ifindex = if_nametoindex(s.intf),
  239. };
  240. if (s.verbose)
  241. fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&saddr), sizeof(saddr));
  242. ret = bind(sock, (void *)&saddr, sizeof(saddr));
  243. if (ret < 0)
  244. error(1, errno, "rebind with sa 0x%02x", sa);
  245. s.last_sa = sa;
  246. return repeat_address(sock, name);
  247. }
  248. static int request_addresses(int sock)
  249. {
  250. static const uint8_t dat[3] = { 0, 0xee, 0, };
  251. int ret;
  252. static const struct sockaddr_can saddr = {
  253. .can_family = AF_CAN,
  254. .can_addr.j1939.pgn = 0x0ea00,
  255. .can_addr.j1939.addr = J1939_NO_ADDR,
  256. };
  257. if (s.verbose)
  258. fprintf(stderr, "- sendto(, { 0, 0xee, 0, }, %zi, 0, %s, %zi);\n", sizeof(dat), libj1939_addr2str(&saddr), sizeof(saddr));
  259. ret = sendto(sock, dat, sizeof(dat), 0, (void *)&saddr, sizeof(saddr));
  260. if (must_warn(ret))
  261. error(1, errno, "send request for address claims");
  262. return ret;
  263. }
  264. /* real policy */
  265. static int choose_new_sa(uint64_t name, int sa)
  266. {
  267. int j, cnt;
  268. /* test current entry */
  269. if ((sa < J1939_IDLE_ADDR) && (addr[sa].flags & F_USE)) {
  270. j = sa;
  271. if (!addr[j].name || (addr[j].name == name) || (addr[j].name > name))
  272. return j;
  273. }
  274. /* take first empty spot */
  275. for (j = 0; j < J1939_IDLE_ADDR; ++j) {
  276. if (!(addr[j].flags & F_USE))
  277. continue;
  278. if (!addr[j].name || (addr[j].name == name))
  279. return j;
  280. }
  281. /*
  282. * no empty spot found
  283. * take next (relative to @sa) spot that we can
  284. * successfully contest
  285. */
  286. j = sa + 1;
  287. for (cnt = 0; cnt < J1939_IDLE_ADDR; ++j, ++cnt) {
  288. if (j >= J1939_IDLE_ADDR)
  289. j = 0;
  290. if (!(addr[j].flags & F_USE))
  291. continue;
  292. if (name < addr[j].name)
  293. return j;
  294. }
  295. return J1939_IDLE_ADDR;
  296. }
  297. /* signa handling */
  298. static void sighandler(int sig, siginfo_t *info, void *vp)
  299. {
  300. switch (sig) {
  301. case SIGINT:
  302. case SIGTERM:
  303. s.sig_term = 1;
  304. break;
  305. case SIGALRM:
  306. s.sig_alrm = 1;
  307. break;
  308. case SIGUSR1:
  309. s.sig_usr1 = 1;
  310. break;
  311. }
  312. }
  313. static void install_signal(int sig)
  314. {
  315. int ret;
  316. struct sigaction sigact = {
  317. .sa_sigaction = sighandler,
  318. .sa_flags = SA_SIGINFO,
  319. };
  320. sigfillset(&sigact.sa_mask);
  321. ret = sigaction(sig, &sigact, NULL);
  322. if (ret < 0)
  323. error(1, errno, "sigaction for signal %i", sig);
  324. }
  325. static void schedule_itimer(int msec)
  326. {
  327. int ret;
  328. struct itimerval val = {};
  329. val.it_value.tv_sec = msec / 1000;
  330. val.it_value.tv_usec = (msec % 1000) * 1000;
  331. s.sig_alrm = 0;
  332. do {
  333. ret = setitimer(ITIMER_REAL, &val, NULL);
  334. } while ((ret < 0) && (errno == EINTR));
  335. if (ret < 0)
  336. error(1, errno, "setitimer %i msec", msec);
  337. }
  338. /* dump status */
  339. static inline int addr_status_mine(int sa)
  340. {
  341. if (sa == s.current_sa)
  342. return '*';
  343. else if (addr[sa].flags & F_USE)
  344. return '+';
  345. else
  346. return '-';
  347. }
  348. static void dump_status(void)
  349. {
  350. int j;
  351. for (j = 0; j < J1939_IDLE_ADDR; ++j) {
  352. if (!addr[j].flags && !addr[j].name)
  353. continue;
  354. fprintf(stdout, "%02x: %c", j, addr_status_mine(j));
  355. if (addr[j].name)
  356. fprintf(stdout, " %016llx", (long long)addr[j].name);
  357. else
  358. fprintf(stdout, " -");
  359. fprintf(stdout, "\n");
  360. }
  361. fflush(stdout);
  362. }
  363. /* cache file */
  364. static void save_cache(void)
  365. {
  366. FILE *fp;
  367. time_t t;
  368. if (!s.cachefile)
  369. return;
  370. fp = fopen(s.cachefile, "w");
  371. if (!fp)
  372. error(1, errno, "fopen %s, w", s.cachefile);
  373. time(&t);
  374. fprintf(fp, "# saved on %s\n", ctime(&t));
  375. fprintf(fp, "\n");
  376. fprintf(fp, "0x%02x\n", s.current_sa);
  377. fclose(fp);
  378. }
  379. static void restore_cache(void)
  380. {
  381. FILE *fp;
  382. int ret;
  383. char *endp;
  384. char *line = 0;
  385. size_t sz = 0;
  386. if (!s.cachefile)
  387. return;
  388. fp = fopen(s.cachefile, "r");
  389. if (!fp) {
  390. if (ENOENT == errno)
  391. return;
  392. error(1, errno, "fopen %s, r", s.cachefile);
  393. }
  394. while (!feof(fp)) {
  395. ret = getline(&line, &sz, fp);
  396. if (ret <= 0)
  397. continue;
  398. if (line[0] == '#')
  399. continue;
  400. ret = strtoul(line, &endp, 0);
  401. if ((endp > line) && (ret >= 0) && (ret <= J1939_IDLE_ADDR)) {
  402. s.current_sa = ret;
  403. break;
  404. }
  405. }
  406. fclose(fp);
  407. if (line)
  408. free(line);
  409. }
  410. /* main */
  411. int main(int argc, char *argv[])
  412. {
  413. int ret, sock, pgn, sa, opt;
  414. socklen_t slen;
  415. uint8_t dat[9];
  416. struct sockaddr_can saddr;
  417. uint64_t cmd_name;
  418. #ifdef _GNU_SOURCE
  419. program_invocation_name = program_invocation_short_name;
  420. #endif
  421. /* argument parsing */
  422. while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
  423. switch (opt) {
  424. case 'v':
  425. ++s.verbose;
  426. break;
  427. case 'c':
  428. s.cachefile = optarg;
  429. break;
  430. case 'r':
  431. s.ranges = optarg;
  432. break;
  433. case 'a':
  434. s.current_sa = strtoul(optarg, 0, 0);
  435. break;
  436. case 'p':
  437. #ifdef _GNU_SOURCE
  438. asprintf(&program_invocation_name, "%s.%s", program_invocation_short_name, optarg);
  439. #else
  440. error(0, 0, "compile with -D_GNU_SOURCE to use -p");
  441. #endif
  442. break;
  443. default:
  444. fputs(help_msg, stderr);
  445. exit(1);
  446. break;
  447. }
  448. if (argv[optind])
  449. s.name = strtoull(argv[optind++], 0, 16);
  450. if (argv[optind])
  451. s.intf = argv[optind++];
  452. /* args done */
  453. restore_cache();
  454. ret = parse_range(s.ranges);
  455. if (!ret)
  456. error(1, 0, "no addresses in range");
  457. if ((s.current_sa < J1939_IDLE_ADDR) && !(addr[s.current_sa].flags & F_USE)) {
  458. if (s.verbose)
  459. error(0, 0, "forget saved address 0x%02x", s.current_sa);
  460. s.current_sa = J1939_IDLE_ADDR;
  461. }
  462. if (s.verbose)
  463. error(0, 0, "ready for %s:%016llx", s.intf, (long long)s.name);
  464. if (!s.intf || !s.name)
  465. error(1, 0, "bad arguments");
  466. ret = sock = open_socket(s.intf, s.name);
  467. install_signal(SIGTERM);
  468. install_signal(SIGINT);
  469. install_signal(SIGALRM);
  470. install_signal(SIGUSR1);
  471. install_signal(SIGUSR2);
  472. while (!s.sig_term) {
  473. if (s.sig_usr1) {
  474. s.sig_usr1 = 0;
  475. dump_status();
  476. }
  477. switch (s.state) {
  478. case STATE_INITIAL:
  479. ret = request_addresses(sock);
  480. if (ret < 0)
  481. error(1, errno, "could not sent initial request");
  482. s.state = STATE_REQ_SENT;
  483. break;
  484. case STATE_REQ_PENDING:
  485. if (!s.sig_alrm)
  486. break;
  487. s.sig_alrm = 0;
  488. /* claim addr */
  489. sa = choose_new_sa(s.name, s.current_sa);
  490. if (sa == J1939_IDLE_ADDR)
  491. error(1, 0, "no free address to use");
  492. ret = claim_address(sock, s.name, sa);
  493. if (ret < 0)
  494. schedule_itimer(50);
  495. s.state = STATE_OPERATIONAL;
  496. break;
  497. case STATE_OPERATIONAL:
  498. if (s.sig_alrm) {
  499. s.sig_alrm = 0;
  500. ret = repeat_address(sock, s.name);
  501. if (ret < 0)
  502. schedule_itimer(50);
  503. }
  504. break;
  505. }
  506. slen = sizeof(saddr);
  507. ret = recvfrom(sock, dat, sizeof(dat), 0, (void *)&saddr, &slen);
  508. if (ret < 0) {
  509. if (EINTR == errno)
  510. continue;
  511. error(1, errno, "recvfrom()");
  512. }
  513. switch (saddr.can_addr.j1939.pgn) {
  514. case 0x0ea00:
  515. if (ret < 3)
  516. break;
  517. pgn = dat[0] + (dat[1] << 8) + ((dat[2] & 0x03) << 16);
  518. if (pgn != 0x0ee00)
  519. /* not interested */
  520. break;
  521. if (s.state == STATE_REQ_SENT) {
  522. if (s.verbose)
  523. error(0, 0, "request sent, pending for 1250 ms");
  524. schedule_itimer(1250);
  525. s.state = STATE_REQ_PENDING;
  526. } else if (s.state == STATE_OPERATIONAL) {
  527. ret = claim_address(sock, s.name, s.current_sa);
  528. if (ret < 0)
  529. schedule_itimer(50);
  530. }
  531. break;
  532. case 0x0ee00:
  533. if (saddr.can_addr.j1939.addr >= J1939_IDLE_ADDR) {
  534. sa = lookup_name(saddr.can_addr.j1939.name);
  535. if (sa < J1939_IDLE_ADDR)
  536. addr[sa].name = 0;
  537. break;
  538. }
  539. sa = lookup_name(saddr.can_addr.j1939.name);
  540. if ((sa != saddr.can_addr.j1939.addr) && (sa < J1939_IDLE_ADDR))
  541. /* update cache */
  542. addr[sa].name = 0;
  543. /* shortcut */
  544. sa = saddr.can_addr.j1939.addr;
  545. addr[sa].name = saddr.can_addr.j1939.name;
  546. addr[sa].flags |= F_SEEN;
  547. if (s.name == saddr.can_addr.j1939.name) {
  548. /* ourselve, disable itimer */
  549. s.current_sa = sa;
  550. if (s.verbose)
  551. error(0, 0, "claimed 0x%02x", sa);
  552. } else if (sa == s.current_sa) {
  553. if (s.verbose)
  554. error(0, 0, "address collision for 0x%02x", sa);
  555. if (s.name > saddr.can_addr.j1939.name) {
  556. sa = choose_new_sa(s.name, sa);
  557. if (sa == J1939_IDLE_ADDR) {
  558. error(0, 0, "no address left");
  559. /* put J1939_IDLE_ADDR in cache file */
  560. s.current_sa = sa;
  561. goto done;
  562. }
  563. }
  564. ret = claim_address(sock, s.name, sa);
  565. if (ret < 0)
  566. schedule_itimer(50);
  567. }
  568. break;
  569. case 0x0fed8:
  570. if (!host_is_little_endian())
  571. bswap(dat, 8);
  572. memcpy(&cmd_name, dat, 8);
  573. if (cmd_name == s.name) {
  574. ret = claim_address(sock, s.name, dat[8]);
  575. if (ret < 0)
  576. schedule_itimer(50);
  577. }
  578. break;
  579. }
  580. }
  581. done:
  582. if (s.verbose)
  583. error(0, 0, "shutdown");
  584. claim_address(sock, s.name, J1939_IDLE_ADDR);
  585. save_cache();
  586. return 0;
  587. }