summaryrefslogtreecommitdiffstats
path: root/cpukit/libnetworking/rtems/rtems_glue.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-01-15 14:13:19 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-01-20 07:11:58 +0100
commitf87ede57a2e97f0743a85b94072c7163fa485ae9 (patch)
tree827af0350535dde1db7f1ae5d80226eb3a62533d /cpukit/libnetworking/rtems/rtems_glue.c
parentlibnetworking: Delete dead code (diff)
downloadrtems-f87ede57a2e97f0743a85b94072c7163fa485ae9.tar.bz2
libnetworking: Fix close of active sockets
Send a special event to notify tasks waiting for a socket state change in case this socket gets closed. This prevents a use after free. Close #785.
Diffstat (limited to 'cpukit/libnetworking/rtems/rtems_glue.c')
-rw-r--r--cpukit/libnetworking/rtems/rtems_glue.c102
1 files changed, 51 insertions, 51 deletions
diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c
index 4c90a98a75..9d122e46a5 100644
--- a/cpukit/libnetworking/rtems/rtems_glue.c
+++ b/cpukit/libnetworking/rtems/rtems_glue.c
@@ -432,47 +432,68 @@ rtems_bsdnet_semaphore_release (void)
#endif
}
-/*
- * Wait for something to happen to a socket buffer
- */
-int
-sbwait(struct sockbuf *sb)
+static int
+rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks)
{
- rtems_event_set events;
- rtems_id tid;
rtems_status_code sc;
+ rtems_event_set out;
+ rtems_event_set out2;
+
+ in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
/*
- * Soak up any pending events.
- * The sleep/wakeup synchronization in the FreeBSD
- * kernel has no memory.
+ * Soak up any pending events. The sleep/wakeup synchronization in the
+ * FreeBSD kernel has no memory.
*/
- rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
+ rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
+ RTEMS_NO_TIMEOUT, &out);
/*
- * Set this task as the target of the wakeup operation.
+ * Wait for the wakeup event.
*/
- rtems_task_ident (RTEMS_SELF, 0, &tid);
- sb->sb_sel.si_pid = tid;
+ sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT,
+ ticks, &out);
/*
- * Show that socket is waiting
+ * Get additional events that may have been received between the
+ * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain().
*/
- sb->sb_flags |= SB_WAIT;
+ rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
+ RTEMS_NO_TIMEOUT, &out2);
+ out |= out2;
+
+ if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
+ return (ENXIO);
+
+ if (sc == RTEMS_SUCCESSFUL)
+ return (0);
+
+ return (EWOULDBLOCK);
+}
+
+/*
+ * Wait for something to happen to a socket buffer
+ */
+int
+sbwait(struct sockbuf *sb)
+{
+ int error;
/*
- * Wait for the wakeup event.
+ * Set this task as the target of the wakeup operation.
*/
- sc = rtems_bsdnet_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events);
+ sb->sb_sel.si_pid = rtems_task_self();
/*
- * Return the status of the wait.
+ * Show that socket is waiting
*/
- switch (sc) {
- case RTEMS_SUCCESSFUL: return 0;
- case RTEMS_TIMEOUT: return EWOULDBLOCK;
- default: return ENXIO;
- }
+ sb->sb_flags |= SB_WAIT;
+
+ error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo);
+ if (error != ENXIO)
+ sb->sb_flags &= ~SB_WAIT;
+
+ return (error);
}
@@ -485,7 +506,6 @@ sowakeup(
struct sockbuf *sb)
{
if (sb->sb_flags & SB_WAIT) {
- sb->sb_flags &= ~SB_WAIT;
rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
}
if (sb->sb_wakeup) {
@@ -514,40 +534,20 @@ wakeup (void *p)
int
soconnsleep (struct socket *so)
{
- rtems_event_set events;
- rtems_id tid;
- rtems_status_code sc;
-
- /*
- * Soak up any pending events.
- * The sleep/wakeup synchronization in the FreeBSD
- * kernel has no memory.
- */
- rtems_event_system_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
+ int error;
/*
* Set this task as the target of the wakeup operation.
*/
if (so->so_pgid)
rtems_panic ("Another task is already sleeping on that socket");
- rtems_task_ident (RTEMS_SELF, 0, &tid);
- so->so_pgid = tid;
-
- /*
- * Wait for the wakeup event.
- */
- sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, so->so_rcv.sb_timeo, &events);
+ so->so_pgid = rtems_task_self();
- /*
- * Relinquish ownership of the socket.
- */
- so->so_pgid = 0;
+ error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo);
+ if (error != ENXIO)
+ so->so_pgid = 0;
- switch (sc) {
- case RTEMS_SUCCESSFUL: return 0;
- case RTEMS_TIMEOUT: return EWOULDBLOCK;
- default: return ENXIO;
- }
+ return (error);
}
/*