version 1.228, 2014/07/30 10:04:26 |
version 1.253, 2017/05/01 10:00:43 |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#ifdef _KERNEL_OPT |
#include "opt_compat_netbsd.h" |
#include "opt_compat_netbsd.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 "opt_multiprocessor.h" /* XXX */ |
|
#include "opt_sctp.h" |
|
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
Line 292 sopendfree_thread(void *v) |
|
Line 295 sopendfree_thread(void *v) |
|
|
|
for (; m != NULL; m = next) { |
for (; m != NULL; m = next) { |
next = m->m_next; |
next = m->m_next; |
KASSERT((~m->m_flags & (M_EXT|M_EXT_PAGES)) == 0); |
KASSERT((~m->m_flags & (M_EXT|M_EXT_PAGES)) == |
|
0); |
KASSERT(m->m_ext.ext_refcnt == 0); |
KASSERT(m->m_ext.ext_refcnt == 0); |
|
|
rv += m->m_ext.ext_size; |
rv += m->m_ext.ext_size; |
Line 600 fsocreate(int domain, struct socket **so |
|
Line 604 fsocreate(int domain, struct socket **so |
|
if (flags & SOCK_NONBLOCK) { |
if (flags & SOCK_NONBLOCK) { |
so->so_state |= SS_NBIO; |
so->so_state |= SS_NBIO; |
} |
} |
fp->f_data = so; |
fp->f_socket = so; |
fd_affix(curproc, fp, fd); |
fd_affix(curproc, fp, fd); |
|
|
if (sop != NULL) { |
if (sop != NULL) { |
Line 624 sofamily(const struct socket *so) |
|
Line 628 sofamily(const struct socket *so) |
|
} |
} |
|
|
int |
int |
sobind(struct socket *so, struct mbuf *nam, struct lwp *l) |
sobind(struct socket *so, struct sockaddr *nam, struct lwp *l) |
{ |
{ |
int error; |
int error; |
|
|
solock(so); |
solock(so); |
error = (*so->so_proto->pr_usrreqs->pr_bind)(so, nam); |
if (nam->sa_family != so->so_proto->pr_domain->dom_family) { |
|
sounlock(so); |
|
return EAFNOSUPPORT; |
|
} |
|
error = (*so->so_proto->pr_usrreqs->pr_bind)(so, nam, l); |
sounlock(so); |
sounlock(so); |
return error; |
return error; |
} |
} |
|
|
solisten(struct socket *so, int backlog, struct lwp *l) |
solisten(struct socket *so, int backlog, struct lwp *l) |
{ |
{ |
int error; |
int error; |
|
short oldopt, oldqlimit; |
|
|
solock(so); |
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); |
sounlock(so); |
return EINVAL; |
return EINVAL; |
} |
} |
error = (*so->so_proto->pr_usrreqs->pr_listen)(so); |
oldopt = so->so_options; |
if (error != 0) { |
oldqlimit = so->so_qlimit; |
sounlock(so); |
|
return error; |
|
} |
|
if (TAILQ_EMPTY(&so->so_q)) |
if (TAILQ_EMPTY(&so->so_q)) |
so->so_options |= SO_ACCEPTCONN; |
so->so_options |= SO_ACCEPTCONN; |
if (backlog < 0) |
if (backlog < 0) |
backlog = 0; |
backlog = 0; |
so->so_qlimit = min(backlog, somaxconn); |
so->so_qlimit = min(backlog, somaxconn); |
|
|
|
error = (*so->so_proto->pr_usrreqs->pr_listen)(so, l); |
|
if (error != 0) { |
|
so->so_options = oldopt; |
|
so->so_qlimit = oldqlimit; |
|
sounlock(so); |
|
return error; |
|
} |
sounlock(so); |
sounlock(so); |
return 0; |
return 0; |
} |
} |
Line 773 soabort(struct socket *so) |
|
Line 787 soabort(struct socket *so) |
|
{ |
{ |
u_int refs; |
u_int refs; |
int error; |
int error; |
|
|
KASSERT(solocked(so)); |
KASSERT(solocked(so)); |
KASSERT(so->so_head == NULL); |
KASSERT(so->so_head == NULL); |
|
|
so->so_aborting++; /* XXX */ |
so->so_aborting++; /* XXX */ |
error = (*so->so_proto->pr_usrreqs->pr_generic)(so, |
error = (*so->so_proto->pr_usrreqs->pr_abort)(so); |
PRU_ABORT, NULL, NULL, NULL, NULL); |
|
refs = --so->so_aborting; /* XXX */ |
refs = --so->so_aborting; /* XXX */ |
if (error || (refs == 0)) { |
if (error || (refs == 0)) { |
sofree(so); |
sofree(so); |
Line 790 soabort(struct socket *so) |
|
Line 803 soabort(struct socket *so) |
|
} |
} |
|
|
int |
int |
soaccept(struct socket *so, struct mbuf *nam) |
soaccept(struct socket *so, struct sockaddr *nam) |
{ |
{ |
int error; |
int error; |
|
|
Line 808 soaccept(struct socket *so, struct mbuf |
|
Line 821 soaccept(struct socket *so, struct mbuf |
|
} |
} |
|
|
int |
int |
soconnect(struct socket *so, struct mbuf *nam, struct lwp *l) |
soconnect(struct socket *so, struct sockaddr *nam, struct lwp *l) |
{ |
{ |
int error; |
int error; |
|
|
Line 824 soconnect(struct socket *so, struct mbuf |
|
Line 837 soconnect(struct socket *so, struct mbuf |
|
*/ |
*/ |
if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && |
if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && |
((so->so_proto->pr_flags & PR_CONNREQUIRED) || |
((so->so_proto->pr_flags & PR_CONNREQUIRED) || |
(error = sodisconnect(so)))) |
(error = sodisconnect(so)))) { |
error = EISCONN; |
error = EISCONN; |
else |
} else { |
error = (*so->so_proto->pr_usrreqs->pr_connect)(so, nam); |
if (nam->sa_family != so->so_proto->pr_domain->dom_family) { |
|
return EAFNOSUPPORT; |
|
} |
|
error = (*so->so_proto->pr_usrreqs->pr_connect)(so, nam, l); |
|
} |
|
|
return error; |
return error; |
} |
} |
Line 837 soconnect2(struct socket *so1, struct so |
|
Line 854 soconnect2(struct socket *so1, struct so |
|
{ |
{ |
KASSERT(solocked2(so1, so2)); |
KASSERT(solocked2(so1, so2)); |
|
|
return (*so1->so_proto->pr_usrreqs->pr_generic)(so1, |
return (*so1->so_proto->pr_usrreqs->pr_connect2)(so1, so2); |
PRU_CONNECT2, NULL, (struct mbuf *)so2, NULL, NULL); |
|
} |
} |
|
|
int |
int |
Line 853 sodisconnect(struct socket *so) |
|
Line 869 sodisconnect(struct socket *so) |
|
} else if (so->so_state & SS_ISDISCONNECTING) { |
} else if (so->so_state & SS_ISDISCONNECTING) { |
error = EALREADY; |
error = EALREADY; |
} else { |
} else { |
error = (*so->so_proto->pr_usrreqs->pr_generic)(so, |
error = (*so->so_proto->pr_usrreqs->pr_disconnect)(so); |
PRU_DISCONNECT, NULL, NULL, NULL, NULL); |
|
} |
} |
return (error); |
return (error); |
} |
} |
Line 878 sodisconnect(struct socket *so) |
|
Line 893 sodisconnect(struct socket *so) |
|
* Data and control buffers are freed on return. |
* Data and control buffers are freed on return. |
*/ |
*/ |
int |
int |
sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top, |
sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, |
struct mbuf *control, int flags, struct lwp *l) |
struct mbuf *top, struct mbuf *control, int flags, struct lwp *l) |
{ |
{ |
struct mbuf **mp, *m; |
struct mbuf **mp, *m; |
long space, len, resid, clen, mlen; |
long space, len, resid, clen, mlen; |
Line 936 sosend(struct socket *so, struct mbuf *a |
|
Line 951 sosend(struct socket *so, struct mbuf *a |
|
error = ENOTCONN; |
error = ENOTCONN; |
goto release; |
goto release; |
} |
} |
} else if (addr == 0) { |
} else if (addr == NULL) { |
error = EDESTADDRREQ; |
error = EDESTADDRREQ; |
goto release; |
goto release; |
} |
} |
Line 984 sosend(struct socket *so, struct mbuf *a |
|
Line 999 sosend(struct socket *so, struct mbuf *a |
|
m = m_gethdr(M_WAIT, MT_DATA); |
m = m_gethdr(M_WAIT, MT_DATA); |
mlen = MHLEN; |
mlen = MHLEN; |
m->m_pkthdr.len = 0; |
m->m_pkthdr.len = 0; |
m->m_pkthdr.rcvif = NULL; |
m_reset_rcvif(m); |
} else { |
} else { |
m = m_get(M_WAIT, MT_DATA); |
m = m_get(M_WAIT, MT_DATA); |
mlen = MLEN; |
mlen = MLEN; |
Line 1050 sosend(struct socket *so, struct mbuf *a |
|
Line 1065 sosend(struct socket *so, struct mbuf *a |
|
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; |
if (flags & MSG_OOB) |
if (flags & MSG_OOB) { |
error = (*so->so_proto->pr_usrreqs->pr_sendoob)(so, |
error = (*so->so_proto->pr_usrreqs->pr_sendoob)( |
top, control); |
so, top, control); |
else |
} else { |
error = (*so->so_proto->pr_usrreqs->pr_generic)(so, |
error = (*so->so_proto->pr_usrreqs->pr_send)(so, |
PRU_SEND, top, addr, control, curlwp); |
top, addr, control, l); |
|
} |
if (dontroute) |
if (dontroute) |
so->so_options &= ~SO_DONTROUTE; |
so->so_options &= ~SO_DONTROUTE; |
if (resid > 0) |
if (resid > 0) |
Line 1309 soreceive(struct socket *so, struct mbuf |
|
Line 1325 soreceive(struct socket *so, struct mbuf |
|
m->m_next = NULL; |
m->m_next = NULL; |
m = so->so_rcv.sb_mb; |
m = so->so_rcv.sb_mb; |
} else { |
} else { |
MFREE(m, so->so_rcv.sb_mb); |
m = so->so_rcv.sb_mb = m_free(m); |
m = so->so_rcv.sb_mb; |
|
} |
} |
sbsync(&so->so_rcv, nextrecord); |
sbsync(&so->so_rcv, nextrecord); |
} |
} |
} |
} |
|
if (pr->pr_flags & PR_ADDR_OPT) { |
|
/* |
|
* For SCTP we may be getting a |
|
* whole message OR a partial delivery. |
|
*/ |
|
if (m->m_type == MT_SONAME) { |
|
orig_resid = 0; |
|
if (flags & MSG_PEEK) { |
|
if (paddr) |
|
*paddr = m_copy(m, 0, m->m_len); |
|
m = m->m_next; |
|
} else { |
|
sbfree(&so->so_rcv, m); |
|
if (paddr) { |
|
*paddr = m; |
|
so->so_rcv.sb_mb = m->m_next; |
|
m->m_next = 0; |
|
m = so->so_rcv.sb_mb; |
|
} else { |
|
m = so->so_rcv.sb_mb = m_free(m); |
|
} |
|
} |
|
} |
|
} |
|
|
/* |
/* |
* Process one or more MT_CONTROL mbufs present before any data mbufs |
* Process one or more MT_CONTROL mbufs present before any data mbufs |
Line 1369 soreceive(struct socket *so, struct mbuf |
|
Line 1408 soreceive(struct socket *so, struct mbuf |
|
*/ |
*/ |
if (dom->dom_dispose != NULL && |
if (dom->dom_dispose != NULL && |
type == SCM_RIGHTS) { |
type == SCM_RIGHTS) { |
sounlock(so); |
sounlock(so); |
(*dom->dom_dispose)(cm); |
(*dom->dom_dispose)(cm); |
solock(so); |
solock(so); |
} |
} |
Line 1449 soreceive(struct socket *so, struct mbuf |
|
Line 1488 soreceive(struct socket *so, struct mbuf |
|
if (len == m->m_len - moff) { |
if (len == m->m_len - moff) { |
if (m->m_flags & M_EOR) |
if (m->m_flags & M_EOR) |
flags |= MSG_EOR; |
flags |= MSG_EOR; |
|
#ifdef SCTP |
|
if (m->m_flags & M_NOTIFICATION) |
|
flags |= MSG_NOTIFICATION; |
|
#endif /* SCTP */ |
if (flags & MSG_PEEK) { |
if (flags & MSG_PEEK) { |
m = m->m_next; |
m = m->m_next; |
moff = 0; |
moff = 0; |
Line 1461 soreceive(struct socket *so, struct mbuf |
|
Line 1504 soreceive(struct socket *so, struct mbuf |
|
so->so_rcv.sb_mb = m = m->m_next; |
so->so_rcv.sb_mb = m = m->m_next; |
*mp = NULL; |
*mp = NULL; |
} else { |
} else { |
MFREE(m, so->so_rcv.sb_mb); |
m = so->so_rcv.sb_mb = m_free(m); |
m = so->so_rcv.sb_mb; |
|
} |
} |
/* |
/* |
* If m != NULL, we also know that |
* If m != NULL, we also know that |
Line 1534 soreceive(struct socket *so, struct mbuf |
|
Line 1576 soreceive(struct socket *so, struct mbuf |
|
* get it filled again. |
* get it filled again. |
*/ |
*/ |
if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) |
if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) |
(*pr->pr_usrreqs->pr_generic)(so, PRU_RCVD, |
(*pr->pr_usrreqs->pr_rcvd)(so, flags, l); |
NULL, (struct mbuf *)(long)flags, NULL, l); |
|
SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2"); |
SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2"); |
SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2"); |
SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2"); |
if (wakeup_state & SS_RESTARTSYS) |
if (wakeup_state & SS_RESTARTSYS) |
Line 1576 soreceive(struct socket *so, struct mbuf |
|
Line 1617 soreceive(struct socket *so, struct mbuf |
|
SBLASTRECORDCHK(&so->so_rcv, "soreceive 4"); |
SBLASTRECORDCHK(&so->so_rcv, "soreceive 4"); |
SBLASTMBUFCHK(&so->so_rcv, "soreceive 4"); |
SBLASTMBUFCHK(&so->so_rcv, "soreceive 4"); |
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) |
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) |
(*pr->pr_usrreqs->pr_generic)(so, PRU_RCVD, NULL, |
(*pr->pr_usrreqs->pr_rcvd)(so, flags, l); |
(struct mbuf *)(long)flags, NULL, l); |
|
} |
} |
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) { |
Line 1611 soshutdown(struct socket *so, int how) |
|
Line 1651 soshutdown(struct socket *so, int how) |
|
error = 0; |
error = 0; |
} |
} |
if (how == SHUT_WR || how == SHUT_RDWR) |
if (how == SHUT_WR || how == SHUT_RDWR) |
error = (*pr->pr_usrreqs->pr_generic)(so, |
error = (*pr->pr_usrreqs->pr_shutdown)(so); |
PRU_SHUTDOWN, NULL, NULL, NULL, NULL); |
|
|
|
return error; |
return error; |
} |
} |
Line 1683 sosetopt1(struct socket *so, const struc |
|
Line 1722 sosetopt1(struct socket *so, const struc |
|
KASSERT(solocked(so)); |
KASSERT(solocked(so)); |
break; |
break; |
|
|
case SO_LINGER: |
case SO_LINGER: |
error = sockopt_get(sopt, &l, sizeof(l)); |
error = sockopt_get(sopt, &l, sizeof(l)); |
solock(so); |
solock(so); |
if (error) |
if (error) |
break; |
break; |
if (l.l_linger < 0 || l.l_linger > USHRT_MAX || |
if (l.l_linger < 0 || l.l_linger > USHRT_MAX || |
l.l_linger > (INT_MAX / hz)) { |
l.l_linger > (INT_MAX / hz)) { |
error = EDOM; |
error = EDOM; |
break; |
break; |
} |
} |
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 1877 so_setsockopt(struct lwp *l, struct sock |
|
Line 1916 so_setsockopt(struct lwp *l, struct sock |
|
|
|
return error; |
return error; |
} |
} |
|
|
/* |
/* |
* internal get SOL_SOCKET options |
* internal get SOL_SOCKET options |
*/ |
*/ |
Line 2054 sockopt_destroy(struct sockopt *sopt) |
|
Line 2093 sockopt_destroy(struct sockopt *sopt) |
|
/* |
/* |
* set sockopt value |
* set sockopt value |
* - value is copied into sockopt |
* - value is copied into sockopt |
* - memory is allocated when necessary, will not sleep |
* - memory is allocated when necessary, will not sleep |
*/ |
*/ |
int |
int |
sockopt_set(struct sockopt *sopt, const void *buf, size_t len) |
sockopt_set(struct sockopt *sopt, const void *buf, size_t len) |
Line 2179 filt_sordetach(struct knote *kn) |
|
Line 2218 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_socket; |
solock(so); |
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)) |
Line 2194 filt_soread(struct knote *kn, long hint) |
|
Line 2233 filt_soread(struct knote *kn, long hint) |
|
struct socket *so; |
struct socket *so; |
int rv; |
int rv; |
|
|
so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_socket; |
if (hint != NOTE_SUBMIT) |
if (hint != NOTE_SUBMIT) |
solock(so); |
solock(so); |
kn->kn_data = so->so_rcv.sb_cc; |
kn->kn_data = so->so_rcv.sb_cc; |
Line 2206 filt_soread(struct knote *kn, long hint) |
|
Line 2245 filt_soread(struct knote *kn, long hint) |
|
rv = 1; |
rv = 1; |
else if (kn->kn_sfflags & NOTE_LOWAT) |
else if (kn->kn_sfflags & NOTE_LOWAT) |
rv = (kn->kn_data >= kn->kn_sdata); |
rv = (kn->kn_data >= kn->kn_sdata); |
else |
else |
rv = (kn->kn_data >= so->so_rcv.sb_lowat); |
rv = (kn->kn_data >= so->so_rcv.sb_lowat); |
if (hint != NOTE_SUBMIT) |
if (hint != NOTE_SUBMIT) |
sounlock(so); |
sounlock(so); |
Line 2218 filt_sowdetach(struct knote *kn) |
|
Line 2257 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_socket; |
solock(so); |
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)) |
Line 2233 filt_sowrite(struct knote *kn, long hint |
|
Line 2272 filt_sowrite(struct knote *kn, long hint |
|
struct socket *so; |
struct socket *so; |
int rv; |
int rv; |
|
|
so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_socket; |
if (hint != NOTE_SUBMIT) |
if (hint != NOTE_SUBMIT) |
solock(so); |
solock(so); |
kn->kn_data = sbspace(&so->so_snd); |
kn->kn_data = sbspace(&so->so_snd); |
Line 2262 filt_solisten(struct knote *kn, long hin |
|
Line 2301 filt_solisten(struct knote *kn, long hin |
|
struct socket *so; |
struct socket *so; |
int rv; |
int rv; |
|
|
so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_socket; |
|
|
/* |
/* |
* Set kn_data to number of incoming connections, not |
* Set kn_data to number of incoming connections, not |
Line 2290 soo_kqfilter(struct file *fp, struct kno |
|
Line 2329 soo_kqfilter(struct file *fp, struct kno |
|
struct socket *so; |
struct socket *so; |
struct sockbuf *sb; |
struct sockbuf *sb; |
|
|
so = ((file_t *)kn->kn_obj)->f_data; |
so = ((file_t *)kn->kn_obj)->f_socket; |
solock(so); |
solock(so); |
switch (kn->kn_filter) { |
switch (kn->kn_filter) { |
case EVFILT_READ: |
case EVFILT_READ: |