[BACK]Return to uipc_socket.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/uipc_socket.c between version 1.111.2.12 and 1.166

version 1.111.2.12, 2008/02/11 14:59:58 version 1.166, 2008/05/26 17:21:18
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   
 /*-  /*-
  * Copyright (c) 2002, 2007 The NetBSD Foundation, Inc.   * Copyright (c) 2002, 2007, 2008 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
  * This code is derived from software contributed to The NetBSD Foundation   * This code is derived from software contributed to The NetBSD Foundation
Line 15 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software  
  *    must display the following acknowledgement:  
  *      This product includes software developed by the NetBSD  
  *      Foundation, Inc. and its contributors.  
  * 4. Neither the name of The NetBSD Foundation nor the names of its  
  *    contributors may be used to endorse or promote products derived  
  *    from this software without specific prior written permission.  
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
Line 37 
Line 30 
  */   */
   
 /*  /*
    * Copyright (c) 2004 The FreeBSD Foundation
    * Copyright (c) 2004 Robert Watson
  * Copyright (c) 1982, 1986, 1988, 1990, 1993   * Copyright (c) 1982, 1986, 1988, 1990, 1993
  *      The Regents of the University of California.  All rights reserved.   *      The Regents of the University of California.  All rights reserved.
  *   *
Line 89  __KERNEL_RCSID(0, "$NetBSD$");
Line 84  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/socketvar.h>  #include <sys/socketvar.h>
 #include <sys/signalvar.h>  #include <sys/signalvar.h>
 #include <sys/resourcevar.h>  #include <sys/resourcevar.h>
 #include <sys/pool.h>  
 #include <sys/event.h>  #include <sys/event.h>
 #include <sys/poll.h>  #include <sys/poll.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
Line 98  __KERNEL_RCSID(0, "$NetBSD$");
Line 92  __KERNEL_RCSID(0, "$NetBSD$");
   
 #include <uvm/uvm.h>  #include <uvm/uvm.h>
   
 POOL_INIT(socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL,  
     IPL_SOFTNET);  
   
 MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options");  MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options");
 MALLOC_DEFINE(M_SONAME, "soname", "socket name");  MALLOC_DEFINE(M_SONAME, "soname", "socket name");
   
Line 108  extern const struct fileops socketops;
Line 99  extern const struct fileops socketops;
   
 extern int      somaxconn;                      /* patchable (XXX sysctl) */  extern int      somaxconn;                      /* patchable (XXX sysctl) */
 int             somaxconn = SOMAXCONN;  int             somaxconn = SOMAXCONN;
   kmutex_t        *softnet_lock;
   
 #ifdef SOSEND_COUNTERS  #ifdef SOSEND_COUNTERS
 #include <sys/device.h>  #include <sys/device.h>
