PageRenderTime 27ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 1ms

/examples/broken/netshm/netshm.c

https://bitbucket.org/robinreal/rtnetts
C | 501 lines | 350 code | 115 blank | 36 comment | 42 complexity | 88cfcc6d8bcf1771b173da3cf606bedd MD5 | raw file
  1. /***
  2. *
  3. * netshm.c
  4. * FIXME: port over to Process Image model (see rt_cifibm driver)
  5. *
  6. * netshm - simple device providing a distributed pseudo shared memory
  7. * Copyright (C) 2004 Jan Kiszka <jan.kiszka@web.de>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. *
  23. */
  24. #include <linux/init.h>
  25. #include <linux/module.h>
  26. #include <linux/kernel.h>
  27. #include <linux/net.h>
  28. #include <linux/if_packet.h>
  29. #include <asm/uaccess.h>
  30. #include <rtdm_driver.h>
  31. #include <rtnet_sys.h>
  32. #include <rtnet.h>
  33. #include <rtmac.h>
  34. #include <netshm.h>
  35. #define NETSHM_PROTOCOL 0x2004
  36. #define DEFAULT_RECV_TASK_PRIO 10
  37. #define MODE_DROPPING 0
  38. #define MODE_DISABLED 1
  39. #define MODE_ENABLED 2
  40. #define GET_PRIV(context) (struct netshm_priv *) \
  41. &(context)-> dev_private[16 - (sizeof(struct rtdm_dev_context) & 15)]
  42. struct netshm_hdr {
  43. u16 offset;
  44. u16 length;
  45. } __attribute__((packed));
  46. struct netshm_priv {
  47. /* rtos_task_t must be aligned. We will move the private structure
  48. in rtdm_dev_context appropriately. */
  49. rtos_task_t recv_task;
  50. rtos_event_sem_t recv_sem;
  51. rtos_res_lock_t mem_lock;
  52. volatile int receiver_mode;
  53. int sock;
  54. struct rtdm_dev_context *sock_ctx;
  55. ssize_t (*sock_sendmsg)(struct rtdm_dev_context *context,
  56. int call_flags,
  57. const struct msghdr *msg,
  58. int flags);
  59. ssize_t (*sock_recvmsg)(struct rtdm_dev_context *context,
  60. int call_flags,
  61. struct msghdr *msg,
  62. int flags);
  63. int rtmac;
  64. struct rtdm_dev_context *rtmac_ctx;
  65. int (*rtmac_ioctl)(struct rtdm_dev_context *context,
  66. int call_flags, int request,
  67. void *arg);
  68. void* mem_start;
  69. size_t mem_size;
  70. size_t local_mem_offs;
  71. size_t local_mem_size;
  72. int call_flags;
  73. struct msghdr msg_out;
  74. struct iovec iov_out[2];
  75. struct netshm_hdr hdr_out;
  76. char __align; /* create room for structure alignment */
  77. };
  78. static char *shm_name = "myNETSHM";
  79. static int shm_if = 1;
  80. MODULE_PARM(shm_name, "s");
  81. MODULE_PARM(shm_if, "i");
  82. MODULE_PARM_DESC(shm_name, "name of the shared memory");
  83. MODULE_PARM_DESC(shm_if, "network interface to be used (1-n)");
  84. MODULE_LICENSE("GPL");
  85. static struct sockaddr_ll broadcast_addr = {
  86. sll_family: PF_PACKET,
  87. sll_protocol: __constant_htons(NETSHM_PROTOCOL),
  88. sll_halen: 6,
  89. sll_addr: { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
  90. };
  91. void receive_callback(struct rtdm_dev_context *context, void *arg)
  92. {
  93. struct netshm_priv *priv = (struct netshm_priv *)arg;
  94. rtos_res_lock(&priv->mem_lock);
  95. if (priv->receiver_mode != MODE_DISABLED)
  96. rtos_event_sem_signal(&priv->recv_sem);
  97. rtos_res_unlock(&priv->mem_lock);
  98. }
  99. void receiver(int arg)
  100. {
  101. struct netshm_priv *priv = (struct netshm_priv *)arg;
  102. struct netshm_hdr hdr;
  103. struct iovec iov[2];
  104. struct msghdr msg;
  105. int ret;
  106. msg.msg_name = NULL;
  107. msg.msg_namelen = 0;
  108. msg.msg_iov = iov;
  109. msg.msg_control = NULL;
  110. msg.msg_controllen = 0;
  111. RTDM_LOCK_CONTEXT(priv->sock_ctx);
  112. while (1) {
  113. if (RTOS_EVENT_ERROR(rtos_event_sem_wait(&priv->recv_sem)))
  114. goto done; /* we are shutting down */
  115. rtos_res_lock(&priv->mem_lock);
  116. /* double-check receiver_mode to avoid races */
  117. if (priv->receiver_mode != MODE_DISABLED)
  118. while (1) {
  119. msg.msg_iovlen = 1;
  120. iov[0].iov_base = &hdr;
  121. iov[0].iov_len = sizeof(struct netshm_hdr);
  122. ret = priv->sock_recvmsg(priv->sock_ctx, 0, &msg, MSG_PEEK);
  123. if (ret < 0) {
  124. if (ret != -EAGAIN)
  125. goto done; /* error */
  126. break; /* no more messages - leave inner loop */
  127. }
  128. hdr.offset = ntohs(hdr.offset);
  129. hdr.length = ntohs(hdr.length);
  130. if ((hdr.offset + hdr.length > priv->mem_size) ||
  131. (priv->receiver_mode == MODE_DROPPING)) {
  132. iov[0].iov_len = 0;
  133. if (priv->sock_recvmsg(priv->sock_ctx, priv->call_flags,
  134. &msg, 0) < 0)
  135. goto done; /* error */
  136. } else {
  137. msg.msg_iovlen = 2;
  138. /* write the header to the user buffer as well, will be
  139. * overwritten with data afterwards. */
  140. iov[0].iov_base = priv->mem_start + hdr.offset;
  141. iov[0].iov_len = sizeof(struct netshm_hdr);
  142. iov[1].iov_base = iov[0].iov_base;
  143. iov[1].iov_len = hdr.length;
  144. ret = priv->sock_recvmsg(priv->sock_ctx, priv->call_flags,
  145. &msg, 0);
  146. if (ret < 0)
  147. goto done; /* error */
  148. }
  149. }
  150. rtos_res_unlock(&priv->mem_lock);
  151. }
  152. done:
  153. rtos_res_unlock(&priv->mem_lock);
  154. RTDM_UNLOCK_CONTEXT(priv->sock_ctx);
  155. }
  156. int netshm_open(struct rtdm_dev_context *context, int call_flags, int oflags)
  157. {
  158. struct netshm_priv *priv = GET_PRIV(context);
  159. struct sockaddr_ll local_addr;
  160. struct rtdm_getcontext_args getcontext;
  161. struct rtnet_callback callback = {receive_callback, priv};
  162. int sock;
  163. int rtmac;
  164. char rtmac_name[] = "TDMA0";
  165. int ret;
  166. int nonblock = 1;
  167. sock = socket_rt(AF_PACKET, SOCK_DGRAM, htons(NETSHM_PROTOCOL));
  168. if (sock < 0)
  169. return sock;
  170. priv->sock = sock;
  171. priv->receiver_mode = MODE_DROPPING;
  172. local_addr.sll_family = PF_PACKET;
  173. local_addr.sll_protocol = htons(NETSHM_PROTOCOL);
  174. local_addr.sll_ifindex = shm_if;
  175. ret = bind_rt(sock, (struct sockaddr *)&local_addr,
  176. sizeof(struct sockaddr_ll));
  177. if (ret < 0)
  178. goto err_sock;
  179. getcontext.struct_version = RTDM_CONTEXT_STRUCT_VER;
  180. ret = ioctl_rt(sock, RTIOC_GETCONTEXT, &getcontext);
  181. if (ret < 0)
  182. goto err_sock;
  183. priv->sock_ctx = getcontext.context;
  184. priv->sock_sendmsg = getcontext.context->ops->sendmsg_rt;
  185. priv->sock_recvmsg = getcontext.context->ops->recvmsg_rt;
  186. ret = ioctl_rt(sock, RTNET_RTIOC_NONBLOCK, &nonblock);
  187. if (ret < 0)
  188. goto err_sock;
  189. ret = ioctl_rt(sock, RTNET_RTIOC_CALLBACK, &callback);
  190. if (ret < 0)
  191. goto err_sock;
  192. rtmac_name[4] = shm_if-1 + '0';
  193. rtmac = open_rt(rtmac_name, O_RDONLY);
  194. if (rtmac < 0) {
  195. ret = rtmac;
  196. goto err_rtmac1;
  197. }
  198. priv->rtmac = rtmac;
  199. getcontext.struct_version = RTDM_CONTEXT_STRUCT_VER;
  200. ret = ioctl_rt(rtmac, RTIOC_GETCONTEXT, &getcontext);
  201. if (ret < 0)
  202. goto err_rtmac2;
  203. priv->rtmac_ctx = getcontext.context;
  204. priv->rtmac_ioctl = getcontext.context->ops->ioctl_rt;
  205. ret = rtos_task_init_suspended(&priv->recv_task, receiver, (int)priv,
  206. DEFAULT_RECV_TASK_PRIO);
  207. if (ret < 0)
  208. goto err_task;
  209. rtos_event_sem_init(&priv->recv_sem);
  210. rtos_res_lock_init(&priv->mem_lock);
  211. priv->msg_out.msg_name = &broadcast_addr;
  212. priv->msg_out.msg_namelen = sizeof(broadcast_addr);
  213. priv->msg_out.msg_iov = NULL;
  214. priv->msg_out.msg_iovlen = 2;
  215. priv->msg_out.msg_control = NULL;
  216. priv->msg_out.msg_controllen = 0;
  217. return 0;
  218. err_task:
  219. err_rtmac2:
  220. close_rt(rtmac);
  221. err_rtmac1:
  222. err_sock:
  223. close_rt(sock);
  224. return ret;
  225. }
  226. int netshm_close(struct rtdm_dev_context *context, int call_flags)
  227. {
  228. struct netshm_priv *priv = GET_PRIV(context);
  229. int ret;
  230. rtos_event_sem_delete(&priv->recv_sem);
  231. rtos_res_lock_delete(&priv->mem_lock);
  232. if (atomic_read(&context->close_lock_count) > 1)
  233. return -EAGAIN;
  234. if (priv->sock >= 0) {
  235. ret = close_rt(priv->sock);
  236. if (ret < 0)
  237. return ret;
  238. priv->sock = -1;
  239. }
  240. if (priv->rtmac >= 0) {
  241. ret = close_rt(priv->rtmac);
  242. if (ret < 0)
  243. return ret;
  244. priv->rtmac = -1;
  245. }
  246. rtos_task_delete(&priv->recv_task);
  247. return 0;
  248. }
  249. int netshm_ioctl_nrt(struct rtdm_dev_context *context, int call_flags,
  250. int request, void *arg)
  251. {
  252. struct netshm_priv *priv = GET_PRIV(context);
  253. struct netshm_attach_args args;
  254. struct netshm_attach_args *args_ptr;
  255. int ret;
  256. switch (request) {
  257. case NETSHM_RTIOC_ATTACH:
  258. if (priv->msg_out.msg_iov) {
  259. ret = -EBUSY;
  260. break;
  261. }
  262. args_ptr = arg;
  263. if (call_flags & RTDM_USER_MODE_CALL) {
  264. ret = copy_from_user(&args, arg,
  265. sizeof(struct netshm_attach_args));
  266. if (ret < 0)
  267. break;
  268. args_ptr = &args;
  269. }
  270. if (args_ptr->mem_size < args_ptr->local_mem_offs +
  271. args_ptr->local_mem_size) {
  272. ret = -EINVAL;
  273. break;
  274. }
  275. priv->mem_start = args_ptr->mem_start;
  276. priv->mem_size = args_ptr->mem_size;
  277. priv->local_mem_offs = args_ptr->local_mem_offs;
  278. priv->local_mem_size = args_ptr->local_mem_size;
  279. priv->hdr_out.offset = htons(priv->local_mem_offs);
  280. priv->hdr_out.length = htons(priv->local_mem_size);
  281. priv->call_flags = call_flags & RTDM_USER_MODE_CALL;
  282. priv->msg_out.msg_iov = priv->iov_out;
  283. if (args_ptr->recv_task_prio >= 0)
  284. rtos_task_set_priority(&priv->recv_task,
  285. args_ptr->recv_task_prio);
  286. rtos_task_resume(&priv->recv_task);
  287. if (args_ptr->xmit_params >= 0)
  288. ioctl_rt(priv->sock, RTNET_RTIOC_XMITPARAMS,
  289. &args_ptr->xmit_params);
  290. ret = 0;
  291. break;
  292. default:
  293. ret = -ENOTTY;
  294. break;
  295. }
  296. return ret;
  297. }
  298. int netshm_ioctl_rt(struct rtdm_dev_context *context, int call_flags,
  299. int request, void *arg)
  300. {
  301. struct netshm_priv *priv = GET_PRIV(context);
  302. int ret;
  303. switch (request) {
  304. case NETSHM_RTIOC_CYCLE:
  305. if (!priv->msg_out.msg_iov)
  306. return -EACCES;
  307. if (priv->local_mem_size > 0) {
  308. priv->iov_out[0].iov_base = &priv->hdr_out;
  309. priv->iov_out[0].iov_len = sizeof(struct netshm_hdr);
  310. priv->iov_out[1].iov_base = priv->mem_start +
  311. priv->local_mem_offs;
  312. priv->iov_out[1].iov_len = priv->local_mem_size;
  313. RTDM_LOCK_CONTEXT(priv->sock_ctx);
  314. ret = priv->sock_sendmsg(priv->sock_ctx, call_flags,
  315. &priv->msg_out, 0);
  316. RTDM_UNLOCK_CONTEXT(priv->sock_ctx);
  317. if (ret < 0)
  318. return ret;
  319. }
  320. /* wait on completion of processing cycle (first cycle) */
  321. RTDM_LOCK_CONTEXT(priv->rtmac_ctx);
  322. ret = priv->rtmac_ioctl(priv->rtmac_ctx, call_flags,
  323. RTMAC_RTIOC_WAITONCYCLE,
  324. RTMAC_WAIT_ON_DEFAULT);
  325. if (ret < 0) {
  326. RTDM_UNLOCK_CONTEXT(priv->rtmac_ctx);
  327. return ret;
  328. }
  329. /* now accept update packets */
  330. priv->receiver_mode = MODE_ENABLED;
  331. /* explicitely wake up receiver to process pending messages */
  332. rtos_event_sem_signal(&priv->recv_sem);
  333. /* wait on completion of communication cycle (second cycle) */
  334. ret = priv->rtmac_ioctl(priv->rtmac_ctx, call_flags,
  335. RTMAC_RTIOC_WAITONCYCLE,
  336. RTMAC_WAIT_ON_DEFAULT);
  337. RTDM_UNLOCK_CONTEXT(priv->rtmac_ctx);
  338. rtos_res_lock(&priv->mem_lock);
  339. priv->receiver_mode = MODE_DISABLED;
  340. rtos_res_unlock(&priv->mem_lock);
  341. break;
  342. default:
  343. ret = netshm_ioctl_nrt(context, call_flags, request, arg);
  344. break;
  345. }
  346. return ret;
  347. }
  348. static struct rtdm_device netshm_dev = {
  349. struct_version: RTDM_DEVICE_STRUCT_VER,
  350. /* RTDM_EXCLUSIVE: only one user at the same time */
  351. device_flags: RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
  352. context_size: sizeof(struct netshm_priv),
  353. open_nrt: netshm_open,
  354. ops: {
  355. close_nrt: netshm_close,
  356. /* Note: Instead of using two different entry functions for ioctl,
  357. we could also check the caller's context (=> context_flags). But
  358. this is a demo... */
  359. ioctl_rt: netshm_ioctl_rt,
  360. ioctl_nrt: netshm_ioctl_nrt,
  361. },
  362. device_class: RTDM_CLASS_EXPERIMENTAL,
  363. device_sub_class: 100,
  364. driver_name: "netshm",
  365. peripheral_name: "Simple shared memory over RTnet",
  366. provider_name: "(C) 2004 RTnet Development Team, "
  367. "http://rtnet.sf.net",
  368. proc_name: netshm_dev.device_name
  369. };
  370. int __init init_module(void)
  371. {
  372. printk("netshm: loading\n");
  373. broadcast_addr.sll_ifindex = shm_if;
  374. strncpy(netshm_dev.device_name, shm_name, RTDM_MAX_DEVNAME_LEN);
  375. netshm_dev.device_name[RTDM_MAX_DEVNAME_LEN] = 0;
  376. return rtdm_dev_register(&netshm_dev);
  377. }
  378. void cleanup_module(void)
  379. {
  380. printk("netshm: unloading\n");
  381. while (rtdm_dev_unregister(&netshm_dev) == -EAGAIN) {
  382. printk("netshm: waiting for remaining open devices\n");
  383. set_current_state(TASK_UNINTERRUPTIBLE);
  384. schedule_timeout(1*HZ); /* sleep 1 second */
  385. }
  386. }