version 1.235.2.3, 2015/09/22 12:06:07 |
version 1.267, 2018/11/07 09:58:19 |
Line 80 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 80 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#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 |
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
Line 117 MALLOC_DEFINE(M_SONAME, "soname", "socke |
|
Line 118 MALLOC_DEFINE(M_SONAME, "soname", "socke |
|
|
|
extern const struct fileops socketops; |
extern const struct fileops socketops; |
|
|
|
static int sooptions; |
extern int somaxconn; /* patchable (XXX sysctl) */ |
extern int somaxconn; /* patchable (XXX sysctl) */ |
int somaxconn = SOMAXCONN; |
int somaxconn = SOMAXCONN; |
kmutex_t *softnet_lock; |
kmutex_t *softnet_lock; |
Line 294 sopendfree_thread(void *v) |
|
Line 296 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 433 socket_listener_cb(kauth_cred_t cred, ka |
|
Line 436 socket_listener_cb(kauth_cred_t cred, ka |
|
|
|
case KAUTH_REQ_NETWORK_SOCKET_OPEN: |
case KAUTH_REQ_NETWORK_SOCKET_OPEN: |
/* We allow "raw" routing/bluetooth sockets to anyone. */ |
/* We allow "raw" routing/bluetooth sockets to anyone. */ |
if ((u_long)arg1 == PF_ROUTE || (u_long)arg1 == PF_OROUTE |
switch ((u_long)arg1) { |
|| (u_long)arg1 == PF_BLUETOOTH) { |
case PF_ROUTE: |
|
case PF_OROUTE: |
|
case PF_BLUETOOTH: |
|
case PF_CAN: |
result = KAUTH_RESULT_ALLOW; |
result = KAUTH_RESULT_ALLOW; |
} else { |
break; |
|
default: |
/* Privileged, let secmodel handle this. */ |
/* Privileged, let secmodel handle this. */ |
if ((u_long)arg2 == SOCK_RAW) |
if ((u_long)arg2 == SOCK_RAW) |
break; |
break; |
|
result = KAUTH_RESULT_ALLOW; |
|
break; |
} |
} |
|
|
result = KAUTH_RESULT_ALLOW; |
|
|
|
break; |
break; |
|
|
case KAUTH_REQ_NETWORK_SOCKET_CANSEE: |
case KAUTH_REQ_NETWORK_SOCKET_CANSEE: |
Line 532 socreate(int dom, struct socket **aso, i |
|
Line 538 socreate(int dom, struct socket **aso, i |
|
so->so_proto = prp; |
so->so_proto = prp; |
so->so_send = sosend; |
so->so_send = sosend; |
so->so_receive = soreceive; |
so->so_receive = soreceive; |
|
so->so_options = sooptions; |
#ifdef MBUFTRACE |
#ifdef MBUFTRACE |
so->so_rcv.sb_mowner = &prp->pr_domain->dom_mowner; |
so->so_rcv.sb_mowner = &prp->pr_domain->dom_mowner; |
so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner; |
so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner; |
|
|
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 | |
Line 651 solisten(struct socket *so, int backlog, |
|
Line 659 solisten(struct socket *so, int backlog, |
|
sounlock(so); |
sounlock(so); |
return EINVAL; |
return EINVAL; |
} |
} |
|
oldopt = so->so_options; |
|
oldqlimit = so->so_qlimit; |
|
if (TAILQ_EMPTY(&so->so_q)) |
|
so->so_options |= SO_ACCEPTCONN; |
|
if (backlog < 0) |
|
backlog = 0; |
|
so->so_qlimit = uimin(backlog, somaxconn); |
|
|
error = (*so->so_proto->pr_usrreqs->pr_listen)(so, l); |
error = (*so->so_proto->pr_usrreqs->pr_listen)(so, l); |
if (error != 0) { |
if (error != 0) { |
|
so->so_options = oldopt; |
|
so->so_qlimit = oldqlimit; |
sounlock(so); |
sounlock(so); |
return error; |
return error; |
} |
} |
if (TAILQ_EMPTY(&so->so_q)) |
|
so->so_options |= SO_ACCEPTCONN; |
|
if (backlog < 0) |
|
backlog = 0; |
|
so->so_qlimit = min(backlog, somaxconn); |
|
sounlock(so); |
sounlock(so); |
return 0; |
return 0; |
} |
} |
Line 991 sosend(struct socket *so, struct sockadd |
|
Line 1004 sosend(struct socket *so, struct sockadd |
|
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 1058 sosend(struct socket *so, struct sockadd |
|
Line 1071 sosend(struct socket *so, struct sockadd |
|
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_send)(so, |
error = (*so->so_proto->pr_usrreqs->pr_send)(so, |
top, addr, control, l); |
top, addr, control, l); |
Line 1229 soreceive(struct socket *so, struct mbuf |
|
Line 1242 soreceive(struct socket *so, struct mbuf |
|
if (m == NULL && so->so_rcv.sb_cc) |
if (m == NULL && so->so_rcv.sb_cc) |
panic("receive 1"); |
panic("receive 1"); |
#endif |
#endif |
if (so->so_error) { |
if (so->so_error || so->so_rerror) { |
if (m != NULL) |
if (m != NULL) |
goto dontblock; |
goto dontblock; |
error = so->so_error; |
if (so->so_error) { |
if ((flags & MSG_PEEK) == 0) |
error = so->so_error; |
so->so_error = 0; |
so->so_error = 0; |
|
} else { |
|
error = so->so_rerror; |
|
so->so_rerror = 0; |
|
} |
goto release; |
goto release; |
} |
} |
if (so->so_state & SS_CANTRCVMORE) { |
if (so->so_state & SS_CANTRCVMORE) { |
Line 1306 soreceive(struct socket *so, struct mbuf |
|
Line 1323 soreceive(struct socket *so, struct mbuf |
|
orig_resid = 0; |
orig_resid = 0; |
if (flags & MSG_PEEK) { |
if (flags & MSG_PEEK) { |
if (paddr) |
if (paddr) |
*paddr = m_copy(m, 0, m->m_len); |
*paddr = m_copym(m, 0, m->m_len, M_DONTWAIT); |
m = m->m_next; |
m = m->m_next; |
} else { |
} else { |
sbfree(&so->so_rcv, m); |
sbfree(&so->so_rcv, m); |
Line 1317 soreceive(struct socket *so, struct mbuf |
|
Line 1334 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_copym(m, 0, m->m_len, M_DONTWAIT); |
|
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 1337 soreceive(struct socket *so, struct mbuf |
|
Line 1377 soreceive(struct socket *so, struct mbuf |
|
do { |
do { |
if (flags & MSG_PEEK) { |
if (flags & MSG_PEEK) { |
if (controlp != NULL) { |
if (controlp != NULL) { |
*controlp = m_copy(m, 0, m->m_len); |
*controlp = m_copym(m, 0, m->m_len, M_DONTWAIT); |
controlp = &(*controlp)->m_next; |
controlp = &(*controlp)->m_next; |
} |
} |
m = m->m_next; |
m = m->m_next; |
Line 1377 soreceive(struct socket *so, struct mbuf |
|
Line 1417 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 1457 soreceive(struct socket *so, struct mbuf |
|
Line 1497 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 1469 soreceive(struct socket *so, struct mbuf |
|
Line 1513 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 1528 soreceive(struct socket *so, struct mbuf |
|
Line 1571 soreceive(struct socket *so, struct mbuf |
|
*/ |
*/ |
while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 && |
while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 && |
!sosendallatonce(so) && !nextrecord) { |
!sosendallatonce(so) && !nextrecord) { |
if (so->so_error || so->so_state & SS_CANTRCVMORE) |
if (so->so_error || so->so_rerror || |
|
so->so_state & SS_CANTRCVMORE) |
break; |
break; |
/* |
/* |
* If we are peeking and the socket receive buffer is |
* If we are peeking and the socket receive buffer is |
Line 1688 sosetopt1(struct socket *so, const struc |
|
Line 1732 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 1715 sosetopt1(struct socket *so, const struc |
|
Line 1759 sosetopt1(struct socket *so, const struc |
|
case SO_OOBINLINE: |
case SO_OOBINLINE: |
case SO_TIMESTAMP: |
case SO_TIMESTAMP: |
case SO_NOSIGPIPE: |
case SO_NOSIGPIPE: |
|
case SO_RERROR: |
#ifdef SO_OTIMESTAMP |
#ifdef SO_OTIMESTAMP |
case SO_OTIMESTAMP: |
case SO_OTIMESTAMP: |
#endif |
#endif |
Line 1916 sogetopt1(struct socket *so, struct sock |
|
Line 1961 sogetopt1(struct socket *so, struct sock |
|
case SO_OOBINLINE: |
case SO_OOBINLINE: |
case SO_TIMESTAMP: |
case SO_TIMESTAMP: |
case SO_NOSIGPIPE: |
case SO_NOSIGPIPE: |
|
case SO_RERROR: |
#ifdef SO_OTIMESTAMP |
#ifdef SO_OTIMESTAMP |
case SO_OTIMESTAMP: |
case SO_OTIMESTAMP: |
#endif |
#endif |
Line 1928 sogetopt1(struct socket *so, struct sock |
|
Line 1974 sogetopt1(struct socket *so, struct sock |
|
break; |
break; |
|
|
case SO_ERROR: |
case SO_ERROR: |
|
if (so->so_error == 0) { |
|
so->so_error = so->so_rerror; |
|
so->so_rerror = 0; |
|
} |
error = sockopt_setint(sopt, so->so_error); |
error = sockopt_setint(sopt, so->so_error); |
so->so_error = 0; |
so->so_error = 0; |
break; |
break; |
Line 2059 sockopt_destroy(struct sockopt *sopt) |
|
Line 2109 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 2072 sockopt_set(struct sockopt *sopt, const |
|
Line 2122 sockopt_set(struct sockopt *sopt, const |
|
return error; |
return error; |
} |
} |
|
|
KASSERT(sopt->sopt_size == len); |
if (sopt->sopt_size < len) |
|
return EINVAL; |
|
|
memcpy(sopt->sopt_data, buf, len); |
memcpy(sopt->sopt_data, buf, len); |
|
sopt->sopt_retsize = len; |
|
|
return 0; |
return 0; |
} |
} |
|
|
Line 2132 sockopt_setmbuf(struct sockopt *sopt, st |
|
Line 2186 sockopt_setmbuf(struct sockopt *sopt, st |
|
return error; |
return error; |
} |
} |
|
|
KASSERT(sopt->sopt_size == len); |
if (sopt->sopt_size < len) |
|
return EINVAL; |
|
|
m_copydata(m, 0, len, sopt->sopt_data); |
m_copydata(m, 0, len, sopt->sopt_data); |
m_freem(m); |
m_freem(m); |
|
sopt->sopt_retsize = len; |
|
|
return 0; |
return 0; |
} |
} |
Line 2207 filt_soread(struct knote *kn, long hint) |
|
Line 2264 filt_soread(struct knote *kn, long hint) |
|
kn->kn_flags |= EV_EOF; |
kn->kn_flags |= EV_EOF; |
kn->kn_fflags = so->so_error; |
kn->kn_fflags = so->so_error; |
rv = 1; |
rv = 1; |
} else if (so->so_error) /* temporary udp error */ |
} else if (so->so_error || so->so_rerror) |
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); |
Line 2246 filt_sowrite(struct knote *kn, long hint |
|
Line 2303 filt_sowrite(struct knote *kn, long hint |
|
kn->kn_flags |= EV_EOF; |
kn->kn_flags |= EV_EOF; |
kn->kn_fflags = so->so_error; |
kn->kn_fflags = so->so_error; |
rv = 1; |
rv = 1; |
} else if (so->so_error) /* temporary udp error */ |
} else if (so->so_error) |
rv = 1; |
rv = 1; |
else if (((so->so_state & SS_ISCONNECTED) == 0) && |
else if (((so->so_state & SS_ISCONNECTED) == 0) && |
(so->so_proto->pr_flags & PR_CONNREQUIRED)) |
(so->so_proto->pr_flags & PR_CONNREQUIRED)) |
Line 2282 filt_solisten(struct knote *kn, long hin |
|
Line 2339 filt_solisten(struct knote *kn, long hin |
|
return rv; |
return rv; |
} |
} |
|
|
static const struct filterops solisten_filtops = |
static const struct filterops solisten_filtops = { |
{ 1, NULL, filt_sordetach, filt_solisten }; |
.f_isfd = 1, |
static const struct filterops soread_filtops = |
.f_attach = NULL, |
{ 1, NULL, filt_sordetach, filt_soread }; |
.f_detach = filt_sordetach, |
static const struct filterops sowrite_filtops = |
.f_event = filt_solisten, |
{ 1, NULL, filt_sowdetach, filt_sowrite }; |
}; |
|
|
|
static const struct filterops soread_filtops = { |
|
.f_isfd = 1, |
|
.f_attach = NULL, |
|
.f_detach = filt_sordetach, |
|
.f_event = filt_soread, |
|
}; |
|
|
|
static const struct filterops sowrite_filtops = { |
|
.f_isfd = 1, |
|
.f_attach = NULL, |
|
.f_detach = filt_sowdetach, |
|
.f_event = filt_sowrite, |
|
}; |
|
|
int |
int |
soo_kqfilter(struct file *fp, struct knote *kn) |
soo_kqfilter(struct file *fp, struct knote *kn) |
Line 2373 sopoll(struct socket *so, int events) |
|
Line 2444 sopoll(struct socket *so, int events) |
|
return revents; |
return revents; |
} |
} |
|
|
|
struct mbuf ** |
|
sbsavetimestamp(int opt, struct mbuf **mp) |
|
{ |
|
struct timeval tv; |
|
microtime(&tv); |
|
|
|
#ifdef SO_OTIMESTAMP |
|
if (opt & SO_OTIMESTAMP) { |
|
struct timeval50 tv50; |
|
|
|
timeval_to_timeval50(&tv, &tv50); |
|
*mp = sbcreatecontrol(&tv50, sizeof(tv50), |
|
SCM_OTIMESTAMP, SOL_SOCKET); |
|
if (*mp) |
|
mp = &(*mp)->m_next; |
|
} else |
|
#endif |
|
|
|
if (opt & SO_TIMESTAMP) { |
|
*mp = sbcreatecontrol(&tv, sizeof(tv), |
|
SCM_TIMESTAMP, SOL_SOCKET); |
|
if (*mp) |
|
mp = &(*mp)->m_next; |
|
} |
|
return mp; |
|
} |
|
|
|
|
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
|
|
Line 2432 sysctl_kern_sbmax(SYSCTLFN_ARGS) |
|
Line 2530 sysctl_kern_sbmax(SYSCTLFN_ARGS) |
|
return (error); |
return (error); |
} |
} |
|
|
|
/* |
|
* sysctl helper routine for kern.sooptions. Ensures that only allowed |
|
* options can be set. |
|
*/ |
|
static int |
|
sysctl_kern_sooptions(SYSCTLFN_ARGS) |
|
{ |
|
int error, new_options; |
|
struct sysctlnode node; |
|
|
|
new_options = sooptions; |
|
node = *rnode; |
|
node.sysctl_data = &new_options; |
|
error = sysctl_lookup(SYSCTLFN_CALL(&node)); |
|
if (error || newp == NULL) |
|
return error; |
|
|
|
if (new_options & ~SO_DEFOPTS) |
|
return EINVAL; |
|
|
|
sooptions = new_options; |
|
|
|
return 0; |
|
} |
|
|
static void |
static void |
sysctl_kern_socket_setup(void) |
sysctl_kern_socket_setup(void) |
{ |
{ |
Line 2452 sysctl_kern_socket_setup(void) |
|
Line 2575 sysctl_kern_socket_setup(void) |
|
SYSCTL_DESCR("Maximum socket buffer size"), |
SYSCTL_DESCR("Maximum socket buffer size"), |
sysctl_kern_sbmax, 0, NULL, 0, |
sysctl_kern_sbmax, 0, NULL, 0, |
CTL_KERN, KERN_SBMAX, CTL_EOL); |
CTL_KERN, KERN_SBMAX, CTL_EOL); |
|
|
|
sysctl_createv(&socket_sysctllog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "sooptions", |
|
SYSCTL_DESCR("Default socket options"), |
|
sysctl_kern_sooptions, 0, NULL, 0, |
|
CTL_KERN, CTL_CREATE, CTL_EOL); |
} |
} |