devif_callback.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /****************************************************************************
  2. * net/devif/devif_callback.c
  3. *
  4. * Copyright (C) 2008-2009, 2015 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #if defined(CONFIG_NET)
  40. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include <string.h>
  43. #include <debug.h>
  44. #include <assert.h>
  45. #include <nuttx/net/netconfig.h>
  46. #include <nuttx/net/net.h>
  47. #include <nuttx/net/netdev.h>
  48. #include "netdev/netdev.h"
  49. #include "devif/devif.h"
  50. /****************************************************************************
  51. * Private Data
  52. ****************************************************************************/
  53. static struct devif_callback_s g_cbprealloc[CONFIG_NET_NACTIVESOCKETS];
  54. static FAR struct devif_callback_s *g_cbfreelist = NULL;
  55. /****************************************************************************
  56. * Private Functions
  57. ****************************************************************************/
  58. /****************************************************************************
  59. * Name: devif_callback_free
  60. *
  61. * Description:
  62. * Return a callback container to the free list.
  63. *
  64. * Assumptions:
  65. * This function is called with the network locked.
  66. *
  67. ****************************************************************************/
  68. static void devif_callback_free(FAR struct net_driver_s *dev,
  69. FAR struct devif_callback_s *cb,
  70. FAR struct devif_callback_s **list)
  71. {
  72. FAR struct devif_callback_s *prev;
  73. FAR struct devif_callback_s *curr;
  74. if (cb)
  75. {
  76. net_lock();
  77. #ifdef CONFIG_DEBUG_FEATURES
  78. /* Check for double freed callbacks */
  79. curr = g_cbfreelist;
  80. while (curr != NULL)
  81. {
  82. DEBUGASSERT(cb != curr);
  83. curr = curr->nxtconn;
  84. }
  85. #endif
  86. /* Remove the callback structure from the device notification list if
  87. * it is supposed to be in the device notification list.
  88. */
  89. if (dev != NULL)
  90. {
  91. /* Find the callback structure in the device event list */
  92. for (prev = NULL, curr = dev->d_devcb;
  93. curr != NULL && curr != cb;
  94. prev = curr, curr = curr->nxtdev);
  95. /* Remove the structure from the device event list */
  96. DEBUGASSERT(curr);
  97. if (curr != NULL)
  98. {
  99. if (prev)
  100. {
  101. prev->nxtdev = cb->nxtdev;
  102. }
  103. else
  104. {
  105. dev->d_devcb = cb->nxtdev;
  106. }
  107. }
  108. }
  109. /* Remove the callback structure from the data notification list if
  110. * it is supposed to be in the data notification list.
  111. */
  112. if (list)
  113. {
  114. /* Find the callback structure in the connection event list */
  115. for (prev = NULL, curr = *list;
  116. curr && curr != cb;
  117. prev = curr, curr = curr->nxtconn);
  118. /* Remove the structure from the connection event list */
  119. DEBUGASSERT(curr);
  120. if (curr)
  121. {
  122. if (prev)
  123. {
  124. prev->nxtconn = cb->nxtconn;
  125. }
  126. else
  127. {
  128. *list = cb->nxtconn;
  129. }
  130. }
  131. }
  132. /* Put the structure into the free list */
  133. cb->nxtconn = g_cbfreelist;
  134. cb->nxtdev = NULL;
  135. g_cbfreelist = cb;
  136. net_unlock();
  137. }
  138. }
  139. /****************************************************************************
  140. * Name: devif_event_trigger
  141. *
  142. * Description:
  143. * Return true if the current set of events should trigger a callback to
  144. * occur.
  145. *
  146. * Input Parameters:
  147. * events - The set of events that has occurred.
  148. * triggers - The set of events that will trigger a callback.
  149. *
  150. ****************************************************************************/
  151. static bool devif_event_trigger(uint16_t events, uint16_t triggers)
  152. {
  153. /* The events are divided into a set of individual bits that may be ORed
  154. * together PLUS a field that encodes a single poll event.
  155. *
  156. * First check if any of the individual event bits will trigger the
  157. * callback.
  158. */
  159. if ((events & triggers & ~DEVPOLL_MASK) != 0)
  160. {
  161. return true;
  162. }
  163. /* No... check the encoded device event. */
  164. if ((events & DEVPOLL_MASK) == (triggers & DEVPOLL_MASK))
  165. {
  166. return true;
  167. }
  168. /* No.. this event set will not generate the callback */
  169. return false;
  170. }
  171. /****************************************************************************
  172. * Public Functions
  173. ****************************************************************************/
  174. /****************************************************************************
  175. * Name: devif_callback_init
  176. *
  177. * Description:
  178. * Configure the pre-allocated callback structures into a free list.
  179. *
  180. * Assumptions:
  181. * Called early in the initialization sequence so that no special
  182. * protection is required.
  183. *
  184. ****************************************************************************/
  185. void devif_callback_init(void)
  186. {
  187. int i;
  188. for (i = 0; i < CONFIG_NET_NACTIVESOCKETS; i++)
  189. {
  190. g_cbprealloc[i].nxtconn = g_cbfreelist;
  191. g_cbfreelist = &g_cbprealloc[i];
  192. }
  193. }
  194. /****************************************************************************
  195. * Name: devif_callback_alloc
  196. *
  197. * Description:
  198. * Allocate a callback container from the free list.
  199. *
  200. * If dev is non-NULL, then this function verifies that the device
  201. * reference is still valid and that the device is still UP status. If
  202. * those conditions are not true, this function will fail to allocate the
  203. * callback.
  204. *
  205. * Assumptions:
  206. * This function is called with the network locked.
  207. *
  208. ****************************************************************************/
  209. FAR struct devif_callback_s *
  210. devif_callback_alloc(FAR struct net_driver_s *dev,
  211. FAR struct devif_callback_s **list)
  212. {
  213. FAR struct devif_callback_s *ret;
  214. /* Check the head of the free list */
  215. net_lock();
  216. ret = g_cbfreelist;
  217. if (ret)
  218. {
  219. /* Remove the next instance from the head of the free list */
  220. g_cbfreelist = ret->nxtconn;
  221. memset(ret, 0, sizeof(struct devif_callback_s));
  222. /* Add the newly allocated instance to the head of the device event
  223. * list.
  224. */
  225. if (dev)
  226. {
  227. /* Verify that the device pointer is valid, i.e., that it still
  228. * points to a registered network device and also that the network
  229. * device in in the UP state.
  230. *
  231. * And if it does, should that device also not be in the UP state?
  232. */
  233. if (!netdev_verify(dev) && (dev->d_flags & IFF_UP) != 0)
  234. {
  235. /* No.. release the callback structure and fail */
  236. devif_callback_free(NULL, NULL, list);
  237. net_unlock();
  238. return NULL;
  239. }
  240. ret->nxtdev = dev->d_devcb;
  241. dev->d_devcb = ret;
  242. }
  243. /* Add the newly allocated instance to the head of the specified list */
  244. if (list)
  245. {
  246. ret->nxtconn = *list;
  247. *list = ret;
  248. }
  249. }
  250. #ifdef CONFIG_DEBUG_FEATURES
  251. else
  252. {
  253. nerr("ERROR: Failed to allocate callback\n");
  254. }
  255. #endif
  256. net_unlock();
  257. return ret;
  258. }
  259. /****************************************************************************
  260. * Name: devif_conn_callback_free
  261. *
  262. * Description:
  263. * Return a connection/port callback container to the free list.
  264. *
  265. * This function is just a front-end for devif_callback_free(). If the
  266. * dev argument is non-NULL, it will verify that the device reference is
  267. * still valid before attempting to free the callback structure. A
  268. * non-NULL list pointer is assumed to be valid in any case.
  269. *
  270. * The callback structure will be freed in any event.
  271. *
  272. * Assumptions:
  273. * This function is called with the network locked.
  274. *
  275. ****************************************************************************/
  276. void devif_conn_callback_free(FAR struct net_driver_s *dev,
  277. FAR struct devif_callback_s *cb,
  278. FAR struct devif_callback_s **list)
  279. {
  280. /* Check if the device pointer is still valid. It could be invalid if, for
  281. * example, the device were unregistered between the time when the callback
  282. * was allocated and the time when the callback was freed.
  283. */
  284. if (dev && !netdev_verify(dev))
  285. {
  286. /* The device reference is longer valid */
  287. dev = NULL;
  288. }
  289. /* Then free the callback */
  290. devif_callback_free(dev, cb, list);
  291. }
  292. /****************************************************************************
  293. * Name: devif_dev_callback_free
  294. *
  295. * Description:
  296. * Return a device callback container to the free list.
  297. *
  298. * This function is just a front-end for devif_callback_free(). If the
  299. * de argument is non-NULL, it will verify that the device reference is
  300. * still valid before attempting to free the callback structure. It
  301. * differs from devif_conn_callback_free in that connection/port-related
  302. * connections are also associated with the device and, hence, also will
  303. * not be valid if the device pointer is not valid.
  304. *
  305. * The callback structure will be freed in any event.
  306. *
  307. * Assumptions:
  308. * This function is called with the network locked.
  309. *
  310. ****************************************************************************/
  311. void devif_dev_callback_free(FAR struct net_driver_s *dev,
  312. FAR struct devif_callback_s *cb)
  313. {
  314. FAR struct devif_callback_s **list;
  315. /* Check if the device pointer is still valid. It could be invalid if, for
  316. * example, the device were unregistered between the time when the callback
  317. * was allocated and the time when the callback was freed.
  318. */
  319. if (dev != NULL && netdev_verify(dev))
  320. {
  321. /* The device reference is valid.. the use the list pointer in the
  322. * device structure as well.
  323. */
  324. list = &dev->d_conncb;
  325. }
  326. else
  327. {
  328. /* The device reference is longer valid */
  329. dev = NULL;
  330. list = NULL;
  331. }
  332. /* Then free the callback */
  333. devif_callback_free(dev, cb, list);
  334. }
  335. /****************************************************************************
  336. * Name: devif_conn_event
  337. *
  338. * Description:
  339. * Execute a list of callbacks using the packet event chain.
  340. *
  341. * Input Parameters:
  342. * dev - The network device state structure associated with the network
  343. * device that initiated the callback event.
  344. * pvconn - Holds a reference to the TCP connection structure or the UDP
  345. * port structure. May be NULL if the even is not related to a TCP
  346. * connection or UDP port.
  347. * flags - The bit set of events to be notified.
  348. * list - The list to traverse in performing the notifications
  349. *
  350. * Returned Value:
  351. * The updated flags as modified by the callback functions.
  352. *
  353. * Assumptions:
  354. * This function is called with the network locked.
  355. *
  356. ****************************************************************************/
  357. uint16_t devif_conn_event(FAR struct net_driver_s *dev, void *pvconn,
  358. uint16_t flags, FAR struct devif_callback_s *list)
  359. {
  360. FAR struct devif_callback_s *next;
  361. /* Loop for each callback in the list and while there are still events
  362. * set in the flags set.
  363. */
  364. net_lock();
  365. while (list && flags)
  366. {
  367. /* Save the pointer to the next callback in the lists. This is done
  368. * because the callback action might delete the entry pointed to by
  369. * list.
  370. */
  371. next = list->nxtconn;
  372. /* Check if this callback handles any of the events in the flag set */
  373. if (list->event != NULL && devif_event_trigger(flags, list->flags))
  374. {
  375. /* Yes.. perform the callback. Actions perform by the callback
  376. * may delete the current list entry or add a new list entry to
  377. * beginning of the list (which will be ignored on this pass)
  378. */
  379. flags = list->event(dev, pvconn, list->priv, flags);
  380. }
  381. /* Set up for the next time through the loop */
  382. list = next;
  383. }
  384. net_unlock();
  385. return flags;
  386. }
  387. /****************************************************************************
  388. * Name: devif_dev_event
  389. *
  390. * Description:
  391. * Execute a list of callbacks using the device event chain.
  392. *
  393. * Input Parameters:
  394. * dev - The network device state structure associated with the network
  395. * device that initiated the callback event.
  396. * pvconn - Holds a reference to the TCP connection structure or the UDP
  397. * port structure. May be NULL if the even is not related to a TCP
  398. * connection or UDP port.
  399. * flags - The bit set of events to be notified.
  400. *
  401. * Returned Value:
  402. * The updated flags as modified by the callback functions.
  403. *
  404. * Assumptions:
  405. * This function is called with the network locked.
  406. *
  407. ****************************************************************************/
  408. uint16_t devif_dev_event(FAR struct net_driver_s *dev, void *pvconn,
  409. uint16_t flags)
  410. {
  411. FAR struct devif_callback_s *cb;
  412. FAR struct devif_callback_s *next;
  413. /* Loop for each callback in the list and while there are still events
  414. * set in the flags set.
  415. */
  416. net_lock();
  417. for (cb = dev->d_devcb; cb != NULL && flags != 0; cb = next)
  418. {
  419. /* Save the pointer to the next callback in the lists. This is done
  420. * because the callback action might delete the entry pointed to by
  421. * list.
  422. */
  423. next = cb->nxtdev;
  424. /* Check if this callback handles any of the events in the flag set */
  425. if (cb->event != NULL && devif_event_trigger(flags, cb->flags))
  426. {
  427. /* Yes.. perform the callback. Actions perform by the callback
  428. * may delete the current list entry or add a new list entry to
  429. * beginning of the list (which will be ignored on this pass)
  430. */
  431. flags = cb->event(dev, pvconn, cb->priv, flags);
  432. }
  433. /* Set up for the next time through the loop */
  434. cb = next;
  435. }
  436. net_unlock();
  437. return flags;
  438. }
  439. #endif /* CONFIG_NET */