summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2004-07-17 21:06:36 +0000
committerdwmalone <dwmalone@FreeBSD.org>2004-07-17 21:06:36 +0000
commitc8c1b8f415a3f8e57219cf3587707d7d24b8d582 (patch)
treedca356ba37d0e4e58bfdf5b38929557fe4c9839d /sys/kern
parent7beb6d42ceb4bcb8294f42ff6a0a292e434bcc88 (diff)
downloadFreeBSD-src-c8c1b8f415a3f8e57219cf3587707d7d24b8d582.zip
FreeBSD-src-c8c1b8f415a3f8e57219cf3587707d7d24b8d582.tar.gz
Add a kern_setsockopt and kern_getsockopt which can read the option
values from either user land or from the kernel. Use them for [gs]etsockopt and to clean up some calls to [gs]etsockopt in the Linux emulation code that uses the stackgap.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_syscalls.c120
1 files changed, 86 insertions, 34 deletions
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index eeff60d..238dee4 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -1242,23 +1242,48 @@ setsockopt(td, uap)
int valsize;
} */ *uap;
{
+
+ return (kern_setsockopt(td, uap->s, uap->level, uap->name,
+ uap->val, UIO_USERSPACE, uap->valsize));
+}
+
+int
+kern_setsockopt(td, s, level, name, val, valseg, valsize)
+ struct thread *td;
+ int s;
+ int level;
+ int name;
+ void *val;
+ enum uio_seg valseg;
+ socklen_t valsize;
+{
+ int error;
struct socket *so;
struct sockopt sopt;
- int error;
- if (uap->val == 0 && uap->valsize != 0)
+ if (val == NULL && valsize != 0)
return (EFAULT);
- if (uap->valsize < 0)
+ if (valsize < 0)
return (EINVAL);
- NET_LOCK_GIANT();
- if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) {
- sopt.sopt_dir = SOPT_SET;
- sopt.sopt_level = uap->level;
- sopt.sopt_name = uap->name;
- sopt.sopt_val = uap->val;
- sopt.sopt_valsize = uap->valsize;
+ sopt.sopt_dir = SOPT_SET;
+ sopt.sopt_level = level;
+ sopt.sopt_name = name;
+ sopt.sopt_val = val;
+ sopt.sopt_valsize = valsize;
+ switch (valseg) {
+ case UIO_USERSPACE:
sopt.sopt_td = td;
+ break;
+ case UIO_SYSSPACE:
+ sopt.sopt_td = NULL;
+ break;
+ default:
+ panic("kern_setsockopt called with bad valseg");
+ }
+
+ NET_LOCK_GIANT();
+ if ((error = fgetsock(td, s, &so, NULL)) == 0) {
error = sosetopt(so, &sopt);
fputsock(so);
}
@@ -1283,39 +1308,66 @@ getsockopt(td, uap)
{
socklen_t valsize;
int error;
- struct socket *so;
- struct sockopt sopt;
- NET_LOCK_GIANT();
- if ((error = fgetsock(td, uap->s, &so, NULL)) != 0)
- goto done2;
if (uap->val) {
error = copyin(uap->avalsize, &valsize, sizeof (valsize));
if (error)
- goto done1;
- if (valsize < 0) {
- error = EINVAL;
- goto done1;
- }
- } else {
- valsize = 0;
+ return (error);
}
- sopt.sopt_dir = SOPT_GET;
- sopt.sopt_level = uap->level;
- sopt.sopt_name = uap->name;
- sopt.sopt_val = uap->val;
- sopt.sopt_valsize = (size_t)valsize; /* checked non-negative above */
- sopt.sopt_td = td;
+ error = kern_getsockopt(td, uap->s, uap->level, uap->name,
+ uap->val, UIO_USERSPACE, &valsize);
- error = sogetopt(so, &sopt);
- if (error == 0) {
- valsize = sopt.sopt_valsize;
+ if (error == 0)
error = copyout(&valsize, uap->avalsize, sizeof (valsize));
+ return (error);
+}
+
+/*
+ * Kernel version of getsockopt.
+ * optval can be a userland or userspace. optlen is always a kernel pointer.
+ */
+int
+kern_getsockopt(td, s, level, name, val, valseg, valsize)
+ struct thread *td;
+ int s;
+ int level;
+ int name;
+ void *val;
+ enum uio_seg valseg;
+ socklen_t *valsize;
+{
+ int error;
+ struct socket *so;
+ struct sockopt sopt;
+
+ if (val == NULL)
+ *valsize = 0;
+ if (*valsize < 0)
+ return (EINVAL);
+
+ sopt.sopt_dir = SOPT_GET;
+ sopt.sopt_level = level;
+ sopt.sopt_name = name;
+ sopt.sopt_val = val;
+ sopt.sopt_valsize = (size_t)*valsize; /* checked non-negative above */
+ switch (valseg) {
+ case UIO_USERSPACE:
+ sopt.sopt_td = td;
+ break;
+ case UIO_SYSSPACE:
+ sopt.sopt_td = NULL;
+ break;
+ default:
+ panic("kern_getsockopt called with bad valseg");
+ }
+
+ NET_LOCK_GIANT();
+ if ((error = fgetsock(td, s, &so, NULL)) == 0) {
+ error = sogetopt(so, &sopt);
+ *valsize = sopt.sopt_valsize;
+ fputsock(so);
}
-done1:
- fputsock(so);
-done2:
NET_UNLOCK_GIANT();
return (error);
}
OpenPOWER on IntegriCloud