[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.151.6.1 and 1.151.6.2

version 1.151.6.1, 2008/04/03 12:43:05 version 1.151.6.2, 2008/06/02 13:24:13
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 74  __KERNEL_RCSID(0, "$NetBSD$");
Line 69  __KERNEL_RCSID(0, "$NetBSD$");
 #include "opt_sosend_loan.h"  #include "opt_sosend_loan.h"
 #include "opt_mbuftrace.h"  #include "opt_mbuftrace.h"
 #include "opt_somaxkva.h"  #include "opt_somaxkva.h"
   #include "opt_multiprocessor.h" /* XXX */
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
Line 89  __KERNEL_RCSID(0, "$NetBSD$");
Line 85  __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 93  __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 100  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 135  EVCNT_ATTACH_STATIC(sosend_kvalimit);
Line 128  EVCNT_ATTACH_STATIC(sosend_kvalimit);
   
 static struct callback_entry sokva_reclaimerentry;  static struct callback_entry sokva_reclaimerentry;
   
 #ifdef SOSEND_NO_LOAN  #if defined(SOSEND_NO_LOAN) || defined(MULTIPROCESSOR)
 int sock_loan_thresh = -1;  int sock_loan_thresh = -1;
 #else  #else
 int sock_loan_thresh = 4096;  int sock_loan_thresh = 4096;
Line 275  sodopendfree(void)
Line 268  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 363  sosend_loan(struct socket *so, struct ui
Line 359  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 439  soinit(void)
Line 434  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 458  soinit(void)
Line 455  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 488  socreate(int dom, struct socket **aso, i
Line 487  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 502  socreate(int dom, struct socket **aso, i
Line 498  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 535  fsocreate(int domain, struct socket **so
Line 538  fsocreate(int domain, struct socket **so
         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) {
                 fd_abort(curproc, fp, fd);                  fd_abort(curproc, fp, fd);
         } else {          } else {
Line 551  fsocreate(int domain, struct socket **so
Line 554  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 |          if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING |
             SS_ISDISCONNECTING)) != 0)              SS_ISDISCONNECTING)) != 0) {
                   sounlock(so);
                 return (EOPNOTSUPP);                  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 579  solisten(struct socket *so, int backlog,
Line 584  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 605  sofree(struct socket *so)
Line 617  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 620  int
Line 636  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 646  soclose(struct socket *so)
Line 673  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 656  soclose(struct socket *so)
Line 681  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 666  soclose(struct socket *so)
Line 691  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 690  soabort(struct socket *so)
Line 721  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 704  soaccept(struct socket *so, struct mbuf 
Line 736  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 729  soconnect(struct socket *so, struct mbuf
Line 761  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 796  sosend(struct socket *so, struct mbuf *a
Line 824  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 817  sosend(struct socket *so, struct mbuf *a
Line 852  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 (l)          l->l_ru.ru_msgsnd++;
                 l->l_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 873  sosend(struct socket *so, struct mbuf *a
Line 911  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 923  sosend(struct socket *so, struct mbuf *a
Line 963  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 933  sosend(struct socket *so, struct mbuf *a
Line 975  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 963  sosend(struct socket *so, struct mbuf *a
Line 1002  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 971  sosend(struct socket *so, struct mbuf *a
Line 1012  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 991  soreceive(struct socket *so, struct mbuf
Line 1069  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 1019  soreceive(struct socket *so, struct mbuf
Line 1097  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 1035  soreceive(struct socket *so, struct mbuf
Line 1115  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 1100  soreceive(struct socket *so, struct mbuf
Line 1190  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_ru.ru_msgrcv++;                  l->l_ru.ru_msgrcv++;
Line 1139  soreceive(struct socket *so, struct mbuf
Line 1242  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 1237  soreceive(struct socket *so, struct mbuf
Line 1349  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 1296  soreceive(struct socket *so, struct mbuf
Line 1410  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 1347  soreceive(struct socket *so, struct mbuf
Line 1468  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 1383  soreceive(struct socket *so, struct mbuf
Line 1505  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 1391  soreceive(struct socket *so, struct mbuf
Line 1512  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 1399  int
Line 1521  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 1417  sorflush(struct socket *so)
Line 1545  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 1433  sorflush(struct socket *so)
Line 1561  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 1556  sosetopt(struct socket *so, int level, i
Line 1686  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 1572  sosetopt(struct socket *so, int level, i
Line 1703  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 1579  int
Line 1711  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 1654  sogetopt(struct socket *so, int level, i
Line 1788  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
Line 1676  filt_sordetach(struct knote *kn)
Line 1814  filt_sordetach(struct knote *kn)
         struct socket   *so;          struct socket   *so;
   
         so = ((file_t *)kn->kn_obj)->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 1686  static int
Line 1826  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 = ((file_t *)kn->kn_obj)->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 1707  filt_sowdetach(struct knote *kn)
Line 1853  filt_sowdetach(struct knote *kn)
         struct socket   *so;          struct socket   *so;
   
         so = ((file_t *)kn->kn_obj)->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 1717  static int
Line 1865  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 = ((file_t *)kn->kn_obj)->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 1740  static int
Line 1894  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 = ((file_t *)kn->kn_obj)->f_data;          so = ((file_t *)kn->kn_obj)->f_data;
   
Line 1747  filt_solisten(struct knote *kn, long hin
Line 1902  filt_solisten(struct knote *kn, long hin
          * 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 1765  soo_kqfilter(struct file *fp, struct kno
Line 1925  soo_kqfilter(struct file *fp, struct kno
         struct sockbuf  *sb;          struct sockbuf  *sb;
   
         so = ((file_t *)kn->kn_obj)->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 1778  soo_kqfilter(struct file *fp, struct kno
Line 1939  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);
 }  }
   
Line 1811  int
Line 1974  int
 sopoll(struct socket *so, int events)  sopoll(struct socket *so, int events)
 {  {
         int revents = 0;          int revents = 0;
         int s;  
   
   #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)          if ((revents = sodopoll(so, events)) != 0)
                 return revents;                  return revents;
   #endif
   
         KERNEL_LOCK(1, curlwp);          solock(so);
         s = splsoftnet();  
   
         if ((revents = sodopoll(so, events)) == 0) {          if ((revents = sodopoll(so, events)) == 0) {
                 if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {                  if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
                         selrecord(curlwp, &so->so_rcv.sb_sel);                          selrecord(curlwp, &so->so_rcv.sb_sel);
                         so->so_rcv.sb_flags |= SB_SEL;                          so->so_rcv.sb_flags |= SB_NOTIFY;
                 }                  }
   
                 if (events & (POLLOUT | POLLWRNORM)) {                  if (events & (POLLOUT | POLLWRNORM)) {
                         selrecord(curlwp, &so->so_snd.sb_sel);                          selrecord(curlwp, &so->so_snd.sb_sel);
                         so->so_snd.sb_flags |= SB_SEL;                          so->so_snd.sb_flags |= SB_NOTIFY;
                 }                  }
         }          }
           sounlock(so);
         splx(s);  
         KERNEL_UNLOCK_ONE(curlwp);  
   
         return revents;          return revents;
 }  }

Legend:
Removed from v.1.151.6.1  
changed lines
  Added in v.1.151.6.2

CVSweb <webmaster@jp.NetBSD.org>