[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.4 and 1.156

version 1.151.6.4, 2008/09/28 10:40:54 version 1.156, 2008/03/24 12:24:37
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 30 
Line 37 
  */   */
   
 /*  /*
  * 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 65 
Line 70 
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
 #include "opt_inet.h"  
 #include "opt_sock_counters.h"  #include "opt_sock_counters.h"
 #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 86  __KERNEL_RCSID(0, "$NetBSD$");
Line 89  __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 94  __KERNEL_RCSID(0, "$NetBSD$");
Line 98  __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 101  extern const struct fileops socketops;
Line 108  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 129  EVCNT_ATTACH_STATIC(sosend_kvalimit);
Line 135  EVCNT_ATTACH_STATIC(sosend_kvalimit);
   
 static struct callback_entry sokva_reclaimerentry;  static struct callback_entry sokva_reclaimerentry;
   
 #if defined(SOSEND_NO_LOAN) || defined(MULTIPROCESSOR)  #ifdef SOSEND_NO_LOAN
 int sock_loan_thresh = -1;  int sock_loan_thresh = -1;
 #else  #else
 int sock_loan_thresh = 4096;  int sock_loan_thresh = 4096;
Line 269  sodopendfree(void)
Line 275  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 360  sosend_loan(struct socket *so, struct ui
Line 363  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 419  getsombuf(struct socket *so, int type)
Line 423  getsombuf(struct socket *so, int type)
         return m;          return m;
 }  }
   
   struct mbuf *
   m_intopt(struct socket *so, int val)
   {
           struct mbuf *m;
   
           m = getsombuf(so, MT_SOOPTS);
           m->m_len = sizeof(int);
           *mtod(m, int *) = val;
           return m;
   }
   
 void  void
 soinit(void)  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 445  soinit(void)
Line 458  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;          int             error, s;
         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 477  socreate(int dom, struct socket **aso, i
Line 488  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 = soget(true);          so = pool_get(&socket_pool, PR_WAITOK);
           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 488  socreate(int dom, struct socket **aso, i
Line 502  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);
         so->so_egid = kauth_cred_getegid(l->l_cred);  
         so->so_cpid = l->l_proc->p_pid;  
         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;
         }          }
         sounlock(so);          splx(s);
         *aso = so;          *aso = so;
         return 0;          return 0;
 }  }
Line 530  fsocreate(int domain, struct socket **so
Line 535  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, NULL);          error = socreate(domain, &so, type, protocol, l);
         if (error != 0) {          if (error != 0) {
                 fd_abort(curproc, fp, fd);                  fd_abort(curproc, fp, fd);
         } else {          } else {
Line 546  fsocreate(int domain, struct socket **so
Line 551  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     error;          int     s, error;
   
         solock(so);          s = splsoftnet();
         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);
         sounlock(so);          splx(s);
         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     error;          int     s, error;
   
         solock(so);          s = splsoftnet();
         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) {
                 sounlock(so);                  splx(s);
                 return error;                  return error;
         }          }
         if (TAILQ_EMPTY(&so->so_q))          if (TAILQ_EMPTY(&so->so_q))
Line 576  solisten(struct socket *so, int backlog,
Line 576  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);
         sounlock(so);          splx(s);
         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 609  sofree(struct socket *so)
Line 602  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);
         refs = so->so_aborting; /* XXX */          seldestroy(&so->so_rcv.sb_sel);
 #ifdef INET          seldestroy(&so->so_snd.sb_sel);
         /* remove acccept filter if one is present. */          pool_put(&socket_pool, so);
         if (so->so_accf != NULL)  
                 do_setopt_accept_filter(so, NULL);  
 #endif  
         sounlock(so);  
         if (refs == 0)          /* XXX */  
                 soput(so);  
 }  }
   
 /*  /*
Line 633  int
Line 617  int
 soclose(struct socket *so)  soclose(struct socket *so)
 {  {
         struct socket   *so2;          struct socket   *so2;
         int             error;          int             s, error;
         int             error2;  
   
         error = 0;          error = 0;
         solock(so);          s = splsoftnet();               /* conservative */
         if (so->so_options & SO_ACCEPTCONN) {          if (so->so_options & SO_ACCEPTCONN) {
                 do {                  while ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) {
                         while ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) {                          (void) soqremque(so2, 0);
                                 KASSERT(solocked2(so, so2));                          (void) soabort(so2);
                                 (void) soqremque(so2, 0);                  }
                                 /* soabort drops the lock. */                  while ((so2 = TAILQ_FIRST(&so->so_q)) != 0) {
                                 (void) soabort(so2);                          (void) soqremque(so2, 1);
                                 solock(so);                          (void) soabort(so2);
                         }                  }
                         while ((so2 = TAILQ_FIRST(&so->so_q)) != 0) {  
                                 KASSERT(solocked2(so, so2));  
                                 (void) soqremque(so2, 1);  
                                 /* soabort drops the lock. */  
                                 (void) soabort(so2);  
                                 solock(so);  
                         }  
                 } while (!TAILQ_EMPTY(&so->so_q0));  
         }          }
         if (so->so_pcb == 0)          if (so->so_pcb == 0)
                 goto discard;                  goto discard;
