This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Net stack serialization fix


This patch fixes the network stack problems I mentioned here:

http://sources.redhat.com/ml/ecos-discuss/2002-10/msg00734.html

This ought to be checked over for sensibility, particularly by Gary.
It probably errs on the side of caution in some places.


Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/bsd_tcpip/current/ChangeLog,v
retrieving revision 1.10
diff -u -5 -r1.10 ChangeLog
--- ChangeLog	4 Nov 2002 20:23:24 -0000	1.10
+++ ChangeLog	6 Nov 2002 19:14:50 -0000
@@ -1,5 +1,13 @@
+2002-11-06  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/sys/kern/sockio.c: Added calls to splsoftnet() and
+	splx() to various functions. These are intended to avoid race
+	conditions between threads that are making simultaneous calls on
+	the same socket. This should duplicate the conditions that the
+	code expects in the BSD kernel.
+
 2002-11-04  Gary Thomas  <gthomas@ecoscentric.com>
 
 	* src/sys/net/if.c (if_attach): Moved check for ifq_maxlen to
 	this function since it can't be checked until the device comes
 	online, which may not be a sysinit time for PCMCIA devices.
Index: src/sys/kern/sockio.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/bsd_tcpip/current/src/sys/kern/sockio.c,v
retrieving revision 1.2
diff -u -5 -r1.2 sockio.c
--- src/sys/kern/sockio.c	3 Nov 2002 19:49:44 -0000	1.2
+++ src/sys/kern/sockio.c	6 Nov 2002 19:15:00 -0000
@@ -212,10 +212,11 @@
 
 static int     
 bsd_socket(cyg_nstab_entry *nste, int domain, int type,
            int protocol, cyg_file *file)
 {
+    register int s = splsoftnet();
     int error = 0;
     struct socket *so;
 
     error = socreate(domain, &so, type, protocol, (struct proc *)&proc0);
 
@@ -231,10 +232,11 @@
         file->f_offset  = 0;
         file->f_data    = (CYG_ADDRWORD)so;
         file->f_xops    = (CYG_ADDRWORD)&bsd_sockops;
     }
     
+    splx(s);
     return error;
 }
 
 
 //==========================================================================
@@ -243,38 +245,45 @@
 // -------------------------------------------------------------------------
 
 static int 
 bsd_bind(cyg_file *fp, const sockaddr *sa, socklen_t len)
 {
+    register int s = splsoftnet();
     int error;
 
     error = sobind((struct socket *)fp->f_data, (sockaddr *)sa, 0);
+
+    splx(s);
     return error;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_connect(cyg_file *fp, const sockaddr *sa, socklen_t len)
 {
+    register int s = splsoftnet();
     struct socket *so;
-    int error, s;
+    int error;
 
     so = (struct socket *)fp->f_data;
 
     if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
+    {
+        splx(s);
         return (EALREADY);
+    }
 
     error = soconnect(so, (struct sockaddr *)sa, 0);
     if (error)
         goto bad;
 
     if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
+        splx(s);
         return (EINPROGRESS);
     }
 
-    s = splsoftnet();
     while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
         error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
                        "netcon", 0);
         if (error)
             break;
@@ -283,15 +292,15 @@
     if (error == 0) {
         error = so->so_error;
         so->so_error = 0;
     }
 
-    splx(s);
-
 bad:
     so->so_state &= ~SS_ISCONNECTING;
 
+    splx(s);
+
     return error;
 }
 
 // -------------------------------------------------------------------------
 
