netlink_conn.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /****************************************************************************
  2. * net/netlink/netlink_conn.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <stdint.h>
  25. #include <string.h>
  26. #include <queue.h>
  27. #include <assert.h>
  28. #include <errno.h>
  29. #include <debug.h>
  30. #include <arch/irq.h>
  31. #include <nuttx/kmalloc.h>
  32. #include <nuttx/semaphore.h>
  33. #include <nuttx/net/netconfig.h>
  34. #include <nuttx/net/net.h>
  35. #include <nuttx/net/netlink.h>
  36. #include "utils/utils.h"
  37. #include "netlink/netlink.h"
  38. #ifdef CONFIG_NET_NETLINK
  39. /****************************************************************************
  40. * Private Data
  41. ****************************************************************************/
  42. /* The array containing all NetLink connections. */
  43. static struct netlink_conn_s g_netlink_connections[CONFIG_NETLINK_CONNS];
  44. /* A list of all free NetLink connections */
  45. static dq_queue_t g_free_netlink_connections;
  46. static sem_t g_free_sem;
  47. /* A list of all allocated NetLink connections */
  48. static dq_queue_t g_active_netlink_connections;
  49. /****************************************************************************
  50. * Private Functions
  51. ****************************************************************************/
  52. /****************************************************************************
  53. * Name: _netlink_semtake() and _netlink_semgive()
  54. *
  55. * Description:
  56. * Take/give semaphore
  57. *
  58. ****************************************************************************/
  59. static void _netlink_semtake(FAR sem_t *sem)
  60. {
  61. net_lockedwait_uninterruptible(sem);
  62. }
  63. static void _netlink_semgive(FAR sem_t *sem)
  64. {
  65. nxsem_post(sem);
  66. }
  67. /****************************************************************************
  68. * Name: netlink_response_available
  69. *
  70. * Description:
  71. * Handle a Netlink response available notification.
  72. *
  73. * Input Parameters:
  74. * Standard work handler parameters
  75. *
  76. * Returned Value:
  77. * None
  78. *
  79. ****************************************************************************/
  80. static void netlink_response_available(FAR void *arg)
  81. {
  82. DEBUGASSERT(arg != NULL);
  83. /* wakeup the waiter */
  84. _netlink_semgive(arg);
  85. }
  86. /****************************************************************************
  87. * Public Functions
  88. ****************************************************************************/
  89. /****************************************************************************
  90. * Name: netlink_initialize()
  91. *
  92. * Description:
  93. * Initialize the NetLink connection structures. Called once and only
  94. * from the networking layer.
  95. *
  96. ****************************************************************************/
  97. void netlink_initialize(void)
  98. {
  99. int i;
  100. /* Initialize the queues */
  101. dq_init(&g_free_netlink_connections);
  102. dq_init(&g_active_netlink_connections);
  103. nxsem_init(&g_free_sem, 0, 1);
  104. for (i = 0; i < CONFIG_NETLINK_CONNS; i++)
  105. {
  106. FAR struct netlink_conn_s *conn = &g_netlink_connections[i];
  107. /* Mark the connection closed and move it to the free list */
  108. memset(conn, 0, sizeof(*conn));
  109. dq_addlast(&conn->node, &g_free_netlink_connections);
  110. }
  111. }
  112. /****************************************************************************
  113. * Name: netlink_alloc()
  114. *
  115. * Description:
  116. * Allocate a new, uninitialized NetLink connection structure. This is
  117. * normally something done by the implementation of the socket() API
  118. *
  119. ****************************************************************************/
  120. FAR struct netlink_conn_s *netlink_alloc(void)
  121. {
  122. FAR struct netlink_conn_s *conn;
  123. /* The free list is protected by a semaphore (that behaves like a mutex). */
  124. _netlink_semtake(&g_free_sem);
  125. conn = (FAR struct netlink_conn_s *)
  126. dq_remfirst(&g_free_netlink_connections);
  127. if (conn != NULL)
  128. {
  129. /* Make sure that the connection is marked as uninitialized */
  130. memset(conn, 0, sizeof(*conn));
  131. /* Enqueue the connection into the active list */
  132. dq_addlast(&conn->node, &g_active_netlink_connections);
  133. }
  134. _netlink_semgive(&g_free_sem);
  135. return conn;
  136. }
  137. /****************************************************************************
  138. * Name: netlink_free()
  139. *
  140. * Description:
  141. * Free a NetLink connection structure that is no longer in use. This
  142. * should be done by the implementation of close().
  143. *
  144. ****************************************************************************/
  145. void netlink_free(FAR struct netlink_conn_s *conn)
  146. {
  147. FAR sq_entry_t *resp;
  148. /* The free list is protected by a semaphore (that behaves like a mutex). */
  149. DEBUGASSERT(conn->crefs == 0);
  150. _netlink_semtake(&g_free_sem);
  151. /* Remove the connection from the active list */
  152. dq_rem(&conn->node, &g_active_netlink_connections);
  153. /* Free any unclaimed responses */
  154. while ((resp = sq_remfirst(&conn->resplist)) != NULL)
  155. {
  156. kmm_free(resp);
  157. }
  158. /* Reset structure */
  159. memset(conn, 0, sizeof(*conn));
  160. /* Free the connection */
  161. dq_addlast(&conn->node, &g_free_netlink_connections);
  162. _netlink_semgive(&g_free_sem);
  163. }
  164. /****************************************************************************
  165. * Name: netlink_nextconn()
  166. *
  167. * Description:
  168. * Traverse the list of allocated NetLink connections
  169. *
  170. * Assumptions:
  171. * This function is called from NetLink device logic.
  172. *
  173. ****************************************************************************/
  174. FAR struct netlink_conn_s *netlink_nextconn(FAR struct netlink_conn_s *conn)
  175. {
  176. if (conn == NULL)
  177. {
  178. return (FAR struct netlink_conn_s *)g_active_netlink_connections.head;
  179. }
  180. else
  181. {
  182. return (FAR struct netlink_conn_s *)conn->node.flink;
  183. }
  184. }
  185. /****************************************************************************
  186. * Name: netlink_add_response
  187. *
  188. * Description:
  189. * Add response data at the tail of the pending response list.
  190. *
  191. * Note: The network will be momentarily locked to support exclusive
  192. * access to the pending response list.
  193. *
  194. * Input Parameters:
  195. * handle - The handle previously provided to the sendto() implementation
  196. * for the protocol. This is an opaque reference to the Netlink
  197. * socket state structure.
  198. * resp - The response to the request. The memory referenced by 'resp'
  199. * must have been allocated via kmm_malloc(). It will be freed
  200. * using kmm_free() after it has been consumed.
  201. *
  202. ****************************************************************************/
  203. void netlink_add_response(NETLINK_HANDLE handle,
  204. FAR struct netlink_response_s *resp)
  205. {
  206. FAR struct netlink_conn_s *conn;
  207. conn = handle;
  208. DEBUGASSERT(conn != NULL && resp != NULL);
  209. /* Add the response to the end of the FIFO list */
  210. net_lock();
  211. sq_addlast(&resp->flink, &conn->resplist);
  212. /* Notify any waiters that a response is available */
  213. netlink_notifier_signal(conn);
  214. net_unlock();
  215. }
  216. /****************************************************************************
  217. * Name: netlink_add_broadcast
  218. *
  219. * Description:
  220. * Add broadcast data to all interested netlink connections.
  221. *
  222. * Note: The network will be momentarily locked to support exclusive
  223. * access to the pending response list.
  224. *
  225. * Input Parameters:
  226. * group - The broadcast group index.
  227. * data - The broadcast data. The memory referenced by 'data'
  228. * must have been allocated via kmm_malloc(). It will be freed
  229. * using kmm_free() after it has been consumed.
  230. *
  231. ****************************************************************************/
  232. void netlink_add_broadcast(int group, FAR struct netlink_response_s *data)
  233. {
  234. FAR struct netlink_conn_s *conn = NULL;
  235. int first = 1;
  236. DEBUGASSERT(data != NULL);
  237. net_lock();
  238. while ((conn = netlink_nextconn(conn)) != NULL)
  239. {
  240. if ((conn->groups & (1 << (group - 1))) == 0)
  241. {
  242. continue;
  243. }
  244. /* Duplicate the package except the first loop */
  245. if (!first)
  246. {
  247. FAR struct netlink_response_s *tmp;
  248. size_t len;
  249. len = sizeof(sq_entry_t) + data->msg.nlmsg_len;
  250. tmp = kmm_malloc(len);
  251. if (tmp == NULL)
  252. {
  253. break;
  254. }
  255. memcpy(tmp, data, len);
  256. data = tmp;
  257. }
  258. first = 0;
  259. /* Add the response to the end of the FIFO list */
  260. sq_addlast(&data->flink, &conn->resplist);
  261. /* Notify any waiters that a response is available */
  262. netlink_notifier_signal(conn);
  263. }
  264. net_unlock();
  265. /* Drop the package if nobody is interested in */
  266. if (first)
  267. {
  268. kmm_free(data);
  269. }
  270. }
  271. /****************************************************************************
  272. * Name: netlink_tryget_response
  273. *
  274. * Description:
  275. * Return the next response from the head of the pending response list.
  276. * Responses are returned one-at-a-time in FIFO order.
  277. *
  278. * Note: The network will be momentarily locked to support exclusive
  279. * access to the pending response list.
  280. *
  281. * Returned Value:
  282. * The next response from the head of the pending response list is
  283. * returned. NULL will be returned if the pending response list is
  284. * empty
  285. *
  286. ****************************************************************************/
  287. FAR struct netlink_response_s *
  288. netlink_tryget_response(FAR struct netlink_conn_s *conn)
  289. {
  290. FAR struct netlink_response_s *resp;
  291. DEBUGASSERT(conn != NULL);
  292. /* Return the response at the head of the pending response list (may be
  293. * NULL).
  294. */
  295. net_lock();
  296. resp = (FAR struct netlink_response_s *)sq_remfirst(&conn->resplist);
  297. net_unlock();
  298. return resp;
  299. }
  300. /****************************************************************************
  301. * Name: netlink_get_response
  302. *
  303. * Description:
  304. * Return the next response from the head of the pending response list.
  305. * Responses are returned one-at-a-time in FIFO order.
  306. *
  307. * Note: The network will be momentarily locked to support exclusive
  308. * access to the pending response list.
  309. *
  310. * Returned Value:
  311. * The next response from the head of the pending response list is
  312. * returned. This function will block until a response is received if
  313. * the pending response list is empty. NULL will be returned only in the
  314. * event of a failure.
  315. *
  316. ****************************************************************************/
  317. FAR struct netlink_response_s *
  318. netlink_get_response(FAR struct netlink_conn_s *conn)
  319. {
  320. FAR struct netlink_response_s *resp;
  321. int ret;
  322. DEBUGASSERT(conn != NULL);
  323. /* Loop, until a response is received. A loop is used because in the case
  324. * of multiple waiters, all waiters will be awakened, but only the highest
  325. * priority waiter will get the response.
  326. */
  327. net_lock();
  328. while ((resp = netlink_tryget_response(conn)) == NULL)
  329. {
  330. sem_t waitsem;
  331. /* Set up a semaphore to notify us when a response is queued. */
  332. nxsem_init(&waitsem, 0, 0);
  333. nxsem_set_protocol(&waitsem, SEM_PRIO_NONE);
  334. /* Set up a notifier to post the semaphore when a response is
  335. * received.
  336. */
  337. ret = netlink_notifier_setup(netlink_response_available, conn,
  338. &waitsem);
  339. if (ret < 0)
  340. {
  341. nerr("ERROR: netlink_notifier_setup() failed: %d\n", ret);
  342. }
  343. else
  344. {
  345. /* Wait for a response to be queued */
  346. _netlink_semtake(&waitsem);
  347. }
  348. /* Clean-up the semaphore */
  349. nxsem_destroy(&waitsem);
  350. netlink_notifier_teardown(conn);
  351. /* Check for any failures */
  352. if (ret < 0)
  353. {
  354. break;
  355. }
  356. }
  357. net_unlock();
  358. return resp;
  359. }
  360. /****************************************************************************
  361. * Name: netlink_check_response
  362. *
  363. * Description:
  364. * Return true is a response is pending now.
  365. *
  366. * Returned Value:
  367. * True: A response is available; False; No response is available.
  368. *
  369. ****************************************************************************/
  370. bool netlink_check_response(FAR struct netlink_conn_s *conn)
  371. {
  372. DEBUGASSERT(conn != NULL);
  373. /* Check if the response is available. It is not necessary to lock the
  374. * network because the sq_peek() is an atomic operation.
  375. */
  376. return (sq_peek(&conn->resplist) != NULL);
  377. }
  378. #endif /* CONFIG_NET_NETLINK */