Line 668  soclose(struct socket *so)
Line 643  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 = sowait(so, so->so_linger * hz);                                  error = tsleep((void *)&so->so_timeo,
                                                  PSOCK | PCATCH, netcls,
                                                  so->so_linger * hz);
                                 if (error)                                  if (error)
                                         break;                                          break;
                         }                          }
Line 676  soclose(struct socket *so)
Line 653  soclose(struct socket *so)
         }          }
  drop:   drop:
         if (so->so_pcb) {          if (so->so_pcb) {
                 error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,                  int 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 686  soclose(struct socket *so)
Line 663  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 with the socket locked..  Will return with it unlocked.   * Must be called at splsoftnet...
  */   */
 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);  
   
         so->so_aborting++;              /* XXX */          KASSERT(so->so_head == NULL);
         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);
         refs = --so->so_aborting;       /* XXX */          if (error) {
         if (error || (refs == 0)) {  
                 sofree(so);                  sofree(so);
         } else {  
                 sounlock(so);  
         }          }
         return error;          return error;
 }  }
Line 716  soabort(struct socket *so)
Line 687  soabort(struct socket *so)
 int  int
 soaccept(struct socket *so, struct mbuf *nam)  soaccept(struct socket *so, struct mbuf *nam)
 {  {
         int     error;          int     s, 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 731  soaccept(struct socket *so, struct mbuf 
Line 701  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             error;          int             s, 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 756  soconnect(struct socket *so, struct mbuf
Line 726  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     error;          int     s, 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     error;          int     s, error;
   
         KASSERT(solocked(so));  
   
           s = splsoftnet();
         if ((so->so_state & SS_ISCONNECTED) == 0) {          if ((so->so_state & SS_ISCONNECTED) == 0) {
                 error = ENOTCONN;                  error = ENOTCONN;
         } else if (so->so_state & SS_ISDISCONNECTING) {                  goto bad;
           }
           if (so->so_state & SS_ISDISCONNECTING) {
                 error = EALREADY;                  error = EALREADY;
         } else {                  goto bad;
                 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 819  sosend(struct socket *so, struct mbuf *a
Line 793  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 847  sosend(struct socket *so, struct mbuf *a
Line 814  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);
         l->l_ru.ru_msgsnd++;          if (p)
                   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 {
                 if (so->so_state & SS_CANTSENDMORE) {                  s = splsoftnet();
                         error = EPIPE;                  if (so->so_state & SS_CANTSENDMORE)
                         goto release;                          snderr(EPIPE);
                 }  
                 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))
                                         error = ENOTCONN;                                          snderr(ENOTCONN);
                                         goto release;                          } else if (addr == 0)
                                 }                                  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)
                         error = EMSGSIZE;                          snderr(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)
                                 error = EWOULDBLOCK;                                  snderr(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 906  sosend(struct socket *so, struct mbuf *a
Line 870  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 958  sosend(struct socket *so, struct mbuf *a
Line 920  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 970  sosend(struct socket *so, struct mbuf *a
Line 930  sosend(struct socket *so, struct mbuf *a
                                 }                                  }
                         } while (space > 0 && atomic);                          } while (space > 0 && atomic);
   
                         if (so->so_state & SS_CANTSENDMORE) {                          s = splsoftnet();
                                 error = EPIPE;  
                                 goto release;                          if (so->so_state & SS_CANTSENDMORE)
                         }                                  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);                              top, addr, control, curlwp);        /* XXX */
                         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 997  sosend(struct socket *so, struct mbuf *a
Line 960  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 1007  sosend(struct socket *so, struct mbuf *a
Line 968  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 1064  soreceive(struct socket *so, struct mbuf
Line 988  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, *mt;          struct mbuf     *m, **mp;
         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 1092  soreceive(struct socket *so, struct mbuf
Line 1016  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 1110  soreceive(struct socket *so, struct mbuf
Line 1032  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 1185  soreceive(struct socket *so, struct mbuf
Line 1097  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);
                 if (error != 0) {                  splx(s);
                         sounlock(so);                  if (error != 0)
                         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.
          * From this point onward, we maintain 'nextrecord' as a cache of the           * While we process the initial mbufs containing address and control
          * pointer to the next record in the socket buffer.  We must keep the           * info, we save a copy of m->m_nextpkt into nextrecord.
          * 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_proc->p_stats->p_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 1237  soreceive(struct socket *so, struct mbuf
Line 1136  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) {
          * Process one or more MT_CONTROL mbufs present before any data mbufs                          if (controlp != NULL)
          * in the first mbuf chain on the socket buffer.  If MSG_PEEK, we                                  *controlp = m_copy(m, 0, m->m_len);
          * just copy the data; if !MSG_PEEK, we call into the protocol to                          m = m->m_next;
          * perform externalization (or freeing if controlp == NULL).                  } else {
          */                          sbfree(&so->so_rcv, m);
         if (__predict_false(m != NULL && m->m_type == MT_CONTROL)) {                          mbuf_removed = 1;
                 struct mbuf *cm = NULL, *cmn;                          if (controlp != NULL) {
                 struct mbuf **cme = &cm;                                  if (dom->dom_externalize && l &&
                                       mtod(m, struct cmsghdr *)->cmsg_type ==
                 do {                                      SCM_RIGHTS)
                         if (flags & MSG_PEEK) {                                          error = (*dom->dom_externalize)(m, l);
                                 if (controlp != NULL) {                                  *controlp = m;
                                         *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 != NULL &&                                  if (dom->dom_dispose &&
                                     type == SCM_RIGHTS) {                                      mtod(m, struct cmsghdr *)->cmsg_type == SCM_RIGHTS)
                                         sounlock(so);                                          (*dom->dom_dispose)(m);
                                         (*dom->dom_dispose)(cm);                                  MFREE(m, so->so_rcv.sb_mb);
                                         solock(so);                                  m = so->so_rcv.sb_mb;
                                 }  
                                 m_freem(cm);  
                         }                          }
                 }                  }
                 if (m != NULL)                  if (controlp != NULL) {
                         nextrecord = so->so_rcv.sb_mb->m_nextpkt;                          orig_resid = 0;
                 else                          controlp = &(*controlp)->m_next;
                         nextrecord = so->so_rcv.sb_mb;                  }
                 orig_resid = 0;  
         }          }
   
         /* If m is non-NULL, we have some data to read. */          /*
         if (__predict_true(m != NULL)) {           * If m is non-NULL, we have some data to read.  From now on,
            * 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 1344  soreceive(struct socket *so, struct mbuf
Line 1234  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 1405  soreceive(struct socket *so, struct mbuf
Line 1293  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)
                                 mt = m_copym(m, 0, len, M_NOWAIT);                                  *mp = m_copym(m, 0, len, M_WAIT);
                                 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 1463  soreceive(struct socket *so, struct mbuf
Line 1344  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 1500  soreceive(struct socket *so, struct mbuf
Line 1380  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 1507  soreceive(struct socket *so, struct mbuf
Line 1388  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 1516  int
Line 1396  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)
                 error = (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL,                  return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL,
                     NULL, NULL, NULL);                      NULL, NULL, NULL);
           return 0;
         return error;  
 }  }
   
 void  void
Line 1540  sorflush(struct socket *so)
Line 1414  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;
         socantrcvmore(so);  
         sb->sb_flags |= SB_NOINTR;          sb->sb_flags |= SB_NOINTR;
         (void )sblock(sb, M_WAITOK);          (void) sblock(sb, M_WAITOK);
           s = splnet();
           socantrcvmore(so);
         sbunlock(sb);          sbunlock(sb);
         asb = *sb;          asb = *sb;
         /*          /*
Line 1556  sorflush(struct socket *so)
Line 1430  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));
         if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) {          splx(s);
                 sounlock(so);          if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
                 (*pr->pr_domain->dom_dispose)(asb.sb_mb);                  (*pr->pr_domain->dom_dispose)(asb.sb_mb);
                 solock(so);  
         }  
         sbrelease(&asb, so);          sbrelease(&asb, so);
 }  }
   
 /*  
  * internal set SOL_SOCKET options  
  */  
 static int  static int
 sosetopt1(struct socket *so, const struct sockopt *sopt)  sosetopt1(struct socket *so, int level, int optname, struct mbuf *m)
 {  {
         int error, optval;          int optval, val;
         struct linger l;          struct linger   *l;
         struct timeval tv;          struct sockbuf  *sb;
           struct timeval *tv;
   
         switch (sopt->sopt_name) {          switch (optname) {
   
 #ifdef INET          case SO_LINGER:
         case SO_ACCEPTFILTER:                  if (m == NULL || m->m_len != sizeof(struct linger))
                 error = do_setopt_accept_filter(so, sopt);                          return EINVAL;
                 if (error)                  l = mtod(m, struct linger *);
                         return error;                  if (l->l_linger < 0 || l->l_linger > USHRT_MAX ||
                 break;                      l->l_linger > (INT_MAX / hz))
 #endif  
   
         case SO_LINGER:  
                 error = sockopt_get(sopt, &l, sizeof(l));  
                 if (error)  
                         return (error);  
   
                 if (l.l_linger < 0 || l.l_linger > USHRT_MAX ||  
                     l.l_linger > (INT_MAX / hz))  
                         return EDOM;                          return EDOM;
                 so->so_linger = l.l_linger;                  so->so_linger = l->l_linger;
                 if (l.l_onoff)                  if (l->l_onoff)
                         so->so_options |= SO_LINGER;                          so->so_options |= SO_LINGER;
                 else                  else
                         so->so_options &= ~SO_LINGER;                          so->so_options &= ~SO_LINGER;
                   break;
                 break;  
   
         case SO_DEBUG:          case SO_DEBUG:
         case SO_KEEPALIVE:          case SO_KEEPALIVE:
Line 1609  sosetopt1(struct socket *so, const struc
Line 1469  sosetopt1(struct socket *so, const struc
         case SO_REUSEPORT:          case SO_REUSEPORT:
         case SO_OOBINLINE:          case SO_OOBINLINE:
         case SO_TIMESTAMP:          case SO_TIMESTAMP:
                 error = sockopt_getint(sopt, &optval);                  if (m == NULL || m->m_len < sizeof(int))
                 if (error)                          return EINVAL;
                         return (error);                  if (*mtod(m, int *))
                           so->so_options |= optname;
                 if (optval)  
                         so->so_options |= sopt->sopt_name;  
                 else                  else
                         so->so_options &= ~sopt->sopt_name;                          so->so_options &= ~optname;
                 break;                  break;
   
         case SO_SNDBUF:          case SO_SNDBUF:
         case SO_RCVBUF:          case SO_RCVBUF:
         case SO_SNDLOWAT:          case SO_SNDLOWAT:
         case SO_RCVLOWAT:          case SO_RCVLOWAT:
                 error = sockopt_getint(sopt, &optval);                  if (m == NULL || m->m_len < sizeof(int))
                 if (error)                          return EINVAL;
                         return (error);  
   
                 /*                  /*
                  * Values < 1 make no sense for any of these                   * Values < 1 make no sense for any of these
                  * options, so disallow them.                   * options, so disallow them.
                  */                   */
                   optval = *mtod(m, int *);
                 if (optval < 1)                  if (optval < 1)
                         return EINVAL;                          return EINVAL;
   
                 switch (sopt->sopt_name) {                  switch (optname) {
                 case SO_SNDBUF:  
                         if (sbreserve(&so->so_snd, (u_long)optval, so) == 0)  
                                 return ENOBUFS;  
   
                         so->so_snd.sb_flags &= ~SB_AUTOSIZE;  
                         break;  
   
                   case SO_SNDBUF:
                 case SO_RCVBUF:                  case SO_RCVBUF:
                         if (sbreserve(&so->so_rcv, (u_long)optval, so) == 0)                          sb = (optname == SO_SNDBUF) ?
                               &so->so_snd : &so->so_rcv;
                           if (sbreserve(sb, (u_long)optval, so) == 0)
                                 return ENOBUFS;                                  return ENOBUFS;
                           sb->sb_flags &= ~SB_AUTOSIZE;
                         so->so_rcv.sb_flags &= ~SB_AUTOSIZE;  
                         break;                          break;
   
                 /*                  /*
Line 1654  sosetopt1(struct socket *so, const struc
Line 1508  sosetopt1(struct socket *so, const struc
                  * the high-water.                   * the high-water.
                  */                   */
                 case SO_SNDLOWAT:                  case SO_SNDLOWAT:
                         if (optval > so->so_snd.sb_hiwat)                          so->so_snd.sb_lowat =
                                 optval = so->so_snd.sb_hiwat;                              (optval > so->so_snd.sb_hiwat) ?
                               so->so_snd.sb_hiwat : optval;
                         so->so_snd.sb_lowat = optval;  
                         break;                          break;
   
                 case SO_RCVLOWAT:                  case SO_RCVLOWAT:
                         if (optval > so->so_rcv.sb_hiwat)                          so->so_rcv.sb_lowat =
                                 optval = so->so_rcv.sb_hiwat;                              (optval > so->so_rcv.sb_hiwat) ?
                               so->so_rcv.sb_hiwat : optval;
                         so->so_rcv.sb_lowat = optval;  
                         break;                          break;
                 }                  }
                 break;                  break;
   
         case SO_SNDTIMEO:          case SO_SNDTIMEO:
         case SO_RCVTIMEO:          case SO_RCVTIMEO:
                 error = sockopt_get(sopt, &tv, sizeof(tv));                  if (m == NULL || m->m_len < sizeof(*tv))
                 if (error)                          return EINVAL;
                         return (error);                  tv = mtod(m, struct timeval *);
                   if (tv->tv_sec > (INT_MAX - tv->tv_usec / tick) / hz)
                 if (tv.tv_sec > (INT_MAX - tv.tv_usec / tick) / hz)  
                         return EDOM;                          return EDOM;
                   val = tv->tv_sec * hz + tv->tv_usec / tick;
                   if (val == 0 && tv->tv_usec != 0)
                           val = 1;
   
                 optval = tv.tv_sec * hz + tv.tv_usec / tick;                  switch (optname) {
                 if (optval == 0 && tv.tv_usec != 0)  
                         optval = 1;  
   
                 switch (sopt->sopt_name) {  
                 case SO_SNDTIMEO:                  case SO_SNDTIMEO:
                         so->so_snd.sb_timeo = optval;                          so->so_snd.sb_timeo = val;
                         break;                          break;
                 case SO_RCVTIMEO:                  case SO_RCVTIMEO:
                         so->so_rcv.sb_timeo = optval;                          so->so_rcv.sb_timeo = val;
                         break;                          break;
                 }                  }
                 break;                  break;
Line 1699  sosetopt1(struct socket *so, const struc
Line 1549  sosetopt1(struct socket *so, const struc
 }  }
   
 int  int
 sosetopt(struct socket *so, struct sockopt *sopt)  sosetopt(struct socket *so, int level, int optname, struct mbuf *m)
 {  {
         int error, prerr;          int error, prerr;
   
         solock(so);          if (level == SOL_SOCKET)
         if (sopt->sopt_level == SOL_SOCKET)                  error = sosetopt1(so, level, optname, m);
                 error = sosetopt1(so, sopt);  
         else          else
                 error = ENOPROTOOPT;                  error = ENOPROTOOPT;
   
         if ((error == 0 || error == ENOPROTOOPT) &&          if ((error == 0 || error == ENOPROTOOPT) &&
             so->so_proto != NULL && so->so_proto->pr_ctloutput != NULL) {              so->so_proto != NULL && so->so_proto->pr_ctloutput != NULL) {
                 /* give the protocol stack a shot */                  /* give the protocol stack a shot */
                 prerr = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, sopt);                  prerr = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, level,
                       optname, &m);
                 if (prerr == 0)                  if (prerr == 0)
                         error = 0;                          error = 0;
                 else if (prerr != ENOPROTOOPT)                  else if (prerr != ENOPROTOOPT)
                         error = prerr;                          error = prerr;
         }          } else if (m != NULL)
         sounlock(so);                  (void)m_free(m);
         return error;          return error;
 }  }
   
 /*  
  * so_setsockopt() is a wrapper providing a sockopt structure for sosetopt()  
  */  
 int  int
 so_setsockopt(struct lwp *l, struct socket *so, int level, int name,  sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
     const void *val, size_t valsize)  
 {  {
         struct sockopt sopt;          struct mbuf     *m;
         int error;  
   
         KASSERT(valsize == 0 || val != NULL);  
   
         sockopt_init(&sopt, level, name, valsize);  
         sockopt_set(&sopt, val, valsize);  
   
         error = sosetopt(so, &sopt);          if (level != SOL_SOCKET) {
   
         sockopt_destroy(&sopt);  
   
         return error;  
 }  
   
 /*  
  * internal get SOL_SOCKET options  
  */  
 static int  
 sogetopt1(struct socket *so, struct sockopt *sopt)  
 {  
         int error, optval;  
         struct linger l;  
         struct timeval tv;  
   
         switch (sopt->sopt_name) {  
   
 #ifdef INET  
         case SO_ACCEPTFILTER:  
                 error = do_getopt_accept_filter(so, sopt);  
                 break;  
 #endif  
   
         case SO_LINGER:  
                 l.l_onoff = (so->so_options & SO_LINGER) ? 1 : 0;  
                 l.l_linger = so->so_linger;  
   
                 error = sockopt_set(sopt, &l, sizeof(l));  
                 break;  
   
         case SO_USELOOPBACK:  
         case SO_DONTROUTE:  
         case SO_DEBUG:  
         case SO_KEEPALIVE:  
         case SO_REUSEADDR:  
         case SO_REUSEPORT:  
         case SO_BROADCAST:  
         case SO_OOBINLINE:  
         case SO_TIMESTAMP:  
                 error = sockopt_setint(sopt,  
                     (so->so_options & sopt->sopt_name) ? 1 : 0);  
                 break;  
   
         case SO_TYPE:  
                 error = sockopt_setint(sopt, so->so_type);  
                 break;  
   
         case SO_ERROR:  
                 error = sockopt_setint(sopt, so->so_error);  
                 so->so_error = 0;  
                 break;  
   
         case SO_SNDBUF:  
                 error = sockopt_setint(sopt, so->so_snd.sb_hiwat);  
                 break;  
   
         case SO_RCVBUF:  
                 error = sockopt_setint(sopt, so->so_rcv.sb_hiwat);  
                 break;  
   
         case SO_SNDLOWAT:  
                 error = sockopt_setint(sopt, so->so_snd.sb_lowat);  
                 break;  
   
         case SO_RCVLOWAT:  
                 error = sockopt_setint(sopt, so->so_rcv.sb_lowat);  
                 break;  
   
         case SO_SNDTIMEO:  
         case SO_RCVTIMEO:  
                 optval = (sopt->sopt_name == SO_SNDTIMEO ?  
                      so->so_snd.sb_timeo : so->so_rcv.sb_timeo);  
   
                 tv.tv_sec = optval / hz;  
                 tv.tv_usec = (optval % hz) * tick;  
   
                 error = sockopt_set(sopt, &tv, sizeof(tv));  
                 break;  
   
         case SO_OVERFLOWED:  
                 error = sockopt_setint(sopt, so->so_rcv.sb_overflowed);  
                 break;  
   
         default:  
                 error = ENOPROTOOPT;  
                 break;  
         }  
   
         return (error);  
 }  
   
 int  
 sogetopt(struct socket *so, struct sockopt *sopt)  
 {  
         int             error;  
   
         solock(so);  
         if (sopt->sopt_level != SOL_SOCKET) {  
                 if (so->so_proto && so->so_proto->pr_ctloutput) {                  if (so->so_proto && so->so_proto->pr_ctloutput) {
                         error = ((*so->so_proto->pr_ctloutput)                          return ((*so->so_proto->pr_ctloutput)
                             (PRCO_GETOPT, so, sopt));                                    (PRCO_GETOPT, so, level, optname, mp));
                 } else                  } else
                         error = (ENOPROTOOPT);                          return (ENOPROTOOPT);
         } else {          } else {
                 error = sogetopt1(so, sopt);                  m = m_get(M_WAIT, MT_SOOPTS);
         }                  m->m_len = sizeof(int);
         sounlock(so);  
         return (error);  
 }  
   
 /*                  switch (optname) {
  * alloc sockopt data buffer buffer  
  *      - will be released at destroy  
  */  
 static void  
 sockopt_alloc(struct sockopt *sopt, size_t len)  
 {  
   
         KASSERT(sopt->sopt_size == 0);  
   
         if (len > sizeof(sopt->sopt_buf))                  case SO_LINGER:
                 sopt->sopt_data = malloc(len, M_SOOPTS, M_WAITOK | M_ZERO);                          m->m_len = sizeof(struct linger);
         else                          mtod(m, struct linger *)->l_onoff =
                 sopt->sopt_data = sopt->sopt_buf;                              (so->so_options & SO_LINGER) ? 1 : 0;
                           mtod(m, struct linger *)->l_linger = so->so_linger;
         sopt->sopt_size = len;                          break;
 }  
   
 /*  
  * initialise sockopt storage  
  */  
 void  
 sockopt_init(struct sockopt *sopt, int level, int name, size_t size)  
 {  
   
         memset(sopt, 0, sizeof(*sopt));  
   
         sopt->sopt_level = level;  
         sopt->sopt_name = name;  
         sockopt_alloc(sopt, size);  
 }  
   
 /*  
  * destroy sockopt storage  
  *      - will release any held memory references  
  */  
 void  
 sockopt_destroy(struct sockopt *sopt)  
 {  
   
         if (sopt->sopt_data != sopt->sopt_buf)  
                 free(sopt->sopt_data, M_SOOPTS);  
   
         memset(sopt, 0, sizeof(*sopt));  
 }  
   
 /*  
  * set sockopt value  
  *      - value is copied into sockopt  
  *      - memory is allocated when necessary  
  */  
 int  
 sockopt_set(struct sockopt *sopt, const void *buf, size_t len)  
 {  
   
         if (sopt->sopt_size == 0)  
                 sockopt_alloc(sopt, len);  
   
         KASSERT(sopt->sopt_size == len);  
         memcpy(sopt->sopt_data, buf, len);  
         return 0;  
 }  
   
 /*  
  * common case of set sockopt integer value  
  */  
 int  
 sockopt_setint(struct sockopt *sopt, int val)  
 {  
   
         return sockopt_set(sopt, &val, sizeof(int));  
 }  
   
 /*  
  * get sockopt value  
  *      - correct size must be given  
  */  
 int  
 sockopt_get(const struct sockopt *sopt, void *buf, size_t len)  
 {  
   
         if (sopt->sopt_size != len)  
                 return EINVAL;  
   
         memcpy(buf, sopt->sopt_data, len);                  case SO_USELOOPBACK:
         return 0;                  case SO_DONTROUTE:
 }                  case SO_DEBUG:
                   case SO_KEEPALIVE:
                   case SO_REUSEADDR:
                   case SO_REUSEPORT:
                   case SO_BROADCAST:
                   case SO_OOBINLINE:
                   case SO_TIMESTAMP:
                           *mtod(m, int *) = (so->so_options & optname) ? 1 : 0;
                           break;
   
 /*                  case SO_TYPE:
  * common case of get sockopt integer value                          *mtod(m, int *) = so->so_type;
  */                          break;
 int  
 sockopt_getint(const struct sockopt *sopt, int *valp)  
 {  
   
         return sockopt_get(sopt, valp, sizeof(int));                  case SO_ERROR:
 }                          *mtod(m, int *) = so->so_error;
                           so->so_error = 0;
                           break;
   
 /*                  case SO_SNDBUF:
  * set sockopt value from mbuf                          *mtod(m, int *) = so->so_snd.sb_hiwat;
  *      - ONLY for legacy code                          break;
  *      - mbuf is released by sockopt  
  */  
 int  
 sockopt_setmbuf(struct sockopt *sopt, struct mbuf *m)  
 {  
         size_t len;  
   
         len = m_length(m);                  case SO_RCVBUF:
                           *mtod(m, int *) = so->so_rcv.sb_hiwat;
                           break;
   
         if (sopt->sopt_size == 0)                  case SO_SNDLOWAT:
                 sockopt_alloc(sopt, len);                          *mtod(m, int *) = so->so_snd.sb_lowat;
                           break;
   
         KASSERT(sopt->sopt_size == len);                  case SO_RCVLOWAT:
         m_copydata(m, 0, len, sopt->sopt_data);                          *mtod(m, int *) = so->so_rcv.sb_lowat;
         m_freem(m);                          break;
   
         return 0;                  case SO_SNDTIMEO:
 }                  case SO_RCVTIMEO:
                       {
                           int val = (optname == SO_SNDTIMEO ?
                                so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
   
                           m->m_len = sizeof(struct timeval);
                           mtod(m, struct timeval *)->tv_sec = val / hz;
                           mtod(m, struct timeval *)->tv_usec =
                               (val % hz) * tick;
                           break;
                       }
   
 /*                  case SO_OVERFLOWED:
  * get sockopt value into mbuf                          *mtod(m, int *) = so->so_rcv.sb_overflowed;
  *      - ONLY for legacy code                          break;
  *      - mbuf to be released by the caller  
  */  
 struct mbuf *  
 sockopt_getmbuf(const struct sockopt *sopt)  
 {  
         struct mbuf *m;  
   
         m = m_get(M_WAIT, MT_SOOPTS);                  default:
         if (m == NULL)                          (void)m_free(m);
                 return NULL;                          return (ENOPROTOOPT);
                   }
         m->m_len = MLEN;                  *mp = m;
         m_copyback(m, 0, sopt->sopt_size, sopt->sopt_data);                  return (0);
         if (m_length(m) != max(sopt->sopt_size, MLEN)) {  
                 m_freem(m);  
                 return NULL;  
         }          }
         m->m_len = min(sopt->sopt_size, MLEN);  
   
         return m;  
 }  }
   
 void  void
Line 2008  filt_sordetach(struct knote *kn)
Line 1673  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 2020  static int
Line 1683  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;
                 rv = 1;                  return (1);
         } else if (so->so_error)        /* temporary udp error */          }
                 rv = 1;          if (so->so_error)       /* temporary udp error */
         else if (kn->kn_sfflags & NOTE_LOWAT)                  return (1);
                 rv = (kn->kn_data >= kn->kn_sdata);          if (kn->kn_sfflags & NOTE_LOWAT)
         else                  return (kn->kn_data >= kn->kn_sdata);
                 rv = (kn->kn_data >= so->so_rcv.sb_lowat);          return (kn->kn_data >= so->so_rcv.sb_lowat);
         if (hint != NOTE_SUBMIT)  
                 sounlock(so);  
         return rv;  
 }  }
   
 static void  static void
Line 2047  filt_sowdetach(struct knote *kn)
Line 1704  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 2059  static int
Line 1714  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;
                 rv = 1;                  return (1);
         } else if (so->so_error)        /* temporary udp error */          }
                 rv = 1;          if (so->so_error)       /* temporary udp error */
         else if (((so->so_state & SS_ISCONNECTED) == 0) &&                  return (1);
           if (((so->so_state & SS_ISCONNECTED) == 0) &&
             (so->so_proto->pr_flags & PR_CONNREQUIRED))              (so->so_proto->pr_flags & PR_CONNREQUIRED))
                 rv = 0;                  return (0);
         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_snd.sb_lowat);
                 rv = (kn->kn_data >= so->so_snd.sb_lowat);  
         if (hint != NOTE_SUBMIT)  
                 sounlock(so);  
         return rv;  
 }  }
   
 /*ARGSUSED*/  /*ARGSUSED*/
Line 2088  static int
Line 1737  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 2096  filt_solisten(struct knote *kn, long hin
Line 1744  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;
         rv = (kn->kn_data > 0);          return (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 2119  soo_kqfilter(struct file *fp, struct kno
Line 1762  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 2133  soo_kqfilter(struct file *fp, struct kno
Line 1775  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 2168  int
Line 1808  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  
   
         solock(so);          KERNEL_LOCK(1, curlwp);
           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_NOTIFY;                          so->so_rcv.sb_flags |= SB_SEL;
                 }                  }
   
                 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_NOTIFY;                          so->so_snd.sb_flags |= SB_SEL;
                 }                  }
         }          }
         sounlock(so);  
           splx(s);
           KERNEL_UNLOCK_ONE(curlwp);
   
         return revents;          return revents;
 }  }

Legend:
Removed from v.1.151.6.4  
changed lines
  Added in v.1.156

CVSweb <webmaster@jp.NetBSD.org>