@@ -454,18 +463,22 @@
 // -------------------------------------------------------------------------
 
 static int 
 bsd_listen(cyg_file *fp, int backlog)
 {
-    return (solisten((struct socket *)fp->f_data, backlog, 0));
+    register int s = splsoftnet();
+    int err = (solisten((struct socket *)fp->f_data, backlog, 0));
+    splx(s);
+    return err;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_getname(cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer)
 {
+    register int s = splsoftnet();
     struct socket *so;
     socklen_t len = 0;
     int error;
     sockaddr *sa;
     
@@ -475,10 +488,11 @@
     so = (struct socket *)fp->f_data;
     sa = 0;
     if (peer) {
         // getpeername()
 	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
+            splx(s);
             return (ENOTCONN);
 	}
 	error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa);
     } else {
         // getsockname()
@@ -499,27 +513,32 @@
  gotnothing:
     *alen = len;
  bad:
     if (sa)
         FREE(sa, M_SONAME);
+    splx(s);
     return (error);
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_shutdown(cyg_file *fp, int how)
 {
-    return (soshutdown((struct socket *)fp->f_data, how));
+    register int s = splsoftnet();
+    int err = (soshutdown((struct socket *)fp->f_data, how));
+    splx(s);
+    return err;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_getsockopt(cyg_file *fp, int level, int optname,
                void *optval, socklen_t *optlen)
 {
+    register int s = splsoftnet();
     socklen_t valsize = 0;
     int error;
     struct sockopt opt;
 
     if( optval != NULL && optlen != NULL)
@@ -534,29 +553,34 @@
 
     error = sogetopt((struct socket *)fp->f_data, &opt);
     if (error == 0) {
         *optlen = opt.sopt_valsize;
     }
+    splx(s);
     return (error);
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_setsockopt(cyg_file *fp, int level, int optname,
                const void *optval, socklen_t optlen)
 {
+    register int s = splsoftnet();
+    int err;
     struct sockopt opt;
 
     opt.sopt_dir = SOPT_SET;
     opt.sopt_level = level;
     opt.sopt_name = optname;
     opt.sopt_val = (void *)optval;
     opt.sopt_valsize = optlen;
     opt.sopt_p = 0;
     
-    return sosetopt((struct socket *)fp->f_data, &opt);
+    err = sosetopt((struct socket *)fp->f_data, &opt);
+    splx(s);
+    return err;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
@@ -579,21 +603,27 @@
 // -------------------------------------------------------------------------
 
 static int 
 bsd_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-    return (soreceive((struct socket *)fp->f_data, (struct sockaddr **)0,
-                      uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
+    register int s = splsoftnet();
+    int err = (soreceive((struct socket *)fp->f_data, (struct sockaddr **)0,
+                         uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
+    splx(s);
+    return err;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-    return (sosend((struct socket *)fp->f_data, (struct sockaddr *)0,
-                   uio, (struct mbuf *)0, (struct mbuf *)0, 0, 0));
+    register int s = splsoftnet();
+    int err = (sosend((struct socket *)fp->f_data, (struct sockaddr *)0,
+                      uio, (struct mbuf *)0, (struct mbuf *)0, 0, 0));
+    splx(s);
+    return err;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
@@ -605,20 +635,23 @@
 // -------------------------------------------------------------------------
 
 static int 
 bsd_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd, CYG_ADDRWORD data)
 {
+    register int s = splsoftnet();
+    int err = 0;
     struct socket *so = (struct socket *)fp->f_data;
     void *p = 0;
 
     switch (cmd) {
 
     case FIONBIO:
         if (*(int *)data)
             so->so_state |= SS_NBIO;
         else
             so->so_state &= ~SS_NBIO;
+        splx(s);
         return (0);
 
     case FIOASYNC:
         if (*(int *)data) {
             so->so_state |= SS_ASYNC;
@@ -627,30 +660,37 @@
         } else {
             so->so_state &= ~SS_ASYNC;
             so->so_rcv.sb_flags &= ~SB_ASYNC;
             so->so_snd.sb_flags &= ~SB_ASYNC;
         }
+        splx(s);
         return (0);
 
     case FIONREAD:
         *(int *)data = so->so_rcv.sb_cc;
+        splx(s);
         return (0);
 
     case SIOCATMARK:
         *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
+        splx(s);
         return (0);
     }
     /*
      * Interface/routing/protocol specific ioctls:
      * interface and routing ioctls should have a
      * different entry since a socket's unnecessary
      */
     if (IOCGROUP(cmd) == 'i')
-        return (ifioctl(so, (u_long)cmd, (caddr_t)data, p));
+        err = (ifioctl(so, (u_long)cmd, (caddr_t)data, p));
     if (IOCGROUP(cmd) == 'r')
-        return (rtioctl((u_long)cmd, (caddr_t)data, p));
-    return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, (caddr_t)data, 0, 0));
+        err =  (rtioctl((u_long)cmd, (caddr_t)data, p));
+    else
+        err = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, (caddr_t)data, 0, 0));
+
+    splx(s);
+    return err;
 }
 
 #if 0  // DEBUG support
 static int 
 bsd_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd, CYG_ADDRWORD data)
@@ -715,32 +755,38 @@
 // -------------------------------------------------------------------------
 
 static int 
 bsd_close(struct CYG_FILE_TAG *fp)
 {
+    register int s = splsoftnet();
     int error = 0;
 
     if (fp->f_data)
         error = soclose((struct socket *)fp->f_data);
     fp->f_data = 0;
+    splx(s);
     return (error);
 }
 
 // -------------------------------------------------------------------------
 
 static int 
 bsd_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
 {
+    register int s = splsoftnet();
     register struct socket *so = (struct socket *)fp->f_data;
-
+    int err;
+    
     bzero((caddr_t)buf, sizeof (*buf));
 
     // Mark socket as a fifo for now. We need to add socket types to
     // sys/stat.h.
     buf->st_mode = __stat_mode_FIFO;
     
-    return ((*so->so_proto->pr_usrreqs->pru_sense)(so, buf));
+    err = ((*so->so_proto->pr_usrreqs->pru_sense)(so, buf));
+    splx(s);
+    return err;
 }
 
 // -------------------------------------------------------------------------
 
 static int 
@@ -836,10 +882,11 @@
 // recvit() function is uipc_syscalls.c.
 
 static int
 bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize)
 {
+    register int s = splsoftnet();
     struct uio auio;
     struct iovec *iov;
     int i;
     size_t len;
     int error;
@@ -857,10 +904,11 @@
     iov = mp->msg_iov;
     for (i = 0; i < mp->msg_iovlen; i++, iov++) {
         /* Don't allow sum > SSIZE_MAX */
         if (iov->iov_len > SSIZE_MAX ||
             (auio.uio_resid += iov->iov_len) > SSIZE_MAX)
+            splx(s);
             return (EINVAL);
     }
 
     len = auio.uio_resid;
     so = (struct socket *)fp->f_data;
@@ -953,10 +1001,11 @@
  out:
     if (fromsa)
         FREE(fromsa, M_SONAME);
     if (control)
         m_freem(control);
+    splx(s);
     return (error);
 }
 
 // -------------------------------------------------------------------------
 // sendit()
@@ -964,10 +1013,11 @@
 // synonymous function is uipc_syscalls.c.
 
 static int
 bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize)
 {
+    register int s = splsoftnet();
     struct uio auio;
     register struct iovec *iov;
     register int i;
     struct mbuf *control;
     struct sockaddr *to;
@@ -983,15 +1033,17 @@
     iov = mp->msg_iov;
     for (i = 0; i < mp->msg_iovlen; i++, iov++) {
         /* Don't allow sum > SSIZE_MAX */
         if (iov->iov_len > SSIZE_MAX ||
             (auio.uio_resid += iov->iov_len) > SSIZE_MAX)
+            splx(s);
             return (EINVAL);
     }
     if (mp->msg_name) {
         error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
         if (error) {
+            splx(s);
             return (error);
         }
     } else {
         to = 0;
     }
@@ -1038,10 +1090,11 @@
     if (error == 0)
         *retsize = len - auio.uio_resid;
  bad:
     if (to)
         FREE(to, M_SONAME);
+    splx(s);
     return (error);
 }
 
 static int
 getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)


-- 
Nick Garnett - eCos Kernel Architect
http://www.eCosCentric.com/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]