You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

629 lines
14 KiB

1 year ago
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <sys/ioctl.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <asm/termbits.h> /* struct termios2 */
  11. #include <time.h>
  12. #include <ctype.h>
  13. #include <signal.h>
  14. #include <sys/time.h>
  15. #define CANUSB_INJECT_SLEEP_GAP_DEFAULT 200 /* ms */
  16. #define CANUSB_TTY_BAUD_RATE_DEFAULT 2000000
  17. typedef enum {
  18. CANUSB_SPEED_1000000 = 0x01,
  19. CANUSB_SPEED_800000 = 0x02,
  20. CANUSB_SPEED_500000 = 0x03,
  21. CANUSB_SPEED_400000 = 0x04,
  22. CANUSB_SPEED_250000 = 0x05,
  23. CANUSB_SPEED_200000 = 0x06,
  24. CANUSB_SPEED_125000 = 0x07,
  25. CANUSB_SPEED_100000 = 0x08,
  26. CANUSB_SPEED_50000 = 0x09,
  27. CANUSB_SPEED_20000 = 0x0a,
  28. CANUSB_SPEED_10000 = 0x0b,
  29. CANUSB_SPEED_5000 = 0x0c,
  30. } CANUSB_SPEED;
  31. typedef enum {
  32. CANUSB_MODE_NORMAL = 0x00,
  33. CANUSB_MODE_LOOPBACK = 0x01,
  34. CANUSB_MODE_SILENT = 0x02,
  35. CANUSB_MODE_LOOPBACK_SILENT = 0x03,
  36. } CANUSB_MODE;
  37. typedef enum {
  38. CANUSB_FRAME_STANDARD = 0x01,
  39. CANUSB_FRAME_EXTENDED = 0x02,
  40. } CANUSB_FRAME;
  41. typedef enum {
  42. CANUSB_INJECT_PAYLOAD_MODE_RANDOM = 0,
  43. CANUSB_INJECT_PAYLOAD_MODE_INCREMENTAL = 1,
  44. CANUSB_INJECT_PAYLOAD_MODE_FIXED = 2,
  45. } CANUSB_PAYLOAD_MODE;
  46. static int terminate_after = 0;
  47. static int program_running = 1;
  48. static int inject_payload_mode = CANUSB_INJECT_PAYLOAD_MODE_FIXED;
  49. static float inject_sleep_gap = CANUSB_INJECT_SLEEP_GAP_DEFAULT;
  50. static int print_traffic = 0;
  51. static CANUSB_SPEED canusb_int_to_speed(int speed)
  52. {
  53. switch (speed) {
  54. case 1000000:
  55. return CANUSB_SPEED_1000000;
  56. case 800000:
  57. return CANUSB_SPEED_800000;
  58. case 500000:
  59. return CANUSB_SPEED_500000;
  60. case 400000:
  61. return CANUSB_SPEED_400000;
  62. case 250000:
  63. return CANUSB_SPEED_250000;
  64. case 200000:
  65. return CANUSB_SPEED_200000;
  66. case 125000:
  67. return CANUSB_SPEED_125000;
  68. case 100000:
  69. return CANUSB_SPEED_100000;
  70. case 50000:
  71. return CANUSB_SPEED_50000;
  72. case 20000:
  73. return CANUSB_SPEED_20000;
  74. case 10000:
  75. return CANUSB_SPEED_10000;
  76. case 5000:
  77. return CANUSB_SPEED_5000;
  78. default:
  79. return 0;
  80. }
  81. }
  82. static int generate_checksum(const unsigned char *data, int data_len)
  83. {
  84. int i, checksum;
  85. checksum = 0;
  86. for (i = 0; i < data_len; i++) {
  87. checksum += data[i];
  88. }
  89. return checksum & 0xff;
  90. }
  91. static int frame_is_complete(const unsigned char *frame, int frame_len)
  92. {
  93. if (frame_len > 0) {
  94. if (frame[0] != 0xaa) {
  95. /* Need to sync on 0xaa at start of frames, so just skip. */
  96. return 1;
  97. }
  98. }
  99. if (frame_len < 2) {
  100. return 0;
  101. }
  102. if (frame[1] == 0x55) { /* Command frame... */
  103. if (frame_len >= 20) { /* ...always 20 bytes. */
  104. return 1;
  105. } else {
  106. return 0;
  107. }
  108. } else if ((frame[1] >> 4) == 0xc) { /* Data frame... */
  109. if (frame_len >= (frame[1] & 0xf) + 5) { /* ...payload and 5 bytes. */
  110. return 1;
  111. } else {
  112. return 0;
  113. }
  114. }
  115. /* Unhandled frame type. */
  116. return 1;
  117. }
  118. static int frame_send(int tty_fd, const unsigned char *frame, int frame_len)
  119. {
  120. int result, i;
  121. if (print_traffic) {
  122. printf(">>> ");
  123. for (i = 0; i < frame_len; i++) {
  124. printf("%02x ", frame[i]);
  125. }
  126. if (print_traffic > 1) {
  127. printf(" '");
  128. for (i = 4; i < frame_len - 1; i++) {
  129. printf("%c", isalnum(frame[i]) ? frame[i] : '.');
  130. }
  131. printf("'");
  132. }
  133. printf("\n");
  134. }
  135. result = write(tty_fd, frame, frame_len);
  136. if (result == -1) {
  137. fprintf(stderr, "write() failed: %s\n", strerror(errno));
  138. return -1;
  139. }
  140. return frame_len;
  141. }
  142. static int frame_recv(int tty_fd, unsigned char *frame, int frame_len_max)
  143. {
  144. int result, frame_len, checksum;
  145. unsigned char byte;
  146. if (print_traffic)
  147. fprintf(stderr, "<<< ");
  148. frame_len = 0;
  149. while (program_running) {
  150. result = read(tty_fd, &byte, 1);
  151. if (result == -1) {
  152. if (errno != EAGAIN && errno != EWOULDBLOCK) {
  153. fprintf(stderr, "read() failed: %s\n", strerror(errno));
  154. return -1;
  155. }
  156. } else if (result > 0) {
  157. if (print_traffic)
  158. fprintf(stderr, "%02x ", byte);
  159. if (frame_len == frame_len_max) {
  160. fprintf(stderr, "frame_recv() failed: Overflow\n");
  161. return -1;
  162. }
  163. frame[frame_len++] = byte;
  164. if (frame_is_complete(frame, frame_len)) {
  165. break;
  166. }
  167. }
  168. usleep(10);
  169. }
  170. if (print_traffic)
  171. fprintf(stderr, "\n");
  172. /* Compare checksum for command frames only. */
  173. if ((frame_len == 20) && (frame[0] == 0xaa) && (frame[1] == 0x55)) {
  174. checksum = generate_checksum(&frame[2], 17);
  175. if (checksum != frame[frame_len - 1]) {
  176. fprintf(stderr, "frame_recv() failed: Checksum incorrect\n");
  177. return -1;
  178. }
  179. }
  180. return frame_len;
  181. }
  182. static int command_settings(int tty_fd, CANUSB_SPEED speed, CANUSB_MODE mode, CANUSB_FRAME frame)
  183. {
  184. int cmd_frame_len;
  185. unsigned char cmd_frame[20];
  186. cmd_frame_len = 0;
  187. cmd_frame[cmd_frame_len++] = 0xaa;
  188. cmd_frame[cmd_frame_len++] = 0x55;
  189. cmd_frame[cmd_frame_len++] = 0x12;
  190. cmd_frame[cmd_frame_len++] = speed;
  191. cmd_frame[cmd_frame_len++] = frame;
  192. cmd_frame[cmd_frame_len++] = 0; /* Filter ID not handled. */
  193. cmd_frame[cmd_frame_len++] = 0; /* Filter ID not handled. */
  194. cmd_frame[cmd_frame_len++] = 0; /* Filter ID not handled. */
  195. cmd_frame[cmd_frame_len++] = 0; /* Filter ID not handled. */
  196. cmd_frame[cmd_frame_len++] = 0; /* Mask ID not handled. */
  197. cmd_frame[cmd_frame_len++] = 0; /* Mask ID not handled. */
  198. cmd_frame[cmd_frame_len++] = 0; /* Mask ID not handled. */
  199. cmd_frame[cmd_frame_len++] = 0; /* Mask ID not handled. */
  200. cmd_frame[cmd_frame_len++] = mode;
  201. cmd_frame[cmd_frame_len++] = 0x01;
  202. cmd_frame[cmd_frame_len++] = 0;
  203. cmd_frame[cmd_frame_len++] = 0;
  204. cmd_frame[cmd_frame_len++] = 0;
  205. cmd_frame[cmd_frame_len++] = 0;
  206. cmd_frame[cmd_frame_len++] = generate_checksum(&cmd_frame[2], 17);
  207. if (frame_send(tty_fd, cmd_frame, cmd_frame_len) < 0) {
  208. return -1;
  209. }
  210. return 0;
  211. }
  212. static int send_data_frame(int tty_fd, CANUSB_FRAME frame, unsigned char id_lsb, unsigned char id_msb, unsigned char data[], int data_length_code)
  213. {
  214. #define MAX_FRAME_SIZE 13
  215. int data_frame_len = 0;
  216. unsigned char data_frame[MAX_FRAME_SIZE] = {0x00};
  217. if (data_length_code < 0 || data_length_code > 8)
  218. {
  219. fprintf(stderr, "Data length code (DLC) must be between 0 and 8!\n");
  220. return -1;
  221. }
  222. /* Byte 0: Packet Start */
  223. data_frame[data_frame_len++] = 0xaa;
  224. /* Byte 1: CAN Bus Data Frame Information */
  225. data_frame[data_frame_len] = 0x00;
  226. data_frame[data_frame_len] |= 0xC0; /* Bit 7 Always 1, Bit 6 Always 1 */
  227. if (frame == CANUSB_FRAME_STANDARD)
  228. data_frame[data_frame_len] &= 0xDF; /* STD frame */
  229. else /* CANUSB_FRAME_EXTENDED */
  230. data_frame[data_frame_len] |= 0x20; /* EXT frame */
  231. data_frame[data_frame_len] &= 0xEF; /* 0=Data */
  232. data_frame[data_frame_len] |= data_length_code; /* DLC=data_len */
  233. data_frame_len++;
  234. /* Byte 2 to 3: ID */
  235. data_frame[data_frame_len++] = id_lsb; /* lsb */
  236. data_frame[data_frame_len++] = id_msb; /* msb */
  237. /* Byte 4 to (4+data_len): Data */
  238. for (int i = 0; i < data_length_code; i++)
  239. data_frame[data_frame_len++] = data[i];
  240. /* Last byte: End of frame */
  241. data_frame[data_frame_len++] = 0x55;
  242. if (frame_send(tty_fd, data_frame, data_frame_len) < 0)
  243. {
  244. fprintf(stderr, "Unable to send frame!\n");
  245. return -1;
  246. }
  247. return 0;
  248. }
  249. static int hex_value(int c)
  250. {
  251. if (c >= 0x30 && c <= 0x39) /* '0' - '9' */
  252. return c - 0x30;
  253. else if (c >= 0x41 && c <= 0x46) /* 'A' - 'F' */
  254. return (c - 0x41) + 10;
  255. else if (c >= 0x61 && c <= 0x66) /* 'a' - 'f' */
  256. return (c - 0x61) + 10;
  257. else
  258. return -1;
  259. }
  260. static int convert_from_hex(const char *hex_string, unsigned char *bin_string, int bin_string_len)
  261. {
  262. int n1, n2, high;
  263. high = -1;
  264. n1 = n2 = 0;
  265. while (hex_string[n1] != '\0') {
  266. if (hex_value(hex_string[n1]) >= 0) {
  267. if (high == -1) {
  268. high = hex_string[n1];
  269. } else {
  270. bin_string[n2] = hex_value(high) * 16 + hex_value(hex_string[n1]);
  271. n2++;
  272. if (n2 >= bin_string_len) {
  273. printf("hex string truncated to %d bytes\n", n2);
  274. break;
  275. }
  276. high = -1;
  277. }
  278. }
  279. n1++;
  280. }
  281. return n2;
  282. }
  283. static int inject_data_frame(int tty_fd, const char *hex_id, const char *hex_data)
  284. {
  285. int data_len;
  286. unsigned char binary_data[8];
  287. unsigned char binary_id_lsb = 0, binary_id_msb = 0;
  288. struct timespec gap_ts;
  289. struct timeval now;
  290. int error = 0;
  291. gap_ts.tv_sec = inject_sleep_gap / 1000;
  292. gap_ts.tv_nsec = (long)(((long long)(inject_sleep_gap * 1000000)) % 1000000000LL);
  293. /* Set seed value for pseudo random numbers. */
  294. gettimeofday(&now, NULL);
  295. srandom(now.tv_usec);
  296. data_len = convert_from_hex(hex_data, binary_data, sizeof(binary_data));
  297. if (data_len == 0) {
  298. fprintf(stderr, "Unable to convert data from hex to binary!\n");
  299. return -1;
  300. }
  301. switch (strlen(hex_id)) {
  302. case 1:
  303. binary_id_lsb = hex_value(hex_id[0]);
  304. break;
  305. case 2:
  306. binary_id_lsb = (hex_value(hex_id[0]) * 16) + hex_value(hex_id[1]);
  307. break;
  308. case 3:
  309. binary_id_msb = hex_value(hex_id[0]);
  310. binary_id_lsb = (hex_value(hex_id[1]) * 16) + hex_value(hex_id[2]);
  311. break;
  312. default:
  313. fprintf(stderr, "Unable to convert ID from hex to binary!\n");
  314. return -1;
  315. }
  316. while (program_running && ! error) {
  317. if (gap_ts.tv_sec || gap_ts.tv_nsec)
  318. nanosleep(&gap_ts, NULL);
  319. if (terminate_after && (--terminate_after == 0))
  320. program_running = 0;
  321. if (inject_payload_mode == CANUSB_INJECT_PAYLOAD_MODE_RANDOM) {
  322. int i;
  323. for (i = 0; i < data_len; i++)
  324. binary_data[i] = random();
  325. } else if (inject_payload_mode == CANUSB_INJECT_PAYLOAD_MODE_INCREMENTAL) {
  326. int i;
  327. for (i = 0; i < data_len; i++)
  328. binary_data[i]++;
  329. }
  330. error = send_data_frame(tty_fd, CANUSB_FRAME_STANDARD, binary_id_lsb, binary_id_msb, binary_data, data_len);
  331. }
  332. return error;
  333. }
  334. static void dump_data_frames(int tty_fd)
  335. {
  336. int i, frame_len;
  337. unsigned char frame[32];
  338. struct timespec ts;
  339. while (program_running) {
  340. frame_len = frame_recv(tty_fd, frame, sizeof(frame));
  341. if (! program_running)
  342. break;
  343. clock_gettime(CLOCK_MONOTONIC, &ts);
  344. printf("%lu.%06lu ", ts.tv_sec, ts.tv_nsec / 1000);
  345. if (frame_len == -1) {
  346. printf("Frame recieve error!\n");
  347. } else {
  348. if ((frame_len >= 6) &&
  349. (frame[0] == 0xaa) &&
  350. ((frame[1] >> 4) == 0xc)) {
  351. printf("Frame ID: %02x%02x, Data: ", frame[3], frame[2]);
  352. for (i = frame_len - 2; i > 3; i--) {
  353. printf("%02x ", frame[i]);
  354. }
  355. printf("\n");
  356. } else {
  357. printf("Unknown: ");
  358. for (i = 0; i <= frame_len; i++) {
  359. printf("%02x ", frame[i]);
  360. }
  361. printf("\n");
  362. }
  363. }
  364. if (terminate_after && (--terminate_after == 0))
  365. program_running = 0;
  366. }
  367. }
  368. static int adapter_init(const char *tty_device, int baudrate)
  369. {
  370. int tty_fd, result;
  371. struct termios2 tio;
  372. tty_fd = open(tty_device, O_RDWR | O_NOCTTY | O_NONBLOCK);
  373. if (tty_fd == -1) {
  374. fprintf(stderr, "open(%s) failed: %s\n", tty_device, strerror(errno));
  375. return -1;
  376. }
  377. result = ioctl(tty_fd, TCGETS2, &tio);
  378. if (result == -1) {
  379. fprintf(stderr, "ioctl() failed: %s\n", strerror(errno));
  380. close(tty_fd);
  381. return -1;
  382. }
  383. tio.c_cflag &= ~CBAUD;
  384. tio.c_cflag = BOTHER | CS8 | CSTOPB;
  385. tio.c_iflag = IGNPAR;
  386. tio.c_oflag = 0;
  387. tio.c_lflag = 0;
  388. tio.c_ispeed = baudrate;
  389. tio.c_ospeed = baudrate;
  390. result = ioctl(tty_fd, TCSETS2, &tio);
  391. if (result == -1) {
  392. fprintf(stderr, "ioctl() failed: %s\n", strerror(errno));
  393. close(tty_fd);
  394. return -1;
  395. }
  396. return tty_fd;
  397. }
  398. static void display_help(const char *progname)
  399. {
  400. fprintf(stderr, "Usage: %s <options>\n", progname);
  401. fprintf(stderr, "Options:\n"
  402. " -h Display this help and exit.\n"
  403. " -t Print TTY/serial traffic debugging info on stderr.\n"
  404. " -d DEVICE Use TTY DEVICE.\n"
  405. " -s SPEED Set CAN SPEED in bps.\n"
  406. " -b BAUDRATE Set TTY/serial BAUDRATE (default: %d).\n"
  407. " -i ID Inject using ID (specified as hex string).\n"
  408. " -j DATA CAN DATA to inject (specified as hex string).\n"
  409. " -n COUNT Terminate after COUNT frames (default: infinite).\n"
  410. " -g MS Inject sleep gap in MS milliseconds (default: %d ms).\n"
  411. " -m MODE Inject payload MODE (%d = random, %d = incremental, %d = fixed).\n"
  412. "\n",
  413. CANUSB_TTY_BAUD_RATE_DEFAULT,
  414. CANUSB_INJECT_SLEEP_GAP_DEFAULT,
  415. CANUSB_INJECT_PAYLOAD_MODE_RANDOM,
  416. CANUSB_INJECT_PAYLOAD_MODE_INCREMENTAL,
  417. CANUSB_INJECT_PAYLOAD_MODE_FIXED);
  418. }
  419. static void sigterm(int signo)
  420. {
  421. program_running = 0;
  422. }
  423. int main(int argc, char *argv[])
  424. {
  425. int c, tty_fd;
  426. char *tty_device = NULL, *inject_data = NULL, *inject_id = NULL;
  427. CANUSB_SPEED speed = 0;
  428. int baudrate = CANUSB_TTY_BAUD_RATE_DEFAULT;
  429. while ((c = getopt(argc, argv, "htd:s:b:i:j:n:g:m:")) != -1) {
  430. switch (c) {
  431. case 'h':
  432. display_help(argv[0]);
  433. return EXIT_SUCCESS;
  434. case 't':
  435. print_traffic++;
  436. break;
  437. case 'd':
  438. tty_device = optarg;
  439. break;
  440. case 's':
  441. speed = canusb_int_to_speed(atoi(optarg));
  442. break;
  443. case 'b':
  444. baudrate = atoi(optarg);
  445. break;
  446. case 'i':
  447. inject_id = optarg;
  448. break;
  449. case 'j':
  450. inject_data = optarg;
  451. break;
  452. case 'n':
  453. terminate_after = atoi(optarg);
  454. break;
  455. case 'g':
  456. inject_sleep_gap = strtof(optarg, NULL);
  457. break;
  458. case 'm':
  459. inject_payload_mode = atoi(optarg);
  460. break;
  461. case '?':
  462. default:
  463. display_help(argv[0]);
  464. return EXIT_FAILURE;
  465. }
  466. }
  467. signal(SIGTERM, sigterm);
  468. signal(SIGHUP, sigterm);
  469. signal(SIGINT, sigterm);
  470. if (tty_device == NULL) {
  471. fprintf(stderr, "Please specify a TTY!\n");
  472. display_help(argv[0]);
  473. return EXIT_FAILURE;
  474. }
  475. if (speed == 0) {
  476. fprintf(stderr, "Please specify a valid speed!\n");
  477. display_help(argv[0]);
  478. return EXIT_FAILURE;
  479. }
  480. tty_fd = adapter_init(tty_device, baudrate);
  481. if (tty_fd == -1) {
  482. return EXIT_FAILURE;
  483. }
  484. command_settings(tty_fd, speed, CANUSB_MODE_NORMAL, CANUSB_FRAME_STANDARD);
  485. if (inject_data == NULL) {
  486. /* Dumping mode (default). */
  487. dump_data_frames(tty_fd);
  488. } else {
  489. /* Inject mode. */
  490. if (inject_id == NULL) {
  491. fprintf(stderr, "Please specify a ID for injection!\n");
  492. display_help(argv[0]);
  493. return EXIT_FAILURE;
  494. }
  495. if (inject_data_frame(tty_fd, inject_id, inject_data) == -1) {
  496. return EXIT_FAILURE;
  497. } else {
  498. return EXIT_SUCCESS;
  499. }
  500. }
  501. return EXIT_SUCCESS;
  502. }