Line 251  sokvafree(vaddr_t sva, vsize_t len)
Line 243  sokvafree(vaddr_t sva, vsize_t len)
 }  }
   
 static void  static void
 sodoloanfree(struct vm_page **pgs, void *buf, size_t size, bool mapped)  sodoloanfree(struct vm_page **pgs, void *buf, size_t size)
 {  {
         vaddr_t sva, eva;          vaddr_t sva, eva;
         vsize_t len;          vsize_t len;
Line 264  sodoloanfree(struct vm_page **pgs, void 
Line 256  sodoloanfree(struct vm_page **pgs, void 
         len = eva - sva;          len = eva - sva;
         npgs = len >> PAGE_SHIFT;          npgs = len >> PAGE_SHIFT;
   
         if (mapped) {          pmap_kremove(sva, len);
                 pmap_kremove(sva, len);          pmap_update(pmap_kernel());
                 pmap_update(pmap_kernel());  
         }  
         uvm_unloan(pgs, npgs, UVM_LOAN_TOPAGE);          uvm_unloan(pgs, npgs, UVM_LOAN_TOPAGE);
         sokvafree(sva, len);          sokvafree(sva, len);
 }  }
   
 static size_t  static size_t
 sodopendfree()  sodopendfree(void)
 {  {
         size_t rv;          size_t rv;
   
           if (__predict_true(so_pendfree == NULL))
                   return 0;
   
         mutex_enter(&so_pendfree_lock);          mutex_enter(&so_pendfree_lock);
         rv = sodopendfreel();          rv = sodopendfreel();
         mutex_exit(&so_pendfree_lock);          mutex_exit(&so_pendfree_lock);
Line 292  sodopendfree()
Line 285  sodopendfree()
  */   */
   
 static size_t  static size_t
 sodopendfreel()  sodopendfreel(void)
 {  {
         struct mbuf *m, *next;          struct mbuf *m, *next;
         size_t rv = 0;          size_t rv = 0;
Line 311  sodopendfreel()
Line 304  sodopendfreel()
   
                         rv += m->m_ext.ext_size;                          rv += m->m_ext.ext_size;
                         sodoloanfree(m->m_ext.ext_pgs, m->m_ext.ext_buf,                          sodoloanfree(m->m_ext.ext_pgs, m->m_ext.ext_buf,
                             m->m_ext.ext_size,                              m->m_ext.ext_size);
                             (m->m_ext.ext_flags & M_EXT_LAZY) == 0);  
                         pool_cache_put(mb_cache, m);                          pool_cache_put(mb_cache, m);
                 }                  }
   
Line 350  sosend_loan(struct socket *so, struct ui
Line 342  sosend_loan(struct socket *so, struct ui
         vsize_t len;          vsize_t len;
         vaddr_t lva;          vaddr_t lva;
         int npgs, error;          int npgs, error;
 #if !defined(__HAVE_LAZY_MBUF)  
         vaddr_t va;          vaddr_t va;
         int i;          int i;
 #endif /* !defined(__HAVE_LAZY_MBUF) */  
   
         if (VMSPACE_IS_KERNEL_P(uio->uio_vmspace))          if (VMSPACE_IS_KERNEL_P(uio->uio_vmspace))
                 return (0);                  return (0);
Line 368  sosend_loan(struct socket *so, struct ui
Line 358  sosend_loan(struct socket *so, struct ui
         len = eva - sva;          len = eva - sva;
         npgs = len >> PAGE_SHIFT;          npgs = len >> PAGE_SHIFT;
   
         /* XXX KDASSERT */  
         KASSERT(npgs <= M_EXT_MAXPAGES);          KASSERT(npgs <= M_EXT_MAXPAGES);
   
         lva = sokvaalloc(len, so);          lva = sokvaalloc(len, so);
Line 382  sosend_loan(struct socket *so, struct ui
Line 371  sosend_loan(struct socket *so, struct ui
                 return (0);                  return (0);
         }          }
   
 #if !defined(__HAVE_LAZY_MBUF)  
         for (i = 0, va = lva; i < npgs; i++, va += PAGE_SIZE)          for (i = 0, va = lva; i < npgs; i++, va += PAGE_SIZE)
                 pmap_kenter_pa(va, VM_PAGE_TO_PHYS(m->m_ext.ext_pgs[i]),                  pmap_kenter_pa(va, VM_PAGE_TO_PHYS(m->m_ext.ext_pgs[i]),
                     VM_PROT_READ);                      VM_PROT_READ);
         pmap_update(pmap_kernel());          pmap_update(pmap_kernel());
 #endif /* !defined(__HAVE_LAZY_MBUF) */  
   
         lva += (vaddr_t) iov->iov_base & PAGE_MASK;          lva += (vaddr_t) iov->iov_base & PAGE_MASK;
   
         MEXTADD(m, (void *) lva, space, M_MBUF, soloanfree, so);          MEXTADD(m, (void *) lva, space, M_MBUF, soloanfree, so);
         m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;          m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;
   
 #if defined(__HAVE_LAZY_MBUF)  
         m->m_flags |= M_EXT_LAZY;  
         m->m_ext.ext_flags |= M_EXT_LAZY;  
 #endif /* defined(__HAVE_LAZY_MBUF) */  
   
         uio->uio_resid -= space;          uio->uio_resid -= space;
         /* uio_offset not updated, not set/used for write(2) */          /* uio_offset not updated, not set/used for write(2) */
         uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + space;          uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + space;
Line 451  soinit(void)
Line 433  soinit(void)
 {  {
   
         mutex_init(&so_pendfree_lock, MUTEX_DEFAULT, IPL_VM);          mutex_init(&so_pendfree_lock, MUTEX_DEFAULT, IPL_VM);
           softnet_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
         cv_init(&socurkva_cv, "sokva");          cv_init(&socurkva_cv, "sokva");
           soinit2();
   
         /* Set the initial adjusted socket buffer size. */          /* Set the initial adjusted socket buffer size. */
         if (sb_max_set(sb_max))          if (sb_max_set(sb_max))
Line 470  soinit(void)
Line 454  soinit(void)
  */   */
 /*ARGSUSED*/  /*ARGSUSED*/
 int  int
 socreate(int dom, struct socket **aso, int type, int proto, struct lwp *l)  socreate(int dom, struct socket **aso, int type, int proto, struct lwp *l,
            struct socket *lockso)
 {  {
         const struct protosw    *prp;          const struct protosw    *prp;
         struct socket   *so;          struct socket   *so;
         uid_t           uid;          uid_t           uid;
         int             error, s;          int             error;
           kmutex_t        *lock;
   
         error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET,          error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET,
             KAUTH_REQ_NETWORK_SOCKET_OPEN, KAUTH_ARG(dom), KAUTH_ARG(type),              KAUTH_REQ_NETWORK_SOCKET_OPEN, KAUTH_ARG(dom), KAUTH_ARG(type),
Line 500  socreate(int dom, struct socket **aso, i
Line 486  socreate(int dom, struct socket **aso, i
                 return EPROTONOSUPPORT;                  return EPROTONOSUPPORT;
         if (prp->pr_type != type)          if (prp->pr_type != type)
                 return EPROTOTYPE;                  return EPROTOTYPE;
         s = splsoftnet();  
         so = pool_get(&socket_pool, PR_WAITOK);          so = soget(true);
         memset(so, 0, sizeof(*so));  
         TAILQ_INIT(&so->so_q0);  
         TAILQ_INIT(&so->so_q);  
         so->so_type = type;          so->so_type = type;
         so->so_proto = prp;          so->so_proto = prp;
         so->so_send = sosend;          so->so_send = sosend;
Line 514  socreate(int dom, struct socket **aso, i
Line 497  socreate(int dom, struct socket **aso, i
         so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner;          so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner;
         so->so_mowner = &prp->pr_domain->dom_mowner;          so->so_mowner = &prp->pr_domain->dom_mowner;
 #endif  #endif
         selinit(&so->so_rcv.sb_sel);  
         selinit(&so->so_snd.sb_sel);  
         uid = kauth_cred_geteuid(l->l_cred);          uid = kauth_cred_geteuid(l->l_cred);
         so->so_uidinfo = uid_find(uid);          so->so_uidinfo = uid_find(uid);
           if (lockso != NULL) {
                   /* Caller wants us to share a lock. */
                   lock = lockso->so_lock;
                   so->so_lock = lock;
                   mutex_obj_hold(lock);
                   mutex_enter(lock);
           } else {
                   /* Lock assigned and taken during PRU_ATTACH. */
           }
         error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL,          error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL,
             (struct mbuf *)(long)proto, NULL, l);              (struct mbuf *)(long)proto, NULL, l);
           KASSERT(solocked(so));
         if (error != 0) {          if (error != 0) {
                 so->so_state |= SS_NOFDREF;                  so->so_state |= SS_NOFDREF;
                 sofree(so);                  sofree(so);
                 splx(s);  
                 return error;                  return error;
         }          }
         splx(s);          sounlock(so);
         *aso = so;          *aso = so;
         return 0;          return 0;
 }  }
Line 538  int
Line 528  int
 fsocreate(int domain, struct socket **sop, int type, int protocol,  fsocreate(int domain, struct socket **sop, int type, int protocol,
     struct lwp *l, int *fdout)      struct lwp *l, int *fdout)
 {  {
         struct filedesc *fdp;  
         struct socket   *so;          struct socket   *so;
         struct file     *fp;          struct file     *fp;
         int             fd, error;          int             fd, error;
   
         fdp = l->l_proc->p_fd;          if ((error = fd_allocfile(&fp, &fd)) != 0)
         /* falloc() will use the desciptor for us */  
         if ((error = falloc(l, &fp, &fd)) != 0)  
                 return (error);                  return (error);
         fp->f_flag = FREAD|FWRITE;          fp->f_flag = FREAD|FWRITE;
         fp->f_type = DTYPE_SOCKET;          fp->f_type = DTYPE_SOCKET;
         fp->f_ops = &socketops;          fp->f_ops = &socketops;
         error = socreate(domain, &so, type, protocol, l);          error = socreate(domain, &so, type, protocol, l, NULL);
         if (error != 0) {          if (error != 0) {
                 FILE_UNUSE(fp, l);                  fd_abort(curproc, fp, fd);
                 fdremove(fdp, fd);  
                 ffree(fp);  
         } else {          } else {
                 if (sop != NULL)                  if (sop != NULL)
                         *sop = so;                          *sop = so;
                 fp->f_data = so;                  fp->f_data = so;
                 FILE_SET_MATURE(fp);                  fd_affix(curproc, fp, fd);
                 FILE_UNUSE(fp, l);  
                 *fdout = fd;                  *fdout = fd;
         }          }
         return error;          return error;
Line 569  fsocreate(int domain, struct socket **so
Line 553  fsocreate(int domain, struct socket **so
 int  int
 sobind(struct socket *so, struct mbuf *nam, struct lwp *l)  sobind(struct socket *so, struct mbuf *nam, struct lwp *l)
 {  {
         int     s, error;          int     error;
   
         s = splsoftnet();          solock(so);
         error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, l);          error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, l);
         splx(s);          sounlock(so);
         return error;          return error;
 }  }
   
 int  int
 solisten(struct socket *so, int backlog, struct lwp *l)  solisten(struct socket *so, int backlog, struct lwp *l)
 {  {
         int     s, error;          int     error;
   
         s = splsoftnet();          solock(so);
           if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING |
               SS_ISDISCONNECTING)) != 0) {
                   sounlock(so);
                   return (EOPNOTSUPP);
           }
         error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL,          error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL,
             NULL, NULL, l);              NULL, NULL, l);
         if (error != 0) {          if (error != 0) {
                 splx(s);                  sounlock(so);
                 return error;                  return error;
         }          }
         if (TAILQ_EMPTY(&so->so_q))          if (TAILQ_EMPTY(&so->so_q))
Line 594  solisten(struct socket *so, int backlog,
Line 583  solisten(struct socket *so, int backlog,
         if (backlog < 0)          if (backlog < 0)
                 backlog = 0;                  backlog = 0;
         so->so_qlimit = min(backlog, somaxconn);          so->so_qlimit = min(backlog, somaxconn);
         splx(s);          sounlock(so);
         return 0;          return 0;
 }  }
   
 void  void
 sofree(struct socket *so)  sofree(struct socket *so)
 {  {
           u_int refs;
   
           KASSERT(solocked(so));
   
         if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)          if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) {
                   sounlock(so);
                 return;                  return;
           }
         if (so->so_head) {          if (so->so_head) {
                 /*                  /*
                  * We must not decommission a socket that's on the accept(2)                   * We must not decommission a socket that's on the accept(2)
                  * queue.  If we do, then accept(2) may hang after select(2)                   * queue.  If we do, then accept(2) may hang after select(2)
                  * indicated that the listening socket was ready.                   * indicated that the listening socket was ready.
                  */                   */
                 if (!soqremque(so, 0))                  if (!soqremque(so, 0)) {
                           sounlock(so);
                         return;                          return;
                   }
         }          }
         if (so->so_rcv.sb_hiwat)          if (so->so_rcv.sb_hiwat)
                 (void)chgsbsize(so->so_uidinfo, &so->so_rcv.sb_hiwat, 0,                  (void)chgsbsize(so->so_uidinfo, &so->so_rcv.sb_hiwat, 0,
Line 620  sofree(struct socket *so)
Line 616  sofree(struct socket *so)
                 (void)chgsbsize(so->so_uidinfo, &so->so_snd.sb_hiwat, 0,                  (void)chgsbsize(so->so_uidinfo, &so->so_snd.sb_hiwat, 0,
                     RLIM_INFINITY);                      RLIM_INFINITY);
         sbrelease(&so->so_snd, so);          sbrelease(&so->so_snd, so);
           KASSERT(!cv_has_waiters(&so->so_cv));
           KASSERT(!cv_has_waiters(&so->so_rcv.sb_cv));
           KASSERT(!cv_has_waiters(&so->so_snd.sb_cv));
         sorflush(so);          sorflush(so);
         seldestroy(&so->so_rcv.sb_sel);          refs = so->so_aborting; /* XXX */
         seldestroy(&so->so_snd.sb_sel);          sounlock(so);
         pool_put(&socket_pool, so);          if (refs == 0)          /* XXX */
                   soput(so);
 }  }
   
 /*  /*
Line 635  int
Line 635  int
 soclose(struct socket *so)  soclose(struct socket *so)
 {  {
         struct socket   *so2;          struct socket   *so2;
         int             s, error;          int             error;
           int             error2;
   
         error = 0;          error = 0;
         s = splsoftnet();               /* conservative */          solock(so);
         if (so->so_options & SO_ACCEPTCONN) {          if (so->so_options & SO_ACCEPTCONN) {
                 while ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) {                  do {
                         (void) soqremque(so2, 0);                          if ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) {
                         (void) soabort(so2);                                  KASSERT(solocked2(so, so2));
                 }                                  (void) soqremque(so2, 0);
                 while ((so2 = TAILQ_FIRST(&so->so_q)) != 0) {                                  /* soabort drops the lock. */
                         (void) soqremque(so2, 1);                                  (void) soabort(so2);
                         (void) soabort(so2);                                  solock(so);
                 }                                  continue;
                           }
                           if ((so2 = TAILQ_FIRST(&so->so_q)) != 0) {
                                   KASSERT(solocked2(so, so2));
                                   (void) soqremque(so2, 1);
                                   /* soabort drops the lock. */
                                   (void) soabort(so2);
                                   solock(so);
                                   continue;
                           }
                   } while (0);
         }          }
         if (so->so_pcb == 0)          if (so->so_pcb == 0)
                 goto discard;                  goto discard;
Line 661  soclose(struct socket *so)
Line 672  soclose(struct socket *so)
                         if ((so->so_state & SS_ISDISCONNECTING) && so->so_nbio)                          if ((so->so_state & SS_ISDISCONNECTING) && so->so_nbio)
                                 goto drop;                                  goto drop;
                         while (so->so_state & SS_ISCONNECTED) {                          while (so->so_state & SS_ISCONNECTED) {
                                 error = tsleep((void *)&so->so_timeo,                                  error = sowait(so, so->so_linger * hz);
                                                PSOCK | PCATCH, netcls,  
                                                so->so_linger * hz);  
                                 if (error)                                  if (error)
                                         break;                                          break;
                         }                          }
Line 671  soclose(struct socket *so)
Line 680  soclose(struct socket *so)
         }          }
  drop:   drop:
         if (so->so_pcb) {          if (so->so_pcb) {
                 int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,                  error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
                     NULL, NULL, NULL, NULL);                      NULL, NULL, NULL, NULL);
                 if (error == 0)                  if (error == 0)
                         error = error2;                          error = error2;
Line 681  soclose(struct socket *so)
Line 690  soclose(struct socket *so)
                 panic("soclose: NOFDREF");                  panic("soclose: NOFDREF");
         so->so_state |= SS_NOFDREF;          so->so_state |= SS_NOFDREF;
         sofree(so);          sofree(so);
         splx(s);  
         return (error);          return (error);
 }  }
   
 /*  /*
  * Must be called at splsoftnet...   * Must be called with the socket locked..  Will return with it unlocked.
  */   */
 int  int
 soabort(struct socket *so)  soabort(struct socket *so)
 {  {
           u_int refs;
         int error;          int error;
   
           KASSERT(solocked(so));
         KASSERT(so->so_head == NULL);          KASSERT(so->so_head == NULL);
   
           so->so_aborting++;              /* XXX */
         error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL,          error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL,
             NULL, NULL, NULL);              NULL, NULL, NULL);
         if (error) {          refs = --so->so_aborting;       /* XXX */
           if (error || (refs == 0)) {
                 sofree(so);                  sofree(so);
           } else {
                   sounlock(so);
         }          }
         return error;          return error;
 }  }
Line 705  soabort(struct socket *so)
Line 720  soabort(struct socket *so)
 int  int
 soaccept(struct socket *so, struct mbuf *nam)  soaccept(struct socket *so, struct mbuf *nam)
 {  {
         int     s, error;          int     error;
   
           KASSERT(solocked(so));
   
         error = 0;          error = 0;
         s = splsoftnet();  
         if ((so->so_state & SS_NOFDREF) == 0)          if ((so->so_state & SS_NOFDREF) == 0)
                 panic("soaccept: !NOFDREF");                  panic("soaccept: !NOFDREF");
         so->so_state &= ~SS_NOFDREF;          so->so_state &= ~SS_NOFDREF;
Line 719  soaccept(struct socket *so, struct mbuf 
Line 735  soaccept(struct socket *so, struct mbuf 
         else          else
                 error = ECONNABORTED;                  error = ECONNABORTED;
   
         splx(s);  
         return (error);          return (error);
 }  }
   
 int  int
 soconnect(struct socket *so, struct mbuf *nam, struct lwp *l)  soconnect(struct socket *so, struct mbuf *nam, struct lwp *l)
 {  {
         int             s, error;          int             error;
   
           KASSERT(solocked(so));
   
         if (so->so_options & SO_ACCEPTCONN)          if (so->so_options & SO_ACCEPTCONN)
                 return (EOPNOTSUPP);                  return (EOPNOTSUPP);
         s = splsoftnet();  
         /*          /*
          * If protocol is connection-based, can only connect once.           * If protocol is connection-based, can only connect once.
          * Otherwise, if connected, try to disconnect first.           * Otherwise, if connected, try to disconnect first.
Line 744  soconnect(struct socket *so, struct mbuf
Line 760  soconnect(struct socket *so, struct mbuf
         else          else
                 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,                  error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
                     NULL, nam, NULL, l);                      NULL, nam, NULL, l);
         splx(s);  
         return (error);          return (error);
 }  }
   
 int  int
 soconnect2(struct socket *so1, struct socket *so2)  soconnect2(struct socket *so1, struct socket *so2)
 {  {
         int     s, error;          int     error;
   
           KASSERT(solocked2(so1, so2));
   
         s = splsoftnet();  
         error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,          error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
             NULL, (struct mbuf *)so2, NULL, NULL);              NULL, (struct mbuf *)so2, NULL, NULL);
         splx(s);  
         return (error);          return (error);
 }  }
   
 int  int
 sodisconnect(struct socket *so)  sodisconnect(struct socket *so)
 {  {
         int     s, error;          int     error;
   
           KASSERT(solocked(so));
   
         s = splsoftnet();  
         if ((so->so_state & SS_ISCONNECTED) == 0) {          if ((so->so_state & SS_ISCONNECTED) == 0) {
                 error = ENOTCONN;                  error = ENOTCONN;
                 goto bad;          } else if (so->so_state & SS_ISDISCONNECTING) {
         }  
         if (so->so_state & SS_ISDISCONNECTING) {  
                 error = EALREADY;                  error = EALREADY;
                 goto bad;          } else {
                   error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
                       NULL, NULL, NULL, NULL);
         }          }
         error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,  
             NULL, NULL, NULL, NULL);  
  bad:  
         splx(s);  
         sodopendfree();          sodopendfree();
         return (error);          return (error);
 }  }
Line 811  sosend(struct socket *so, struct mbuf *a
Line 823  sosend(struct socket *so, struct mbuf *a
   
         p = l->l_proc;          p = l->l_proc;
         sodopendfree();          sodopendfree();
   
         clen = 0;          clen = 0;
   
           /*
            * solock() provides atomicity of access.  splsoftnet() prevents
            * protocol processing soft interrupts from interrupting us and
            * blocking (expensive).
            */
           s = splsoftnet();
           solock(so);
         atomic = sosendallatonce(so) || top;          atomic = sosendallatonce(so) || top;
         if (uio)          if (uio)
                 resid = uio->uio_resid;                  resid = uio->uio_resid;
Line 832  sosend(struct socket *so, struct mbuf *a
Line 851  sosend(struct socket *so, struct mbuf *a
         dontroute =          dontroute =
             (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&              (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
             (so->so_proto->pr_flags & PR_ATOMIC);              (so->so_proto->pr_flags & PR_ATOMIC);
         if (p)          l->l_ru.ru_msgsnd++;
                 p->p_stats->p_ru.ru_msgsnd++;  
         if (control)          if (control)
                 clen = control->m_len;                  clen = control->m_len;
 #define snderr(errno)   { error = errno; splx(s); goto release; }  
   
  restart:   restart:
         if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)          if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
                 goto out;                  goto out;
         do {          do {
                 s = splsoftnet();                  if (so->so_state & SS_CANTSENDMORE) {
                 if (so->so_state & SS_CANTSENDMORE)                          error = EPIPE;
                         snderr(EPIPE);                          goto release;
                   }
                 if (so->so_error) {                  if (so->so_error) {
                         error = so->so_error;                          error = so->so_error;
                         so->so_error = 0;                          so->so_error = 0;
                         splx(s);  
                         goto release;                          goto release;
                 }                  }
                 if ((so->so_state & SS_ISCONNECTED) == 0) {                  if ((so->so_state & SS_ISCONNECTED) == 0) {
                         if (so->so_proto->pr_flags & PR_CONNREQUIRED) {                          if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
                                 if ((so->so_state & SS_ISCONFIRMING) == 0 &&                                  if ((so->so_state & SS_ISCONFIRMING) == 0 &&
                                     !(resid == 0 && clen != 0))                                      !(resid == 0 && clen != 0)) {
                                         snderr(ENOTCONN);                                          error = ENOTCONN;
                         } else if (addr == 0)                                          goto release;
                                 snderr(EDESTADDRREQ);                                  }
                           } else if (addr == 0) {
                                   error = EDESTADDRREQ;
                                   goto release;
                           }
                 }                  }
                 space = sbspace(&so->so_snd);                  space = sbspace(&so->so_snd);
                 if (flags & MSG_OOB)                  if (flags & MSG_OOB)
                         space += 1024;                          space += 1024;
                 if ((atomic && resid > so->so_snd.sb_hiwat) ||                  if ((atomic && resid > so->so_snd.sb_hiwat) ||
                     clen > so->so_snd.sb_hiwat)                      clen > so->so_snd.sb_hiwat) {
                         snderr(EMSGSIZE);                          error = EMSGSIZE;
                           goto release;
                   }
                 if (space < resid + clen &&                  if (space < resid + clen &&
                     (atomic || space < so->so_snd.sb_lowat || space < clen)) {                      (atomic || space < so->so_snd.sb_lowat || space < clen)) {
                         if (so->so_nbio)                          if (so->so_nbio) {
                                 snderr(EWOULDBLOCK);                                  error = EWOULDBLOCK;
                                   goto release;
                           }
                         sbunlock(&so->so_snd);                          sbunlock(&so->so_snd);
                         error = sbwait(&so->so_snd);                          error = sbwait(&so->so_snd);
                         splx(s);  
                         if (error)                          if (error)
                                 goto out;                                  goto out;
                         goto restart;                          goto restart;
                 }                  }
                 splx(s);  
                 mp = &top;                  mp = &top;
                 space -= clen;                  space -= clen;
                 do {                  do {
Line 888  sosend(struct socket *so, struct mbuf *a
Line 910  sosend(struct socket *so, struct mbuf *a
                                 if (flags & MSG_EOR)                                  if (flags & MSG_EOR)
                                         top->m_flags |= M_EOR;                                          top->m_flags |= M_EOR;
                         } else do {                          } else do {
                                   sounlock(so);
                                   splx(s);
                                 if (top == NULL) {                                  if (top == NULL) {
                                         m = m_gethdr(M_WAIT, MT_DATA);                                          m = m_gethdr(M_WAIT, MT_DATA);
                                         mlen = MHLEN;                                          mlen = MHLEN;
Line 938  sosend(struct socket *so, struct mbuf *a
Line 962  sosend(struct socket *so, struct mbuf *a
                                 m->m_len = len;                                  m->m_len = len;
                                 *mp = m;                                  *mp = m;
                                 top->m_pkthdr.len += len;                                  top->m_pkthdr.len += len;
                                   s = splsoftnet();
                                   solock(so);
                                 if (error != 0)                                  if (error != 0)
                                         goto release;                                          goto release;
                                 mp = &m->m_next;                                  mp = &m->m_next;
Line 948  sosend(struct socket *so, struct mbuf *a
Line 974  sosend(struct socket *so, struct mbuf *a
                                 }                                  }
                         } while (space > 0 && atomic);                          } while (space > 0 && atomic);
   
                         s = splsoftnet();                          if (so->so_state & SS_CANTSENDMORE) {
                                   error = EPIPE;
                         if (so->so_state & SS_CANTSENDMORE)                                  goto release;
                                 snderr(EPIPE);                          }
   
                         if (dontroute)                          if (dontroute)
                                 so->so_options |= SO_DONTROUTE;                                  so->so_options |= SO_DONTROUTE;
                         if (resid > 0)                          if (resid > 0)
                                 so->so_state |= SS_MORETOCOME;                                  so->so_state |= SS_MORETOCOME;
                         error = (*so->so_proto->pr_usrreq)(so,                          error = (*so->so_proto->pr_usrreq)(so,
                             (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,                              (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
                             top, addr, control, curlwp);        /* XXX */                              top, addr, control, curlwp);
                         if (dontroute)                          if (dontroute)
                                 so->so_options &= ~SO_DONTROUTE;                                  so->so_options &= ~SO_DONTROUTE;
                         if (resid > 0)                          if (resid > 0)
                                 so->so_state &= ~SS_MORETOCOME;                                  so->so_state &= ~SS_MORETOCOME;
                         splx(s);  
   
                         clen = 0;                          clen = 0;
                         control = NULL;                          control = NULL;
                         top = NULL;                          top = NULL;
Line 978  sosend(struct socket *so, struct mbuf *a
Line 1001  sosend(struct socket *so, struct mbuf *a
  release:   release:
         sbunlock(&so->so_snd);          sbunlock(&so->so_snd);
  out:   out:
           sounlock(so);
           splx(s);
         if (top)          if (top)
                 m_freem(top);                  m_freem(top);
         if (control)          if (control)
Line 986  sosend(struct socket *so, struct mbuf *a
Line 1011  sosend(struct socket *so, struct mbuf *a
 }  }
   
 /*  /*
    * Following replacement or removal of the first mbuf on the first
    * mbuf chain of a socket buffer, push necessary state changes back
    * into the socket buffer so that other consumers see the values
    * consistently.  'nextrecord' is the callers locally stored value of
    * the original value of sb->sb_mb->m_nextpkt which must be restored
    * when the lead mbuf changes.  NOTE: 'nextrecord' may be NULL.
    */
   static void
   sbsync(struct sockbuf *sb, struct mbuf *nextrecord)
   {
   
           KASSERT(solocked(sb->sb_so));
   
           /*
            * First, update for the new value of nextrecord.  If necessary,
            * make it the first record.
            */
           if (sb->sb_mb != NULL)
                   sb->sb_mb->m_nextpkt = nextrecord;
           else
                   sb->sb_mb = nextrecord;
   
           /*
            * Now update any dependent socket buffer fields to reflect
            * the new state.  This is an inline of SB_EMPTY_FIXUP, with
            * the addition of a second clause that takes care of the
            * case where sb_mb has been updated, but remains the last
            * record.
            */
           if (sb->sb_mb == NULL) {
                   sb->sb_mbtail = NULL;
                   sb->sb_lastrecord = NULL;
           } else if (sb->sb_mb->m_nextpkt == NULL)
                   sb->sb_lastrecord = sb->sb_mb;
   }
   
   /*
  * Implement receive operations on a socket.   * Implement receive operations on a socket.
  * We depend on the way that records are added to the sockbuf   * We depend on the way that records are added to the sockbuf
  * by sbappend*.  In particular, each record (mbufs linked through m_next)   * by sbappend*.  In particular, each record (mbufs linked through m_next)
Line 1006  soreceive(struct socket *so, struct mbuf
Line 1068  soreceive(struct socket *so, struct mbuf
         struct mbuf **mp0, struct mbuf **controlp, int *flagsp)          struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
 {  {
         struct lwp *l = curlwp;          struct lwp *l = curlwp;
         struct mbuf     *m, **mp;          struct mbuf     *m, **mp, *mt;
         int atomic, flags, len, error, s, offset, moff, type, orig_resid;          int atomic, flags, len, error, s, offset, moff, type, orig_resid;
         const struct protosw    *pr;          const struct protosw    *pr;
         struct mbuf     *nextrecord;          struct mbuf     *nextrecord;
Line 1034  soreceive(struct socket *so, struct mbuf
Line 1096  soreceive(struct socket *so, struct mbuf
   
         if (flags & MSG_OOB) {          if (flags & MSG_OOB) {
                 m = m_get(M_WAIT, MT_DATA);                  m = m_get(M_WAIT, MT_DATA);
                   solock(so);
                 error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,                  error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
                     (struct mbuf *)(long)(flags & MSG_PEEK), NULL, l);                      (struct mbuf *)(long)(flags & MSG_PEEK), NULL, l);
                   sounlock(so);
                 if (error)                  if (error)
                         goto bad;                          goto bad;
                 do {                  do {
Line 1050  soreceive(struct socket *so, struct mbuf
Line 1114  soreceive(struct socket *so, struct mbuf
         }          }
         if (mp != NULL)          if (mp != NULL)
                 *mp = NULL;                  *mp = NULL;
   
           /*
            * solock() provides atomicity of access.  splsoftnet() prevents
            * protocol processing soft interrupts from interrupting us and
            * blocking (expensive).
            */
           s = splsoftnet();
           solock(so);
         if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)          if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
                 (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, l);                  (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, l);
   
  restart:   restart:
         if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)          if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0) {
                   sounlock(so);
                   splx(s);
                 return error;                  return error;
         s = splsoftnet();          }
   
         m = so->so_rcv.sb_mb;          m = so->so_rcv.sb_mb;
         /*          /*
Line 1115  soreceive(struct socket *so, struct mbuf
Line 1189  soreceive(struct socket *so, struct mbuf
                 SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");                  SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");
                 sbunlock(&so->so_rcv);                  sbunlock(&so->so_rcv);
                 error = sbwait(&so->so_rcv);                  error = sbwait(&so->so_rcv);
                 splx(s);                  if (error != 0) {
                 if (error != 0)                          sounlock(so);
                           splx(s);
                         return error;                          return error;
                   }
                 goto restart;                  goto restart;
         }          }
  dontblock:   dontblock:
         /*          /*
          * On entry here, m points to the first record of the socket buffer.           * On entry here, m points to the first record of the socket buffer.
          * While we process the initial mbufs containing address and control           * From this point onward, we maintain 'nextrecord' as a cache of the
          * info, we save a copy of m->m_nextpkt into nextrecord.           * pointer to the next record in the socket buffer.  We must keep the
            * various socket buffer pointers and local stack versions of the
            * pointers in sync, pushing out modifications before dropping the
            * socket lock, and re-reading them when picking it up.
            *
            * Otherwise, we will race with the network stack appending new data
            * or records onto the socket buffer by using inconsistent/stale
            * versions of the field, possibly resulting in socket buffer
            * corruption.
            *
            * By holding the high-level sblock(), we prevent simultaneous
            * readers from pulling off the front of the socket buffer.
          */           */
         if (l != NULL)          if (l != NULL)
                 l->l_proc->p_stats->p_ru.ru_msgrcv++;                  l->l_ru.ru_msgrcv++;
         KASSERT(m == so->so_rcv.sb_mb);          KASSERT(m == so->so_rcv.sb_mb);
         SBLASTRECORDCHK(&so->so_rcv, "soreceive 1");          SBLASTRECORDCHK(&so->so_rcv, "soreceive 1");
         SBLASTMBUFCHK(&so->so_rcv, "soreceive 1");          SBLASTMBUFCHK(&so->so_rcv, "soreceive 1");
Line 1154  soreceive(struct socket *so, struct mbuf
Line 1241  soreceive(struct socket *so, struct mbuf
                                 MFREE(m, so->so_rcv.sb_mb);                                  MFREE(m, so->so_rcv.sb_mb);
                                 m = so->so_rcv.sb_mb;                                  m = so->so_rcv.sb_mb;
                         }                          }
                           sbsync(&so->so_rcv, nextrecord);
                 }                  }
         }          }
         while (m != NULL && m->m_type == MT_CONTROL && error == 0) {  
                 if (flags & MSG_PEEK) {          /*
                         if (controlp != NULL)           * Process one or more MT_CONTROL mbufs present before any data mbufs
                                 *controlp = m_copy(m, 0, m->m_len);           * in the first mbuf chain on the socket buffer.  If MSG_PEEK, we
                         m = m->m_next;           * just copy the data; if !MSG_PEEK, we call into the protocol to
                 } else {           * perform externalization (or freeing if controlp == NULL).
                         sbfree(&so->so_rcv, m);           */
                         mbuf_removed = 1;          if (__predict_false(m != NULL && m->m_type == MT_CONTROL)) {
                         if (controlp != NULL) {                  struct mbuf *cm = NULL, *cmn;
                                 if (dom->dom_externalize && l &&                  struct mbuf **cme = &cm;
                                     mtod(m, struct cmsghdr *)->cmsg_type ==  
                                     SCM_RIGHTS)                  do {
                                         error = (*dom->dom_externalize)(m, l);                          if (flags & MSG_PEEK) {
                                 *controlp = m;                                  if (controlp != NULL) {
                                           *controlp = m_copy(m, 0, m->m_len);
                                           controlp = &(*controlp)->m_next;
                                   }
                                   m = m->m_next;
                           } else {
                                   sbfree(&so->so_rcv, m);
                                 so->so_rcv.sb_mb = m->m_next;                                  so->so_rcv.sb_mb = m->m_next;
                                 m->m_next = NULL;                                  m->m_next = NULL;
                                   *cme = m;
                                   cme = &(*cme)->m_next;
                                 m = so->so_rcv.sb_mb;                                  m = so->so_rcv.sb_mb;
                           }
                   } while (m != NULL && m->m_type == MT_CONTROL);
                   if ((flags & MSG_PEEK) == 0)
                           sbsync(&so->so_rcv, nextrecord);
                   for (; cm != NULL; cm = cmn) {
                           cmn = cm->m_next;
                           cm->m_next = NULL;
                           type = mtod(cm, struct cmsghdr *)->cmsg_type;
                           if (controlp != NULL) {
                                   if (dom->dom_externalize != NULL &&
                                       type == SCM_RIGHTS) {
                                           sounlock(so);
                                           splx(s);
                                           error = (*dom->dom_externalize)(cm, l);
                                           s = splsoftnet();
                                           solock(so);
                                   }
                                   *controlp = cm;
                                   while (*controlp != NULL)
                                           controlp = &(*controlp)->m_next;
                         } else {                          } else {
                                 /*                                  /*
                                  * Dispose of any SCM_RIGHTS message that went                                   * Dispose of any SCM_RIGHTS message that went
                                  * through the read path rather than recv.                                   * through the read path rather than recv.
                                  */                                   */
                                 if (dom->dom_dispose &&                                  if (dom->dom_dispose != NULL &&
                                     mtod(m, struct cmsghdr *)->cmsg_type == SCM_RIGHTS)                                      type == SCM_RIGHTS) {
                                         (*dom->dom_dispose)(m);                                          sounlock(so);
                                 MFREE(m, so->so_rcv.sb_mb);                                          (*dom->dom_dispose)(cm);
                                 m = so->so_rcv.sb_mb;                                          solock(so);
                                   }
                                   m_freem(cm);
                         }                          }
                 }                  }
                 if (controlp != NULL) {                  if (m != NULL)
                         orig_resid = 0;                          nextrecord = so->so_rcv.sb_mb->m_nextpkt;
                         controlp = &(*controlp)->m_next;                  else
                 }                          nextrecord = so->so_rcv.sb_mb;
                   orig_resid = 0;
         }          }
   
         /*          /* If m is non-NULL, we have some data to read. */
          * If m is non-NULL, we have some data to read.  From now on,          if (__predict_true(m != NULL)) {
          * make sure to keep sb_lastrecord consistent when working on  
          * the last packet on the chain (nextrecord == NULL) and we  
          * change m->m_nextpkt.  
          */  
         if (m != NULL) {  
                 if ((flags & MSG_PEEK) == 0) {  
                         m->m_nextpkt = nextrecord;  
                         /*  
                          * If nextrecord == NULL (this is a single chain),  
                          * then sb_lastrecord may not be valid here if m  
                          * was changed earlier.  
                          */  
                         if (nextrecord == NULL) {  
                                 KASSERT(so->so_rcv.sb_mb == m);  
                                 so->so_rcv.sb_lastrecord = m;  
                         }  
                 }  
                 type = m->m_type;                  type = m->m_type;
                 if (type == MT_OOBDATA)                  if (type == MT_OOBDATA)
                         flags |= MSG_OOB;                          flags |= MSG_OOB;
         } else {  
                 if ((flags & MSG_PEEK) == 0) {  
                         KASSERT(so->so_rcv.sb_mb == m);  
                         so->so_rcv.sb_mb = nextrecord;  
                         SB_EMPTY_FIXUP(&so->so_rcv);  
                 }  
         }          }
         SBLASTRECORDCHK(&so->so_rcv, "soreceive 2");          SBLASTRECORDCHK(&so->so_rcv, "soreceive 2");
         SBLASTMBUFCHK(&so->so_rcv, "soreceive 2");          SBLASTMBUFCHK(&so->so_rcv, "soreceive 2");
Line 1252  soreceive(struct socket *so, struct mbuf
Line 1348  soreceive(struct socket *so, struct mbuf
                 if (mp == NULL) {                  if (mp == NULL) {
                         SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");                          SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");
                         SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");                          SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");
                           sounlock(so);
                         splx(s);                          splx(s);
                         error = uiomove(mtod(m, char *) + moff, (int)len, uio);                          error = uiomove(mtod(m, char *) + moff, (int)len, uio);
                         s = splsoftnet();                          s = splsoftnet();
                           solock(so);
                         if (error != 0) {                          if (error != 0) {
                                 /*                                  /*
                                  * If any part of the record has been removed                                   * If any part of the record has been removed
Line 1311  soreceive(struct socket *so, struct mbuf
Line 1409  soreceive(struct socket *so, struct mbuf
                 } else if (flags & MSG_PEEK)                  } else if (flags & MSG_PEEK)
                         moff += len;                          moff += len;
                 else {                  else {
                         if (mp != NULL)                          if (mp != NULL) {
                                 *mp = m_copym(m, 0, len, M_WAIT);                                  mt = m_copym(m, 0, len, M_NOWAIT);
                                   if (__predict_false(mt == NULL)) {
                                           sounlock(so);
                                           mt = m_copym(m, 0, len, M_WAIT);
                                           solock(so);
                                   }
                                   *mp = mt;
                           }
                         m->m_data += len;                          m->m_data += len;
                         m->m_len -= len;                          m->m_len -= len;
                         so->so_rcv.sb_cc -= len;                          so->so_rcv.sb_cc -= len;
Line 1362  soreceive(struct socket *so, struct mbuf
Line 1467  soreceive(struct socket *so, struct mbuf
                         error = sbwait(&so->so_rcv);                          error = sbwait(&so->so_rcv);
                         if (error != 0) {                          if (error != 0) {
                                 sbunlock(&so->so_rcv);                                  sbunlock(&so->so_rcv);
                                   sounlock(so);
                                 splx(s);                                  splx(s);
                                 return 0;                                  return 0;
                         }                          }
Line 1398  soreceive(struct socket *so, struct mbuf
Line 1504  soreceive(struct socket *so, struct mbuf
         if (orig_resid == uio->uio_resid && orig_resid &&          if (orig_resid == uio->uio_resid && orig_resid &&
             (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {              (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
                 sbunlock(&so->so_rcv);                  sbunlock(&so->so_rcv);
                 splx(s);  
                 goto restart;                  goto restart;
         }          }
   
Line 1406  soreceive(struct socket *so, struct mbuf
Line 1511  soreceive(struct socket *so, struct mbuf
                 *flagsp |= flags;                  *flagsp |= flags;
  release:   release:
         sbunlock(&so->so_rcv);          sbunlock(&so->so_rcv);
           sounlock(so);
         splx(s);          splx(s);
         return error;          return error;
 }  }
Line 1414  int
Line 1520  int
 soshutdown(struct socket *so, int how)  soshutdown(struct socket *so, int how)
 {  {
         const struct protosw    *pr;          const struct protosw    *pr;
           int     error;
   
           KASSERT(solocked(so));
   
         pr = so->so_proto;          pr = so->so_proto;
         if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR))          if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR))
                 return (EINVAL);                  return (EINVAL);
   
         if (how == SHUT_RD || how == SHUT_RDWR)          if (how == SHUT_RD || how == SHUT_RDWR) {
                 sorflush(so);                  sorflush(so);
                   error = 0;
           }
         if (how == SHUT_WR || how == SHUT_RDWR)          if (how == SHUT_WR || how == SHUT_RDWR)
                 return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL,                  error = (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL,
                     NULL, NULL, NULL);                      NULL, NULL, NULL);
         return 0;  
           return error;
 }  }
   
 void  void
Line 1432  sorflush(struct socket *so)
Line 1544  sorflush(struct socket *so)
 {  {
         struct sockbuf  *sb, asb;          struct sockbuf  *sb, asb;
         const struct protosw    *pr;          const struct protosw    *pr;
         int             s;  
           KASSERT(solocked(so));
   
         sb = &so->so_rcv;          sb = &so->so_rcv;
         pr = so->so_proto;          pr = so->so_proto;
         sb->sb_flags |= SB_NOINTR;  
         (void) sblock(sb, M_WAITOK);  
         s = splnet();  
         socantrcvmore(so);          socantrcvmore(so);
           sb->sb_flags |= SB_NOINTR;
           (void )sblock(sb, M_WAITOK);
         sbunlock(sb);          sbunlock(sb);
         asb = *sb;          asb = *sb;
         /*          /*
Line 1448  sorflush(struct socket *so)
Line 1560  sorflush(struct socket *so)
          */           */
         memset(&sb->sb_startzero, 0,          memset(&sb->sb_startzero, 0,
             sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));              sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
         splx(s);          if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) {
         if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)                  sounlock(so);
                 (*pr->pr_domain->dom_dispose)(asb.sb_mb);                  (*pr->pr_domain->dom_dispose)(asb.sb_mb);
                   solock(so);
           }
         sbrelease(&asb, so);          sbrelease(&asb, so);
 }  }
   
Line 1571  sosetopt(struct socket *so, int level, i
Line 1685  sosetopt(struct socket *so, int level, i
 {  {
         int error, prerr;          int error, prerr;
   
           solock(so);
         if (level == SOL_SOCKET)          if (level == SOL_SOCKET)
                 error = sosetopt1(so, level, optname, m);                  error = sosetopt1(so, level, optname, m);
         else          else
Line 1587  sosetopt(struct socket *so, int level, i
Line 1702  sosetopt(struct socket *so, int level, i
                         error = prerr;                          error = prerr;
         } else if (m != NULL)          } else if (m != NULL)
                 (void)m_free(m);                  (void)m_free(m);
           sounlock(so);
         return error;          return error;
 }  }
   
Line 1594  int
Line 1710  int
 sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)  sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
 {  {
         struct mbuf     *m;          struct mbuf     *m;
           int             error;
   
           solock(so);
         if (level != SOL_SOCKET) {          if (level != SOL_SOCKET) {
                 if (so->so_proto && so->so_proto->pr_ctloutput) {                  if (so->so_proto && so->so_proto->pr_ctloutput) {
                         return ((*so->so_proto->pr_ctloutput)                          error = ((*so->so_proto->pr_ctloutput)
                                   (PRCO_GETOPT, so, level, optname, mp));                                    (PRCO_GETOPT, so, level, optname, mp));
                 } else                  } else
                         return (ENOPROTOOPT);                          error = (ENOPROTOOPT);
         } else {          } else {
                 m = m_get(M_WAIT, MT_SOOPTS);                  m = m_get(M_WAIT, MT_SOOPTS);
                 m->m_len = sizeof(int);                  m->m_len = sizeof(int);
Line 1669  sogetopt(struct socket *so, int level, i
Line 1787  sogetopt(struct socket *so, int level, i
                         break;                          break;
   
                 default:                  default:
                           sounlock(so);
                         (void)m_free(m);                          (void)m_free(m);
                         return (ENOPROTOOPT);                          return (ENOPROTOOPT);
                 }                  }
                 *mp = m;                  *mp = m;
                 return (0);                  error = 0;
         }          }
   
           sounlock(so);
           return (error);
 }  }
   
 void  void
 sohasoutofband(struct socket *so)  sohasoutofband(struct socket *so)
 {  {
   
         fownsignal(so->so_pgid, SIGURG, POLL_PRI, POLLPRI|POLLRDBAND, so);          fownsignal(so->so_pgid, SIGURG, POLL_PRI, POLLPRI|POLLRDBAND, so);
         selwakeup(&so->so_rcv.sb_sel);          selnotify(&so->so_rcv.sb_sel, POLLPRI | POLLRDBAND, 0);
 }  }
   
 static void  static void
Line 1689  filt_sordetach(struct knote *kn)
Line 1812  filt_sordetach(struct knote *kn)
 {  {
         struct socket   *so;          struct socket   *so;
   
         so = (struct socket *)kn->kn_fp->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
           solock(so);
         SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext);          SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext);
         if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist))          if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist))
                 so->so_rcv.sb_flags &= ~SB_KNOTE;                  so->so_rcv.sb_flags &= ~SB_KNOTE;
           sounlock(so);
 }  }
   
 /*ARGSUSED*/  /*ARGSUSED*/
Line 1700  static int
Line 1825  static int
 filt_soread(struct knote *kn, long hint)  filt_soread(struct knote *kn, long hint)
 {  {
         struct socket   *so;          struct socket   *so;
           int rv;
   
         so = (struct socket *)kn->kn_fp->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
           if (hint != NOTE_SUBMIT)
                   solock(so);
         kn->kn_data = so->so_rcv.sb_cc;          kn->kn_data = so->so_rcv.sb_cc;
         if (so->so_state & SS_CANTRCVMORE) {          if (so->so_state & SS_CANTRCVMORE) {
                 kn->kn_flags |= EV_EOF;                  kn->kn_flags |= EV_EOF;
                 kn->kn_fflags = so->so_error;                  kn->kn_fflags = so->so_error;
                 return (1);                  rv = 1;
         }          } else if (so->so_error)        /* temporary udp error */
         if (so->so_error)       /* temporary udp error */                  rv = 1;
                 return (1);          else if (kn->kn_sfflags & NOTE_LOWAT)
         if (kn->kn_sfflags & NOTE_LOWAT)                  rv = (kn->kn_data >= kn->kn_sdata);
                 return (kn->kn_data >= kn->kn_sdata);          else
         return (kn->kn_data >= so->so_rcv.sb_lowat);                  rv = (kn->kn_data >= so->so_rcv.sb_lowat);
           if (hint != NOTE_SUBMIT)
                   sounlock(so);
           return rv;
 }  }
   
 static void  static void
Line 1720  filt_sowdetach(struct knote *kn)
Line 1851  filt_sowdetach(struct knote *kn)
 {  {
         struct socket   *so;          struct socket   *so;
   
         so = (struct socket *)kn->kn_fp->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
           solock(so);
         SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext);          SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext);
         if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist))          if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist))
                 so->so_snd.sb_flags &= ~SB_KNOTE;                  so->so_snd.sb_flags &= ~SB_KNOTE;
           sounlock(so);
 }  }
   
 /*ARGSUSED*/  /*ARGSUSED*/
Line 1731  static int
Line 1864  static int
 filt_sowrite(struct knote *kn, long hint)  filt_sowrite(struct knote *kn, long hint)
 {  {
         struct socket   *so;          struct socket   *so;
           int rv;
   
         so = (struct socket *)kn->kn_fp->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
           if (hint != NOTE_SUBMIT)
                   solock(so);
         kn->kn_data = sbspace(&so->so_snd);          kn->kn_data = sbspace(&so->so_snd);
         if (so->so_state & SS_CANTSENDMORE) {          if (so->so_state & SS_CANTSENDMORE) {
                 kn->kn_flags |= EV_EOF;                  kn->kn_flags |= EV_EOF;
                 kn->kn_fflags = so->so_error;                  kn->kn_fflags = so->so_error;
                 return (1);                  rv = 1;
         }          } else if (so->so_error)        /* temporary udp error */
         if (so->so_error)       /* temporary udp error */                  rv = 1;
                 return (1);          else if (((so->so_state & SS_ISCONNECTED) == 0) &&
         if (((so->so_state & SS_ISCONNECTED) == 0) &&  
             (so->so_proto->pr_flags & PR_CONNREQUIRED))              (so->so_proto->pr_flags & PR_CONNREQUIRED))
                 return (0);                  rv = 0;
         if (kn->kn_sfflags & NOTE_LOWAT)          else if (kn->kn_sfflags & NOTE_LOWAT)
                 return (kn->kn_data >= kn->kn_sdata);                  rv = (kn->kn_data >= kn->kn_sdata);
         return (kn->kn_data >= so->so_snd.sb_lowat);          else
                   rv = (kn->kn_data >= so->so_snd.sb_lowat);
           if (hint != NOTE_SUBMIT)
                   sounlock(so);
           return rv;
 }  }
   
 /*ARGSUSED*/  /*ARGSUSED*/
Line 1754  static int
Line 1893  static int
 filt_solisten(struct knote *kn, long hint)  filt_solisten(struct knote *kn, long hint)
 {  {
         struct socket   *so;          struct socket   *so;
           int rv;
   
         so = (struct socket *)kn->kn_fp->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
   
         /*          /*
          * Set kn_data to number of incoming connections, not           * Set kn_data to number of incoming connections, not
          * counting partial (incomplete) connections.           * counting partial (incomplete) connections.
          */           */
           if (hint != NOTE_SUBMIT)
                   solock(so);
         kn->kn_data = so->so_qlen;          kn->kn_data = so->so_qlen;
         return (kn->kn_data > 0);          rv = (kn->kn_data > 0);
           if (hint != NOTE_SUBMIT)
                   sounlock(so);
           return rv;
 }  }
   
 static const struct filterops solisten_filtops =  static const struct filterops solisten_filtops =
Line 1778  soo_kqfilter(struct file *fp, struct kno
Line 1923  soo_kqfilter(struct file *fp, struct kno
         struct socket   *so;          struct socket   *so;
         struct sockbuf  *sb;          struct sockbuf  *sb;
   
         so = (struct socket *)kn->kn_fp->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
           solock(so);
         switch (kn->kn_filter) {          switch (kn->kn_filter) {
         case EVFILT_READ:          case EVFILT_READ:
                 if (so->so_options & SO_ACCEPTCONN)                  if (so->so_options & SO_ACCEPTCONN)
Line 1792  soo_kqfilter(struct file *fp, struct kno
Line 1938  soo_kqfilter(struct file *fp, struct kno
                 sb = &so->so_snd;                  sb = &so->so_snd;
                 break;                  break;
         default:          default:
                   sounlock(so);
                 return (EINVAL);                  return (EINVAL);
         }          }
         SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, kn, kn_selnext);          SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, kn, kn_selnext);
         sb->sb_flags |= SB_KNOTE;          sb->sb_flags |= SB_KNOTE;
           sounlock(so);
         return (0);          return (0);
 }  }
   
   static int
   sodopoll(struct socket *so, int events)
   {
           int revents;
   
           revents = 0;
   
           if (events & (POLLIN | POLLRDNORM))
                   if (soreadable(so))
                           revents |= events & (POLLIN | POLLRDNORM);
   
           if (events & (POLLOUT | POLLWRNORM))
                   if (sowritable(so))
                           revents |= events & (POLLOUT | POLLWRNORM);
   
           if (events & (POLLPRI | POLLRDBAND))
                   if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
                           revents |= events & (POLLPRI | POLLRDBAND);
   
           return revents;
   }
   
   int
   sopoll(struct socket *so, int events)
   {
           int revents = 0;
   
   #ifndef DIAGNOSTIC
           /*
            * Do a quick, unlocked check in expectation that the socket
            * will be ready for I/O.  Don't do this check if DIAGNOSTIC,
            * as the solocked() assertions will fail.
            */
           if ((revents = sodopoll(so, events)) != 0)
                   return revents;
   #endif
   
           solock(so);
           if ((revents = sodopoll(so, events)) == 0) {
                   if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
                           selrecord(curlwp, &so->so_rcv.sb_sel);
                           so->so_rcv.sb_flags |= SB_NOTIFY;
                   }
   
                   if (events & (POLLOUT | POLLWRNORM)) {
                           selrecord(curlwp, &so->so_snd.sb_sel);
                           so->so_snd.sb_flags |= SB_NOTIFY;
                   }
           }
           sounlock(so);
   
           return revents;
   }
   
   
 #include <sys/sysctl.h>  #include <sys/sysctl.h>
   
 static int sysctl_kern_somaxkva(SYSCTLFN_PROTO);  static int sysctl_kern_somaxkva(SYSCTLFN_PROTO);

Legend:
Removed from v.1.111.2.12  
changed lines
  Added in v.1.166

CVSweb <webmaster@jp.NetBSD.org>