bcmserver.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * tst-bcm-server.c
  3. *
  4. * Test programm that implements a socket server which understands ASCII
  5. * messages for simple broadcast manager frame send commands.
  6. *
  7. * < interface command ival_s ival_us can_id can_dlc [data]* >
  8. *
  9. * Only the items 'can_id' and 'data' are given in (ASCII) hexadecimal values.
  10. *
  11. * ## TX path:
  12. *
  13. * The commands are 'A'dd, 'U'pdate, 'D'elete and 'S'end.
  14. * e.g.
  15. *
  16. * Send the CAN frame 123#1122334455667788 every second on vcan1
  17. * < vcan1 A 1 0 123 8 11 22 33 44 55 66 77 88 >
  18. *
  19. * Send the CAN frame 123#1122334455667788 every 10 usecs on vcan1
  20. * < vcan1 A 0 10 123 8 11 22 33 44 55 66 77 88 >
  21. *
  22. * Send the CAN frame 123#42424242 every 20 msecs on vcan1
  23. * < vcan1 A 0 20000 123 4 42 42 42 42 >
  24. *
  25. * Update the CAN frame 123#42424242 with 123#112233 - no change of timers
  26. * < vcan1 U 0 0 123 3 11 22 33 >
  27. *
  28. * Delete the cyclic send job from above
  29. * < vcan1 D 0 0 123 0 >
  30. *
  31. * Send a single CAN frame without cyclic transmission
  32. * < can0 S 0 0 123 0 >
  33. *
  34. * When the socket is closed the cyclic transmissions are terminated.
  35. *
  36. * ## RX path:
  37. *
  38. * The commands are 'R'eceive setup, 'F'ilter ID Setup and 'X' for delete.
  39. * e.g.
  40. *
  41. * Receive CAN ID 0x123 from vcan1 and check for changes in the first byte
  42. * < vcan1 R 0 0 123 1 FF >
  43. *
  44. * Receive CAN ID 0x123 from vcan1 and check for changes in given mask
  45. * < vcan1 R 0 0 123 8 FF 00 F8 00 00 00 00 00 >
  46. *
  47. * As above but throttle receive update rate down to 1.5 seconds
  48. * < vcan1 R 1 500000 123 8 FF 00 F8 00 00 00 00 00 >
  49. *
  50. * Filter for CAN ID 0x123 from vcan1 without content filtering
  51. * < vcan1 F 0 0 123 0 >
  52. *
  53. * Delete receive filter ('R' or 'F') for CAN ID 0x123
  54. * < vcan1 X 0 0 123 0 >
  55. *
  56. * CAN messages received by the given filters are send in the format:
  57. * < interface can_id can_dlc [data]* >
  58. *
  59. * e.g. when receiving a CAN message from vcan1 with
  60. * can_id 0x123 , data length 4 and data 0x11, 0x22, 0x33 and 0x44
  61. *
  62. * < vcan1 123 4 11 22 33 44 >
  63. *
  64. * ##
  65. *
  66. * Authors:
  67. * Andre Naujoks (the socket server stuff)
  68. * Oliver Hartkopp (the rest)
  69. *
  70. * Copyright (c) 2002-2009 Volkswagen Group Electronic Research
  71. * All rights reserved.
  72. *
  73. * Redistribution and use in source and binary forms, with or without
  74. * modification, are permitted provided that the following conditions
  75. * are met:
  76. * 1. Redistributions of source code must retain the above copyright
  77. * notice, this list of conditions and the following disclaimer.
  78. * 2. Redistributions in binary form must reproduce the above copyright
  79. * notice, this list of conditions and the following disclaimer in the
  80. * documentation and/or other materials provided with the distribution.
  81. * 3. Neither the name of Volkswagen nor the names of its contributors
  82. * may be used to endorse or promote products derived from this software
  83. * without specific prior written permission.
  84. *
  85. * Alternatively, provided that this notice is retained in full, this
  86. * software may be distributed under the terms of the GNU General
  87. * Public License ("GPL") version 2, in which case the provisions of the
  88. * GPL apply INSTEAD OF those given above.
  89. *
  90. * The provided data structures and external interfaces from this code
  91. * are not restricted to be used by modules with a GPL compatible license.
  92. *
  93. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  94. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  95. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  96. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  97. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  98. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  99. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  100. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  101. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  102. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  103. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  104. * DAMAGE.
  105. *
  106. * Send feedback to <linux-can@vger.kernel.org>
  107. *
  108. */
  109. #include <stdio.h>
  110. #include <stdlib.h>
  111. #include <unistd.h>
  112. #include <string.h>
  113. #include <signal.h>
  114. #include <errno.h>
  115. #include <sys/types.h>
  116. #include <sys/wait.h>
  117. #include <sys/socket.h>
  118. #include <sys/ioctl.h>
  119. #include <sys/uio.h>
  120. #include <net/if.h>
  121. #include <netinet/in.h>
  122. #include <linux/can.h>
  123. #include <linux/can/bcm.h>
  124. #define MAXLEN 100
  125. #define FORMATSZ 80
  126. #define PORT 28600
  127. void childdied(int i)
  128. {
  129. wait(NULL);
  130. }
  131. int main(int argc, char **argv)
  132. {
  133. int sl, sa, sc;
  134. int i;
  135. int idx = 0;
  136. struct sockaddr_in saddr, clientaddr;
  137. struct sockaddr_can caddr;
  138. socklen_t caddrlen = sizeof(caddr);
  139. struct ifreq ifr;
  140. fd_set readfds;
  141. socklen_t sin_size = sizeof(clientaddr);
  142. struct sigaction signalaction;
  143. sigset_t sigset;
  144. char buf[MAXLEN];
  145. char format[FORMATSZ];
  146. char rxmsg[50];
  147. struct {
  148. struct bcm_msg_head msg_head;
  149. struct can_frame frame;
  150. } msg;
  151. if (snprintf(format, FORMATSZ, "< %%%ds %%c %%lu %%lu %%x %%hhu "
  152. "%%hhx %%hhx %%hhx %%hhx %%hhx %%hhx "
  153. "%%hhx %%hhx >", IFNAMSIZ-1) >= FORMATSZ-1)
  154. exit(1);
  155. sigemptyset(&sigset);
  156. signalaction.sa_handler = &childdied;
  157. signalaction.sa_mask = sigset;
  158. signalaction.sa_flags = 0;
  159. sigaction(SIGCHLD, &signalaction, NULL); /* signal for dying child */
  160. if((sl = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  161. perror("inetsocket");
  162. exit(1);
  163. }
  164. saddr.sin_family = AF_INET;
  165. saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  166. saddr.sin_port = htons(PORT);
  167. while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
  168. printf(".");fflush(NULL);
  169. usleep(100000);
  170. }
  171. if (listen(sl,3) != 0) {
  172. perror("listen");
  173. exit(1);
  174. }
  175. while (1) {
  176. sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
  177. if (sa > 0 ){
  178. if (fork())
  179. close(sa);
  180. else
  181. break;
  182. }
  183. else {
  184. if (errno != EINTR) {
  185. /*
  186. * If the cause for the error was NOT the
  187. * signal from a dying child => give an error
  188. */
  189. perror("accept");
  190. exit(1);
  191. }
  192. }
  193. }
  194. /* open BCM socket */
  195. if ((sc = socket(PF_CAN, SOCK_DGRAM, CAN_BCM)) < 0) {
  196. perror("bcmsocket");
  197. return 1;
  198. }
  199. memset(&caddr, 0, sizeof(caddr));
  200. caddr.can_family = PF_CAN;
  201. /* can_ifindex is set to 0 (any device) => need for sendto() */
  202. if (connect(sc, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) {
  203. perror("connect");
  204. return 1;
  205. }
  206. while (1) {
  207. FD_ZERO(&readfds);
  208. FD_SET(sc, &readfds);
  209. FD_SET(sa, &readfds);
  210. select((sc > sa)?sc+1:sa+1, &readfds, NULL, NULL, NULL);
  211. if (FD_ISSET(sc, &readfds)) {
  212. recvfrom(sc, &msg, sizeof(msg), 0,
  213. (struct sockaddr*)&caddr, &caddrlen);
  214. ifr.ifr_ifindex = caddr.can_ifindex;
  215. ioctl(sc, SIOCGIFNAME, &ifr);
  216. sprintf(rxmsg, "< %s %03X %d ", ifr.ifr_name,
  217. msg.msg_head.can_id, msg.frame.can_dlc);
  218. for ( i = 0; i < msg.frame.can_dlc; i++)
  219. sprintf(rxmsg + strlen(rxmsg), "%02X ",
  220. msg.frame.data[i]);
  221. /* delimiter '\0' for Adobe(TM) Flash(TM) XML sockets */
  222. strcat(rxmsg, ">\0");
  223. send(sa, rxmsg, strlen(rxmsg) + 1, 0);
  224. }
  225. if (FD_ISSET(sa, &readfds)) {
  226. char cmd;
  227. int items;
  228. if (read(sa, buf+idx, 1) < 1)
  229. exit(1);
  230. if (!idx) {
  231. if (buf[0] == '<')
  232. idx = 1;
  233. continue;
  234. }
  235. if (idx > MAXLEN-2) {
  236. idx = 0;
  237. continue;
  238. }
  239. if (buf[idx] != '>') {
  240. idx++;
  241. continue;
  242. }
  243. buf[idx+1] = 0;
  244. idx = 0;
  245. //printf("read '%s'\n", buf);
  246. /* prepare bcm message settings */
  247. memset(&msg, 0, sizeof(msg));
  248. msg.msg_head.nframes = 1;
  249. items = sscanf(buf, format,
  250. ifr.ifr_name,
  251. &cmd,
  252. &msg.msg_head.ival2.tv_sec,
  253. &msg.msg_head.ival2.tv_usec,
  254. &msg.msg_head.can_id,
  255. &msg.frame.can_dlc,
  256. &msg.frame.data[0],
  257. &msg.frame.data[1],
  258. &msg.frame.data[2],
  259. &msg.frame.data[3],
  260. &msg.frame.data[4],
  261. &msg.frame.data[5],
  262. &msg.frame.data[6],
  263. &msg.frame.data[7]);
  264. if (items < 6)
  265. break;
  266. if (msg.frame.can_dlc > 8)
  267. break;
  268. if (items != 6 + msg.frame.can_dlc)
  269. break;
  270. msg.frame.can_id = msg.msg_head.can_id;
  271. switch (cmd) {
  272. case 'S':
  273. msg.msg_head.opcode = TX_SEND;
  274. break;
  275. case 'A':
  276. msg.msg_head.opcode = TX_SETUP;
  277. msg.msg_head.flags |= SETTIMER | STARTTIMER;
  278. break;
  279. case 'U':
  280. msg.msg_head.opcode = TX_SETUP;
  281. msg.msg_head.flags = 0;
  282. break;
  283. case 'D':
  284. msg.msg_head.opcode = TX_DELETE;
  285. break;
  286. case 'R':
  287. msg.msg_head.opcode = RX_SETUP;
  288. msg.msg_head.flags = SETTIMER;
  289. break;
  290. case 'F':
  291. msg.msg_head.opcode = RX_SETUP;
  292. msg.msg_head.flags = RX_FILTER_ID | SETTIMER;
  293. break;
  294. case 'X':
  295. msg.msg_head.opcode = RX_DELETE;
  296. break;
  297. default:
  298. printf("unknown command '%c'.\n", cmd);
  299. exit(1);
  300. }
  301. if (!ioctl(sc, SIOCGIFINDEX, &ifr)) {
  302. caddr.can_ifindex = ifr.ifr_ifindex;
  303. sendto(sc, &msg, sizeof(msg), 0,
  304. (struct sockaddr*)&caddr, sizeof(caddr));
  305. }
  306. }
  307. }
  308. close(sc);
  309. close(sa);
  310. return 0;
  311. }