version 1.177.4.3, 2009/05/03 13:18:55 |
version 1.191, 2009/10/02 23:50:16 |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#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" |
Line 92 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 93 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/mutex.h> |
#include <sys/mutex.h> |
#include <sys/condvar.h> |
#include <sys/condvar.h> |
|
|
|
#ifdef COMPAT_50 |
|
#include <compat/sys/time.h> |
|
#include <compat/sys/socket.h> |
|
#endif |
|
|
#include <uvm/uvm.h> |
#include <uvm/uvm.h> |
|
|
MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options"); |
MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options"); |
Line 145 int somaxkva = SOMAXKVA; |
|
Line 151 int somaxkva = SOMAXKVA; |
|
static int socurkva; |
static int socurkva; |
static kcondvar_t socurkva_cv; |
static kcondvar_t socurkva_cv; |
|
|
|
static kauth_listener_t socket_listener; |
|
|
#define SOCK_LOAN_CHUNK 65536 |
#define SOCK_LOAN_CHUNK 65536 |
|
|
static size_t sodopendfree(void); |
static size_t sodopendfree(void); |
static size_t sodopendfreel(void); |
static size_t sodopendfreel(void); |
|
|
|
static void sysctl_kern_somaxkva_setup(void); |
|
static struct sysctllog *socket_sysctllog; |
|
|
static vsize_t |
static vsize_t |
sokvareserve(struct socket *so, vsize_t len) |
sokvareserve(struct socket *so, vsize_t len) |
{ |
{ |
Line 419 getsombuf(struct socket *so, int type) |
|
Line 430 getsombuf(struct socket *so, int type) |
|
return m; |
return m; |
} |
} |
|
|
|
static int |
|
socket_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, |
|
void *arg0, void *arg1, void *arg2, void *arg3) |
|
{ |
|
int result; |
|
enum kauth_network_req req; |
|
|
|
result = KAUTH_RESULT_DEFER; |
|
req = (enum kauth_network_req)arg0; |
|
|
|
if (action != KAUTH_NETWORK_SOCKET) |
|
return result; |
|
|
|
switch (req) { |
|
case KAUTH_REQ_NETWORK_SOCKET_DROP: { |
|
/* Normal users can only drop their own connections. */ |
|
struct socket *so = (struct socket *)arg1; |
|
uid_t sockuid = so->so_uidinfo->ui_uid; |
|
|
|
if (sockuid == kauth_cred_getuid(cred) || |
|
sockuid == kauth_cred_geteuid(cred)) |
|
result = KAUTH_RESULT_ALLOW; |
|
|
|
break; |
|
} |
|
|
|
case KAUTH_REQ_NETWORK_SOCKET_OPEN: |
|
/* We allow "raw" routing/bluetooth sockets to anyone. */ |
|
if ((u_long)arg1 == PF_ROUTE || (u_long)arg1 == PF_BLUETOOTH) |
|
result = KAUTH_RESULT_ALLOW; |
|
else { |
|
/* Privileged, let secmodel handle this. */ |
|
if ((u_long)arg2 == SOCK_RAW) |
|
break; |
|
} |
|
|
|
result = KAUTH_RESULT_ALLOW; |
|
|
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
return result; |
|
} |
|
|
void |
void |
soinit(void) |
soinit(void) |
{ |
{ |
|
|
|
sysctl_kern_somaxkva_setup(); |
|
|
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); |
softnet_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
cv_init(&socurkva_cv, "sokva"); |
cv_init(&socurkva_cv, "sokva"); |
|
|
|
|
callback_register(&vm_map_to_kernel(kernel_map)->vmk_reclaim_callback, |
callback_register(&vm_map_to_kernel(kernel_map)->vmk_reclaim_callback, |
&sokva_reclaimerentry, NULL, sokva_reclaim_callback); |
&sokva_reclaimerentry, NULL, sokva_reclaim_callback); |
|
|
|
socket_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK, |
|
socket_listener_cb, NULL); |
} |
} |
|
|
/* |
/* |
Line 488 socreate(int dom, struct socket **aso, i |
|
Line 551 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 |
|
/* so->so_cred = kauth_cred_dup(l->l_cred); */ |
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_egid = kauth_cred_getegid(l->l_cred); |
Line 544 fsocreate(int domain, struct socket **so |
|
Line 608 fsocreate(int domain, struct socket **so |
|
} |
} |
|
|
int |
int |
|
sofamily(const struct socket *so) |
|
{ |
|
const struct protosw *pr; |
|
const struct domain *dom; |
|
|
|
if ((pr = so->so_proto) == NULL) |
|
return AF_UNSPEC; |
|
if ((dom = pr->pr_domain) == NULL) |
|
return AF_UNSPEC; |
|
return dom->dom_family; |
|
} |
|
|
|
int |
sobind(struct socket *so, struct mbuf *nam, struct lwp *l) |
sobind(struct socket *so, struct mbuf *nam, struct lwp *l) |
{ |
{ |
int error; |
int error; |
Line 617 sofree(struct socket *so) |
|
Line 694 sofree(struct socket *so) |
|
/* Remove acccept filter if one is present. */ |
/* Remove acccept filter if one is present. */ |
if (so->so_accf != NULL) |
if (so->so_accf != NULL) |
(void)accept_filt_clear(so); |
(void)accept_filt_clear(so); |
|
/* kauth_cred_free(so->so_cred); */ |
sounlock(so); |
sounlock(so); |
if (refs == 0) /* XXX */ |
if (refs == 0) /* XXX */ |
soput(so); |
soput(so); |
Line 1585 sorflush(struct socket *so) |
|
Line 1663 sorflush(struct socket *so) |
|
static int |
static int |
sosetopt1(struct socket *so, const struct sockopt *sopt) |
sosetopt1(struct socket *so, const struct sockopt *sopt) |
{ |
{ |
int error, optval; |
int error = EINVAL, optval, opt; |
struct linger l; |
struct linger l; |
struct timeval tv; |
struct timeval tv; |
|
|
switch (sopt->sopt_name) { |
switch ((opt = sopt->sopt_name)) { |
|
|
case SO_ACCEPTFILTER: |
case SO_ACCEPTFILTER: |
error = accept_filt_setopt(so, sopt); |
error = accept_filt_setopt(so, sopt); |
Line 1622 sosetopt1(struct socket *so, const struc |
|
Line 1700 sosetopt1(struct socket *so, const struc |
|
case SO_REUSEPORT: |
case SO_REUSEPORT: |
case SO_OOBINLINE: |
case SO_OOBINLINE: |
case SO_TIMESTAMP: |
case SO_TIMESTAMP: |
|
#ifdef SO_OTIMESTAMP |
|
case SO_OTIMESTAMP: |
|
#endif |
error = sockopt_getint(sopt, &optval); |
error = sockopt_getint(sopt, &optval); |
solock(so); |
solock(so); |
if (error) |
if (error) |
break; |
break; |
if (optval) |
if (optval) |
so->so_options |= sopt->sopt_name; |
so->so_options |= opt; |
else |
else |
so->so_options &= ~sopt->sopt_name; |
so->so_options &= ~opt; |
break; |
break; |
|
|
case SO_SNDBUF: |
case SO_SNDBUF: |
Line 1650 sosetopt1(struct socket *so, const struc |
|
Line 1731 sosetopt1(struct socket *so, const struc |
|
break; |
break; |
} |
} |
|
|
switch (sopt->sopt_name) { |
switch (opt) { |
case SO_SNDBUF: |
case SO_SNDBUF: |
if (sbreserve(&so->so_snd, (u_long)optval, so) == 0) { |
if (sbreserve(&so->so_snd, (u_long)optval, so) == 0) { |
error = ENOBUFS; |
error = ENOBUFS; |
Line 1687 sosetopt1(struct socket *so, const struc |
|
Line 1768 sosetopt1(struct socket *so, const struc |
|
} |
} |
break; |
break; |
|
|
|
#ifdef COMPAT_50 |
|
case SO_OSNDTIMEO: |
|
case SO_ORCVTIMEO: { |
|
struct timeval50 otv; |
|
error = sockopt_get(sopt, &otv, sizeof(otv)); |
|
if (error) { |
|
solock(so); |
|
break; |
|
} |
|
timeval50_to_timeval(&otv, &tv); |
|
opt = opt == SO_OSNDTIMEO ? SO_SNDTIMEO : SO_RCVTIMEO; |
|
error = 0; |
|
/*FALLTHROUGH*/ |
|
} |
|
#endif /* COMPAT_50 */ |
|
|
case SO_SNDTIMEO: |
case SO_SNDTIMEO: |
case SO_RCVTIMEO: |
case SO_RCVTIMEO: |
error = sockopt_get(sopt, &tv, sizeof(tv)); |
if (error) |
|
error = sockopt_get(sopt, &tv, sizeof(tv)); |
solock(so); |
solock(so); |
if (error) |
if (error) |
break; |
break; |
Line 1703 sosetopt1(struct socket *so, const struc |
|
Line 1801 sosetopt1(struct socket *so, const struc |
|
if (optval == 0 && tv.tv_usec != 0) |
if (optval == 0 && tv.tv_usec != 0) |
optval = 1; |
optval = 1; |
|
|
switch (sopt->sopt_name) { |
switch (opt) { |
case SO_SNDTIMEO: |
case SO_SNDTIMEO: |
so->so_snd.sb_timeo = optval; |
so->so_snd.sb_timeo = optval; |
break; |
break; |
Line 1776 so_setsockopt(struct lwp *l, struct sock |
|
Line 1874 so_setsockopt(struct lwp *l, struct sock |
|
static int |
static int |
sogetopt1(struct socket *so, struct sockopt *sopt) |
sogetopt1(struct socket *so, struct sockopt *sopt) |
{ |
{ |
int error, optval; |
int error, optval, opt; |
struct linger l; |
struct linger l; |
struct timeval tv; |
struct timeval tv; |
|
|
switch (sopt->sopt_name) { |
switch ((opt = sopt->sopt_name)) { |
|
|
case SO_ACCEPTFILTER: |
case SO_ACCEPTFILTER: |
error = accept_filt_getopt(so, sopt); |
error = accept_filt_getopt(so, sopt); |
Line 1802 sogetopt1(struct socket *so, struct sock |
|
Line 1900 sogetopt1(struct socket *so, struct sock |
|
case SO_BROADCAST: |
case SO_BROADCAST: |
case SO_OOBINLINE: |
case SO_OOBINLINE: |
case SO_TIMESTAMP: |
case SO_TIMESTAMP: |
error = sockopt_setint(sopt, |
#ifdef SO_OTIMESTAMP |
(so->so_options & sopt->sopt_name) ? 1 : 0); |
case SO_OTIMESTAMP: |
|
#endif |
|
error = sockopt_setint(sopt, (so->so_options & opt) ? 1 : 0); |
break; |
break; |
|
|
case SO_TYPE: |
case SO_TYPE: |
Line 1831 sogetopt1(struct socket *so, struct sock |
|
Line 1931 sogetopt1(struct socket *so, struct sock |
|
error = sockopt_setint(sopt, so->so_rcv.sb_lowat); |
error = sockopt_setint(sopt, so->so_rcv.sb_lowat); |
break; |
break; |
|
|
|
#ifdef COMPAT_50 |
|
case SO_OSNDTIMEO: |
|
case SO_ORCVTIMEO: { |
|
struct timeval50 otv; |
|
|
|
optval = (opt == SO_OSNDTIMEO ? |
|
so->so_snd.sb_timeo : so->so_rcv.sb_timeo); |
|
|
|
otv.tv_sec = optval / hz; |
|
otv.tv_usec = (optval % hz) * tick; |
|
|
|
error = sockopt_set(sopt, &otv, sizeof(otv)); |
|
break; |
|
} |
|
#endif /* COMPAT_50 */ |
|
|
case SO_SNDTIMEO: |
case SO_SNDTIMEO: |
case SO_RCVTIMEO: |
case SO_RCVTIMEO: |
optval = (sopt->sopt_name == SO_SNDTIMEO ? |
optval = (opt == SO_SNDTIMEO ? |
so->so_snd.sb_timeo : so->so_rcv.sb_timeo); |
so->so_snd.sb_timeo : so->so_rcv.sb_timeo); |
|
|
tv.tv_sec = optval / hz; |
tv.tv_sec = optval / hz; |
Line 2274 sysctl_kern_somaxkva(SYSCTLFN_ARGS) |
|
Line 2390 sysctl_kern_somaxkva(SYSCTLFN_ARGS) |
|
return (error); |
return (error); |
} |
} |
|
|
SYSCTL_SETUP(sysctl_kern_somaxkva_setup, "sysctl kern.somaxkva setup") |
static void |
|
sysctl_kern_somaxkva_setup(void) |
{ |
{ |
|
|
sysctl_createv(clog, 0, NULL, NULL, |
KASSERT(socket_sysctllog == NULL); |
|
sysctl_createv(&socket_sysctllog, 0, NULL, NULL, |
CTLFLAG_PERMANENT, |
CTLFLAG_PERMANENT, |
CTLTYPE_NODE, "kern", NULL, |
CTLTYPE_NODE, "kern", NULL, |
NULL, 0, NULL, 0, |
NULL, 0, NULL, 0, |
CTL_KERN, CTL_EOL); |
CTL_KERN, CTL_EOL); |
|
|
sysctl_createv(clog, 0, NULL, NULL, |
sysctl_createv(&socket_sysctllog, 0, NULL, NULL, |
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
CTLTYPE_INT, "somaxkva", |
CTLTYPE_INT, "somaxkva", |
SYSCTL_DESCR("Maximum amount of kernel memory to be " |
SYSCTL_DESCR("Maximum amount of kernel memory to be " |