diff options
Diffstat (limited to 'cpukit')
26 files changed, 3038 insertions, 263 deletions
diff --git a/cpukit/libnetworking/ChangeLog b/cpukit/libnetworking/ChangeLog index f2d3e93d19..3d7cb9cda2 100644 --- a/cpukit/libnetworking/ChangeLog +++ b/cpukit/libnetworking/ChangeLog @@ -1,3 +1,47 @@ +2002-11-26 Chris Johns <cjohns@cybertec.com.au> + + * Makefile.am: Added sys/linker_set.h + * kern/Makefile.am: Added kern_mib.c and kern_sysctl.c. + * kern/uipc_socket.c: OID changed from KERN_SOMAXCONN to KIPC_SOMAXCONN. + * kern/uipc_socket2.c: OID changed from KERN_MAXSOCKBUF to + KIPC_MAXSOCKBUF. + * net/if_ethersubr.c: FreeBSD 2.2.2 does not have a _net_link node + while 5.0 does. + * net/if_ppp.c: Removed the TEXT_SET define as these macros are + now implemented. + * net/rtsock.c: Enable sysctl support plus fix the bug with the + lastest FreeBSD sysctl header file. + * netinet/icmp_var.h: FreeBSD 2.2.2 does not have a _net_inet_icmp + node while 5.0 does. + * netinet/if_ether.c: FreeBSD 2.2.2 does not have a _net_link_ether + node while 5.0 does. + * netinet/igmp_var.h: FreeBSD 2.2.2 does not have a _net_inet_igmp + node while 5.0 does. + * netinet/in_pcb.c: Fixed the arguments to the sysctl call. Add + inp_gencnt and ipi_count. These are used when listing connections. + * netinet/in_pcb.h: Added counters to aid the listing of connections. + * netinet/in_var.h: Provide the _net_inet_ip and _net_inet_raw nodes. + * netinet/ip_fw.c: Disable the firewall sysctl calls. + * netinet/tcp_subr.c: Merge tcp_pcblist from the lastest FreeBSD source. + * netinet/tcp_var.h: Add structures needed by net-snmp to list + connections. + * netinet/udp_usrreq.c: Merged udp_pcblist from the lastest FreeBSD + source. + * netinet/udp_var.h: Added the sysctl id UDPCTL_PCBLIST. Used by + net-snmp. + * rtems_glue.c: Call sysctl_register_all when initialising the + network stack to register all the sysctl calls. These are in the + special sections and required an updated linker script. + * rtems/rtems_syscall.c: Add the sysctl call. + * sys/kernel.h: Use the lastest FreeBSD method of handling sysctl + structures. This now held in the sys/linker_set.h file. + * sys/queue.h: This is from the lastest FreeBSD code with the circular + code merged back in as it is not used in the lastest FreeBSD kernel. + * sys/sysctl.h: The lastest sysctl. This was needed to use with the new + linker set method. The FreeBSD 2.2.2 version has asm hacks. The lastest + version of the FreeBSD does not have these hacks. It uses gcc attribute + directives. + 2002-12-18 Eric Norum <eric.norum@usask.ca> * Makefile.am: Include netinet sources. diff --git a/cpukit/libnetworking/Makefile.am b/cpukit/libnetworking/Makefile.am index e828fd12bd..481a544294 100644 --- a/cpukit/libnetworking/Makefile.am +++ b/cpukit/libnetworking/Makefile.am @@ -44,8 +44,8 @@ PREINSTALL_FILES += $(PROJECT_INCLUDE)/arpa \ ## kern -kern_C_FILES = kern/kern_subr.c kern/uipc_domain.c kern/uipc_mbuf.c \ - kern/uipc_socket.c kern/uipc_socket2.c +kern_C_FILES = kern/kern_mib.c kern/kern_subr.c kern/uipc_domain.c \ + kern/uipc_mbuf.c kern/uipc_socket.c kern/uipc_socket2.c OBJS = $(kern_C_FILES:kern/%.c=$(ARCH)/%.$(OBJEXT)) $(ARCH)/%.$(OBJEXT): kern/%.c @@ -172,7 +172,7 @@ EXTRA_DIST += $(rtems_C_FILES) include_sysdir = $(includedir)/sys include_sys_HEADERS = sys/buf.h sys/callout.h sys/conf.h sys/domain.h \ - sys/kernel.h sys/libkern.h sys/malloc.h sys/mbuf.h sys/mount.h \ + sys/kernel.h sys/libkern.h sys/linker_set.h sys/malloc.h sys/mbuf.h sys/mount.h \ sys/proc.h sys/protosw.h sys/queue.h sys/reboot.h sys/resourcevar.h \ sys/rtprio.h sys/select.h sys/signalvar.h sys/socket.h sys/socketvar.h \ sys/sysctl.h sys/syslog.h sys/systm.h sys/ttydefaults.h sys/ucred.h \ diff --git a/cpukit/libnetworking/kern/kern_mib.c b/cpukit/libnetworking/kern/kern_mib.c new file mode 100644 index 0000000000..174ddc69e9 --- /dev/null +++ b/cpukit/libnetworking/kern/kern_mib.c @@ -0,0 +1,382 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Karels at Berkeley Software Design, Inc. + * + * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD + * project, to make these variables more userfriendly. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 + * $FreeBSD: src/sys/kern/kern_mib.c,v 1.62 2002/11/07 23:57:17 tmm Exp $ + */ + +#ifndef __rtems__ +#include "opt_posix.h" +#endif + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#ifndef __rtems__ +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/jail.h> +#include <sys/smp.h> +#endif +#include <sys/unistd.h> + +#ifdef __rtems__ +char machine[] = "SET ME"; +char osrelease[] = PACKAGE_VERSION; +char ostype[] = "RTEMS"; +#endif + +SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, + "Sysctl internal magic"); +SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, + "High kernel, proc, limits &c"); +#ifndef __rtems__ +SYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, + "Virtual memory"); +SYSCTL_NODE(, CTL_VFS, vfs, CTLFLAG_RW, 0, + "File system"); +#endif +SYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, + "Network, (see socket.h)"); +#ifndef __rtems__ +SYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, + "Debugging"); +SYSCTL_NODE(_debug, OID_AUTO, sizeof, CTLFLAG_RW, 0, + "Sizeof various things"); +SYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, + "hardware"); +SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, + "machine dependent"); +SYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, + "user-level"); +SYSCTL_NODE(, CTL_P1003_1B, p1003_1b, CTLFLAG_RW, 0, + "p1003_1b, (see p1003_1b.h)"); + +SYSCTL_NODE(, OID_AUTO, compat, CTLFLAG_RW, 0, + "Compatibility code"); +SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW, 0, + "Security"); +#ifdef REGRESSION +SYSCTL_NODE(, OID_AUTO, regression, CTLFLAG_RW, 0, + "Regression test MIB"); +#endif +#endif + +SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, + osrelease, 0, "Operating system release"); + +SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, + 0, BSD, "Operating system revision"); + +#ifndef __rtems__ +SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, + version, 0, "Kernel version"); +#endif + +SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, + ostype, 0, "Operating system type"); + +#ifndef __rtems__ +extern int osreldate; +SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, + &osreldate, 0, "Operating system release date"); + +SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, + &maxproc, 0, "Maximum number of processes"); + +SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW, + &maxprocperuid, 0, "Maximum processes allowed per userid"); + +SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RD, + &maxusers, 0, "Hint for kernel tuning"); + +SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, + 0, ARG_MAX, "Maximum bytes of argument to execve(2)"); + +SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, + 0, _POSIX_VERSION, "Version of POSIX attempting to comply to"); + +SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, + 0, NGROUPS_MAX, "Maximum number of groups a user can belong to"); + +SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, + 0, 1, "Whether job control is available"); + +#ifdef _POSIX_SAVED_IDS +SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, + 0, 1, "Whether saved set-group/user ID is available"); +#else +SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, + 0, 0, "Whether saved set-group/user ID is available"); +#endif + +char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ + +SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW, + kernelname, sizeof kernelname, "Name of kernel file booted"); + +#ifdef SMP +SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, + &mp_ncpus, 0, "Number of active CPUs"); +#else +SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, + 0, 1, "Number of active CPUs"); +#endif + +SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, + 0, BYTE_ORDER, "System byte order"); + +SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, + 0, PAGE_SIZE, "System memory page size"); + +static int +sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) +{ + u_long val; + + val = ctob(physmem); + return (sysctl_handle_long(oidp, &val, 0, req)); +} + +SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_ULONG | CTLFLAG_RD, + 0, 0, sysctl_hw_physmem, "LU", ""); + +static int +sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) +{ + u_long val; + + val = ctob(physmem - cnt.v_wire_count); + return (sysctl_handle_long(oidp, &val, 0, req)); +} + +SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_ULONG | CTLFLAG_RD, + 0, 0, sysctl_hw_usermem, "LU", ""); + +SYSCTL_ULONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, ""); + +static char machine_arch[] = MACHINE_ARCH; +SYSCTL_STRING(_hw, HW_MACHINE_ARCH, machine_arch, CTLFLAG_RD, + machine_arch, 0, "System architecture"); + +char hostname[MAXHOSTNAMELEN]; + +static int +sysctl_hostname(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + char tmphostname[MAXHOSTNAMELEN]; + int error; + + pr = req->td->td_ucred->cr_prison; + if (pr != NULL) { + if (!jail_set_hostname_allowed && req->newptr) + return (EPERM); + /* + * Process is in jail, so make a local copy of jail + * hostname to get/set so we don't have to hold the jail + * mutex during the sysctl copyin/copyout activities. + */ + mtx_lock(&pr->pr_mtx); + bcopy(pr->pr_host, tmphostname, MAXHOSTNAMELEN); + mtx_unlock(&pr->pr_mtx); + + error = sysctl_handle_string(oidp, tmphostname, + sizeof pr->pr_host, req); + + if (req->newptr != NULL && error == 0) { + /* + * Copy the locally set hostname to the jail, if + * appropriate. + */ + mtx_lock(&pr->pr_mtx); + bcopy(tmphostname, pr->pr_host, MAXHOSTNAMELEN); + mtx_unlock(&pr->pr_mtx); + } + } else + error = sysctl_handle_string(oidp, + hostname, sizeof hostname, req); + return (error); +} + +SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, + CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_PRISON, + 0, 0, sysctl_hostname, "A", "Hostname"); + +static int regression_securelevel_nonmonotonic = 0; + +#ifdef REGRESSION +SYSCTL_INT(_regression, OID_AUTO, securelevel_nonmonotonic, CTLFLAG_RW, + ®ression_securelevel_nonmonotonic, 0, "securelevel may be lowered"); +#endif + +int securelevel = -1; +struct mtx securelevel_mtx; + +MTX_SYSINIT(securelevel_lock, &securelevel_mtx, "securelevel mutex lock", + MTX_DEF); + +static int +sysctl_kern_securelvl(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int error, level; + + pr = req->td->td_ucred->cr_prison; + + /* + * If the process is in jail, return the maximum of the global and + * local levels; otherwise, return the global level. + */ + if (pr != NULL) { + mtx_lock(&pr->pr_mtx); + level = imax(securelevel, pr->pr_securelevel); + mtx_unlock(&pr->pr_mtx); + } else + level = securelevel; + error = sysctl_handle_int(oidp, &level, 0, req); + if (error || !req->newptr) + return (error); + /* + * Permit update only if the new securelevel exceeds the + * global level, and local level if any. + */ + if (pr != NULL) { + mtx_lock(&pr->pr_mtx); + if (!regression_securelevel_nonmonotonic && + (level < imax(securelevel, pr->pr_securelevel))) { + mtx_unlock(&pr->pr_mtx); + return (EPERM); + } + pr->pr_securelevel = level; + mtx_unlock(&pr->pr_mtx); + } else { + mtx_lock(&securelevel_mtx); + if (!regression_securelevel_nonmonotonic && + (level < securelevel)) { + mtx_unlock(&securelevel_mtx); + return (EPERM); + } + securelevel = level; + mtx_unlock(&securelevel_mtx); + } + return (error); +} + +SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, + CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_kern_securelvl, + "I", "Current secure level"); + +char domainname[MAXHOSTNAMELEN]; +SYSCTL_STRING(_kern, KERN_NISDOMAINNAME, domainname, CTLFLAG_RW, + &domainname, sizeof(domainname), "Name of the current YP/NIS domain"); + +u_long hostid; +SYSCTL_ULONG(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "Host ID"); + +/* + * This is really cheating. These actually live in the libc, something + * which I'm not quite sure is a good idea anyway, but in order for + * getnext and friends to actually work, we define dummies here. + */ +SYSCTL_STRING(_user, USER_CS_PATH, cs_path, CTLFLAG_RD, + "", 0, "PATH that finds all the standard utilities"); +SYSCTL_INT(_user, USER_BC_BASE_MAX, bc_base_max, CTLFLAG_RD, + 0, 0, "Max ibase/obase values in bc(1)"); +SYSCTL_INT(_user, USER_BC_DIM_MAX, bc_dim_max, CTLFLAG_RD, + 0, 0, "Max array size in bc(1)"); +SYSCTL_INT(_user, USER_BC_SCALE_MAX, bc_scale_max, CTLFLAG_RD, + 0, 0, "Max scale value in bc(1)"); +SYSCTL_INT(_user, USER_BC_STRING_MAX, bc_string_max, CTLFLAG_RD, + 0, 0, "Max string length in bc(1)"); +SYSCTL_INT(_user, USER_COLL_WEIGHTS_MAX, coll_weights_max, CTLFLAG_RD, + 0, 0, "Maximum number of weights assigned to an LC_COLLATE locale entry"); +SYSCTL_INT(_user, USER_EXPR_NEST_MAX, expr_nest_max, CTLFLAG_RD, 0, 0, ""); +SYSCTL_INT(_user, USER_LINE_MAX, line_max, CTLFLAG_RD, + 0, 0, "Max length (bytes) of a text-processing utility's input line"); +SYSCTL_INT(_user, USER_RE_DUP_MAX, re_dup_max, CTLFLAG_RD, + 0, 0, "Maximum number of repeats of a regexp permitted"); +SYSCTL_INT(_user, USER_POSIX2_VERSION, posix2_version, CTLFLAG_RD, + 0, 0, + "The version of POSIX 1003.2 with which the system attempts to comply"); +SYSCTL_INT(_user, USER_POSIX2_C_BIND, posix2_c_bind, CTLFLAG_RD, + 0, 0, "Whether C development supports the C bindings option"); +SYSCTL_INT(_user, USER_POSIX2_C_DEV, posix2_c_dev, CTLFLAG_RD, + 0, 0, "Whether system supports the C development utilities option"); +SYSCTL_INT(_user, USER_POSIX2_CHAR_TERM, posix2_char_term, CTLFLAG_RD, + 0, 0, ""); +SYSCTL_INT(_user, USER_POSIX2_FORT_DEV, posix2_fort_dev, CTLFLAG_RD, + 0, 0, "Whether system supports FORTRAN development utilities"); +SYSCTL_INT(_user, USER_POSIX2_FORT_RUN, posix2_fort_run, CTLFLAG_RD, + 0, 0, "Whether system supports FORTRAN runtime utilities"); +SYSCTL_INT(_user, USER_POSIX2_LOCALEDEF, posix2_localedef, CTLFLAG_RD, + 0, 0, "Whether system supports creation of locales"); +SYSCTL_INT(_user, USER_POSIX2_SW_DEV, posix2_sw_dev, CTLFLAG_RD, + 0, 0, "Whether system supports software development utilities"); +SYSCTL_INT(_user, USER_POSIX2_UPE, posix2_upe, CTLFLAG_RD, + 0, 0, "Whether system supports the user portability utilities"); +SYSCTL_INT(_user, USER_STREAM_MAX, stream_max, CTLFLAG_RD, + 0, 0, "Min Maximum number of streams a process may have open at one time"); +SYSCTL_INT(_user, USER_TZNAME_MAX, tzname_max, CTLFLAG_RD, + 0, 0, "Min Maximum number of types supported for timezone names"); + +#include <sys/vnode.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, vnode, CTLFLAG_RD, + 0, sizeof(struct vnode), "sizeof(struct vnode)"); + +SYSCTL_INT(_debug_sizeof, OID_AUTO, proc, CTLFLAG_RD, + 0, sizeof(struct proc), "sizeof(struct proc)"); + +#include <sys/conf.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD, + 0, sizeof(struct cdev), "sizeof(struct cdev)"); + +#include <sys/bio.h> +#include <sys/buf.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, bio, CTLFLAG_RD, + 0, sizeof(struct bio), "sizeof(struct bio)"); +SYSCTL_INT(_debug_sizeof, OID_AUTO, buf, CTLFLAG_RD, + 0, sizeof(struct buf), "sizeof(struct buf)"); + +#include <sys/user.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, kinfo_proc, CTLFLAG_RD, + 0, sizeof(struct kinfo_proc), "sizeof(struct kinfo_proc)"); + +#endif /* __rtems__ */ diff --git a/cpukit/libnetworking/kern/kern_sysctl.c b/cpukit/libnetworking/kern/kern_sysctl.c new file mode 100644 index 0000000000..4ad2d380bb --- /dev/null +++ b/cpukit/libnetworking/kern/kern_sysctl.c @@ -0,0 +1,1537 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Karels at Berkeley Software Design, Inc. + * + * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD + * project, to make these variables more userfriendly. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 + * $FreeBSD: src/sys/kern/kern_sysctl.c,v 1.135 2002/10/27 07:12:34 rwatson Exp $ + */ + +#ifndef __rtems__ +#include "opt_compat.h" +#include "opt_mac.h" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#ifndef __rtems__ +#include <sys/mac.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> +#include <sys/sysproto.h> +#else +#include <sys/buf.h> +#endif +#include <vm/vm.h> +#include <vm/vm_extern.h> + +#ifndef __rtems__ +static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); +static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); +static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer"); +#else +/* + * Currently these mean nothing on RTEMS. + */ +#define M_SYSCTLOID 1 +#define M_SYSCTLTMP 2 +#define M_ZERO 0 + +typedef unsigned long *uintptr_t; + +#define mtx_lock(l) +#define mtx_unlock(l) + +#endif + +#ifndef __rtems__ +/* + * Locking - this locks the sysctl tree in memory. + */ +static struct sx sysctllock; +#endif + +#ifdef __rtems__ +#define SYSCTL_LOCK() +#define SYSCTL_UNLOCK() +#define SYSCTL_INIT() +#else +#define SYSCTL_LOCK() sx_xlock(&sysctllock) +#define SYSCTL_UNLOCK() sx_xunlock(&sysctllock) +#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl sysctllock") +#endif + +static int sysctl_root(SYSCTL_HANDLER_ARGS); + +struct sysctl_oid_list sysctl__children; /* root list */ + +static struct sysctl_oid * +sysctl_find_oidname(const char *name, struct sysctl_oid_list *list) +{ + struct sysctl_oid *oidp; + + SLIST_FOREACH(oidp, list, oid_link) { + if (strcmp(oidp->oid_name, name) == 0) { + return (oidp); + } + } + return (NULL); +} + +/* + * Initialization of the MIB tree. + * + * Order by number in each list. + */ + +void +sysctl_register_oid(struct sysctl_oid *oidp) +{ + struct sysctl_oid_list *parent = oidp->oid_parent; + struct sysctl_oid *p; + struct sysctl_oid *q; + + /* + * First check if another oid with the same name already + * exists in the parent's list. + */ + p = sysctl_find_oidname(oidp->oid_name, parent); + if (p != NULL) { + if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + p->oid_refcnt++; + return; + } else { + printf("can't re-use a leaf (%s)!\n", p->oid_name); + return; + } + } + /* + * If this oid has a number OID_AUTO, give it a number which + * is greater than any current oid. + * NOTE: DO NOT change the starting value here, change it in + * <sys/sysctl.h>, and make sure it is at least 256 to + * accomodate e.g. net.inet.raw as a static sysctl node. + */ + if (oidp->oid_number == OID_AUTO) { + static int newoid = CTL_AUTO_START; + + oidp->oid_number = newoid++; + if (newoid == 0x7fffffff) + panic("out of oids"); + } +#if 0 + else if (oidp->oid_number >= CTL_AUTO_START) { + /* do not panic; this happens when unregistering sysctl sets */ + printf("static sysctl oid too high: %d", oidp->oid_number); + } +#endif + + /* + * Insert the oid into the parent's list in order. + */ + q = NULL; + SLIST_FOREACH(p, parent, oid_link) { + if (oidp->oid_number < p->oid_number) + break; + q = p; + } + if (q) + SLIST_INSERT_AFTER(q, oidp, oid_link); + else + SLIST_INSERT_HEAD(parent, oidp, oid_link); +} + +void +sysctl_unregister_oid(struct sysctl_oid *oidp) +{ + SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link); +} + +/* Initialize a new context to keep track of dynamically added sysctls. */ +int +sysctl_ctx_init(struct sysctl_ctx_list *c) +{ + + if (c == NULL) { + return (EINVAL); + } + TAILQ_INIT(c); + return (0); +} + +/* Free the context, and destroy all dynamic oids registered in this context */ +int +sysctl_ctx_free(struct sysctl_ctx_list *clist) +{ + struct sysctl_ctx_entry *e, *e1; + int error; + + error = 0; + /* + * First perform a "dry run" to check if it's ok to remove oids. + * XXX FIXME + * XXX This algorithm is a hack. But I don't know any + * XXX better solution for now... + */ + TAILQ_FOREACH(e, clist, link) { + error = sysctl_remove_oid(e->entry, 0, 0); + if (error) + break; + } + /* + * Restore deregistered entries, either from the end, + * or from the place where error occured. + * e contains the entry that was not unregistered + */ + if (error) + e1 = TAILQ_PREV(e, sysctl_ctx_list, link); + else + e1 = TAILQ_LAST(clist, sysctl_ctx_list); + while (e1 != NULL) { + sysctl_register_oid(e1->entry); + e1 = TAILQ_PREV(e1, sysctl_ctx_list, link); + } + if (error) + return(EBUSY); + /* Now really delete the entries */ + e = TAILQ_FIRST(clist); + while (e != NULL) { + e1 = TAILQ_NEXT(e, link); + error = sysctl_remove_oid(e->entry, 1, 0); + if (error) + panic("sysctl_remove_oid: corrupt tree, entry: %s", + e->entry->oid_name); + free(e, M_SYSCTLOID); + e = e1; + } + return (error); +} + +/* Add an entry to the context */ +struct sysctl_ctx_entry * +sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) +{ + struct sysctl_ctx_entry *e; + + if (clist == NULL || oidp == NULL) + return(NULL); + e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK); + e->entry = oidp; + TAILQ_INSERT_HEAD(clist, e, link); + return (e); +} + +/* Find an entry in the context */ +struct sysctl_ctx_entry * +sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) +{ + struct sysctl_ctx_entry *e; + + if (clist == NULL || oidp == NULL) + return(NULL); + TAILQ_FOREACH(e, clist, link) { + if(e->entry == oidp) + return(e); + } + return (e); +} + +/* + * Delete an entry from the context. + * NOTE: this function doesn't free oidp! You have to remove it + * with sysctl_remove_oid(). + */ +int +sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) +{ + struct sysctl_ctx_entry *e; + + if (clist == NULL || oidp == NULL) + return (EINVAL); + e = sysctl_ctx_entry_find(clist, oidp); + if (e != NULL) { + TAILQ_REMOVE(clist, e, link); + free(e, M_SYSCTLOID); + return (0); + } else + return (ENOENT); +} + +/* + * Remove dynamically created sysctl trees. + * oidp - top of the tree to be removed + * del - if 0 - just deregister, otherwise free up entries as well + * recurse - if != 0 traverse the subtree to be deleted + */ +int +sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse) +{ + struct sysctl_oid *p; + int error; + + if (oidp == NULL) + return(EINVAL); + if ((oidp->oid_kind & CTLFLAG_DYN) == 0) { + printf("can't remove non-dynamic nodes!\n"); + return (EINVAL); + } + /* + * WARNING: normal method to do this should be through + * sysctl_ctx_free(). Use recursing as the last resort + * method to purge your sysctl tree of leftovers... + * However, if some other code still references these nodes, + * it will panic. + */ + if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + if (oidp->oid_refcnt == 1) { + SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) { + if (!recurse) + return (ENOTEMPTY); + error = sysctl_remove_oid(p, del, recurse); + if (error) + return (error); + } + if (del) + free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID); + } + } + if (oidp->oid_refcnt > 1 ) { + oidp->oid_refcnt--; + } else { + if (oidp->oid_refcnt == 0) { + printf("Warning: bad oid_refcnt=%u (%s)!\n", + oidp->oid_refcnt, oidp->oid_name); + return (EINVAL); + } + sysctl_unregister_oid(oidp); + if (del) { + if (oidp->descr) + free((void *)(uintptr_t)(const void *)oidp->descr, M_SYSCTLOID); + free((void *)(uintptr_t)(const void *)oidp->oid_name, + M_SYSCTLOID); + free(oidp, M_SYSCTLOID); + } + } + return (0); +} + +/* + * Create new sysctls at run time. + * clist may point to a valid context initialized with sysctl_ctx_init(). + */ +struct sysctl_oid * +sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, + int number, const char *name, int kind, void *arg1, int arg2, + int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr) +{ + struct sysctl_oid *oidp; + ssize_t len; + char *newname; + + /* You have to hook up somewhere.. */ + if (parent == NULL) + return(NULL); + /* Check if the node already exists, otherwise create it */ + oidp = sysctl_find_oidname(name, parent); + if (oidp != NULL) { + if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + oidp->oid_refcnt++; + /* Update the context */ + if (clist != NULL) + sysctl_ctx_entry_add(clist, oidp); + return (oidp); + } else { + printf("can't re-use a leaf (%s)!\n", name); + return (NULL); + } + } + oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO); + oidp->oid_parent = parent; + SLIST_NEXT(oidp, oid_link) = NULL; + oidp->oid_number = number; + oidp->oid_refcnt = 1; + len = strlen(name); + newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); + bcopy(name, newname, len + 1); + newname[len] = '\0'; + oidp->oid_name = newname; + oidp->oid_handler = handler; + oidp->oid_kind = CTLFLAG_DYN | kind; + if ((kind & CTLTYPE) == CTLTYPE_NODE) { + /* Allocate space for children */ + SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list), + M_SYSCTLOID, M_WAITOK); + SLIST_INIT(SYSCTL_CHILDREN(oidp)); + } else { + oidp->oid_arg1 = arg1; + oidp->oid_arg2 = arg2; + } + oidp->oid_fmt = fmt; + if (descr) { + int len = strlen(descr) + 1; + oidp->descr = malloc(len, M_SYSCTLOID, M_WAITOK); + if (oidp->descr) + strcpy((char *)(uintptr_t)(const void *)oidp->descr, descr); + } + /* Update the context, if used */ + if (clist != NULL) + sysctl_ctx_entry_add(clist, oidp); + /* Register this oid */ + sysctl_register_oid(oidp); + return (oidp); +} + +/* + * Register the kernel's oids on startup. + */ +SET_DECLARE(sysctl_set, struct sysctl_oid); + +void +sysctl_register_all(void *arg) +{ + struct sysctl_oid **oidp; + + SYSCTL_INIT(); + SET_FOREACH(oidp, sysctl_set) + sysctl_register_oid(*oidp); +} +SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); + +/* + * "Staff-functions" + * + * These functions implement a presently undocumented interface + * used by the sysctl program to walk the tree, and get the type + * so it can print the value. + * This interface is under work and consideration, and should probably + * be killed with a big axe by the first person who can find the time. + * (be aware though, that the proper interface isn't as obvious as it + * may seem, there are various conflicting requirements. + * + * {0,0} printf the entire MIB-tree. + * {0,1,...} return the name of the "..." OID. + * {0,2,...} return the next OID. + * {0,3} return the OID of the name in "new" + * {0,4,...} return the kind & format info for the "..." OID. + * {0,5,...} return the description the "..." OID. + */ + +static void +sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) +{ + int k; + struct sysctl_oid *oidp; + + SLIST_FOREACH(oidp, l, oid_link) { + + for (k=0; k<i; k++) + printf(" "); + + printf("%d %s ", oidp->oid_number, oidp->oid_name); + + printf("%c%c", + oidp->oid_kind & CTLFLAG_RD ? 'R':' ', + oidp->oid_kind & CTLFLAG_WR ? 'W':' '); + + if (oidp->oid_handler) + printf(" *Handler"); + + switch (oidp->oid_kind & CTLTYPE) { + case CTLTYPE_NODE: + printf(" Node\n"); + if (!oidp->oid_handler) { + sysctl_sysctl_debug_dump_node( + oidp->oid_arg1, i+2); + } + break; + case CTLTYPE_INT: printf(" Int\n"); break; + case CTLTYPE_STRING: printf(" String\n"); break; + case CTLTYPE_QUAD: printf(" Quad\n"); break; + case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; + default: printf("\n"); + } + + } +} + +static int +sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS) +{ +#ifndef __rtems__ + int error; + + error = suser(req->td); + if (error) + return error; +#endif + sysctl_sysctl_debug_dump_node(&sysctl__children, 0); + return ENOENT; +} + +SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, + 0, 0, sysctl_sysctl_debug, "-", ""); + +static int +sysctl_sysctl_name(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *) arg1; + u_int namelen = arg2; + int error = 0; + struct sysctl_oid *oid; + struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; + char buf[10]; + + while (namelen) { + if (!lsp) { + snprintf(buf,sizeof(buf),"%d",*name); + if (req->oldidx) + error = SYSCTL_OUT(req, ".", 1); + if (!error) + error = SYSCTL_OUT(req, buf, strlen(buf)); + if (error) + return (error); + namelen--; + name++; + continue; + } + lsp2 = 0; + SLIST_FOREACH(oid, lsp, oid_link) { + if (oid->oid_number != *name) + continue; + + if (req->oldidx) + error = SYSCTL_OUT(req, ".", 1); + if (!error) + error = SYSCTL_OUT(req, oid->oid_name, + strlen(oid->oid_name)); + if (error) + return (error); + + namelen--; + name++; + + if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) + break; + + if (oid->oid_handler) + break; + + lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; + break; + } + lsp = lsp2; + } + return (SYSCTL_OUT(req, "", 1)); +} + +SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); + +static int +sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, + int *next, int *len, int level, struct sysctl_oid **oidpp) +{ + struct sysctl_oid *oidp; + + *len = level; + SLIST_FOREACH(oidp, lsp, oid_link) { + *next = oidp->oid_number; + *oidpp = oidp; + + if (oidp->oid_kind & CTLFLAG_SKIP) + continue; + + if (!namelen) { + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + return 0; + if (oidp->oid_handler) + /* We really should call the handler here...*/ + return 0; + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, + len, level+1, oidpp)) + return 0; + goto next; + } + + if (oidp->oid_number < *name) + continue; + + if (oidp->oid_number > *name) { + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + return 0; + if (oidp->oid_handler) + return 0; + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, + next+1, len, level+1, oidpp)) + return (0); + goto next; + } + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + continue; + + if (oidp->oid_handler) + continue; + + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, + len, level+1, oidpp)) + return (0); + next: + namelen = 1; + *len = level; + } + return 1; +} + +static int +sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *) arg1; + u_int namelen = arg2; + int i, j, error; + struct sysctl_oid *oid; + struct sysctl_oid_list *lsp = &sysctl__children; + int newoid[CTL_MAXNAME]; + + i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid); + if (i) + return ENOENT; + error = SYSCTL_OUT(req, newoid, j * sizeof (int)); + return (error); +} + +SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); + +static int +name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp) +{ + int i; + struct sysctl_oid *oidp; + struct sysctl_oid_list *lsp = &sysctl__children; + char *p; + + if (!*name) + return ENOENT; + + p = name + strlen(name) - 1 ; + if (*p == '.') + *p = '\0'; + + *len = 0; + + for (p = name; *p && *p != '.'; p++) + ; + i = *p; + if (i == '.') + *p = '\0'; + + oidp = SLIST_FIRST(lsp); + + while (oidp && *len < CTL_MAXNAME) { + if (strcmp(name, oidp->oid_name)) { + oidp = SLIST_NEXT(oidp, oid_link); + continue; + } + *oid++ = oidp->oid_number; + (*len)++; + + if (!i) { + if (oidpp) + *oidpp = oidp; + return (0); + } + + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + break; + + if (oidp->oid_handler) + break; + + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + oidp = SLIST_FIRST(lsp); + name = p+1; + for (p = name; *p && *p != '.'; p++) + ; + i = *p; + if (i == '.') + *p = '\0'; + } + return ENOENT; +} + +static int +sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS) +{ + char *p; + int error, oid[CTL_MAXNAME], len; + struct sysctl_oid *op = 0; + + if (!req->newlen) + return ENOENT; + if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */ + return (ENAMETOOLONG); + + p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); + + error = SYSCTL_IN(req, p, req->newlen); + if (error) { + free(p, M_SYSCTL); + return (error); + } + + p [req->newlen] = '\0'; + + error = name2oid(p, oid, &len, &op); + + free(p, M_SYSCTL); + + if (error) + return (error); + + error = SYSCTL_OUT(req, oid, len * sizeof *oid); + return (error); +} + +SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, + sysctl_sysctl_name2oid, "I", ""); + +static int +sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS) +{ + struct sysctl_oid *oid; + int error; + + error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); + if (error) + return (error); + + if (!oid->oid_fmt) + return (ENOENT); + error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind)); + if (error) + return (error); + error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1); + return (error); +} + + +SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); + +static int +sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS) +{ + struct sysctl_oid *oid; + int error; + + error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); + if (error) + return (error); + + if (!oid->descr) + return (ENOENT); + error = SYSCTL_OUT(req, oid->descr, strlen(oid->descr) + 1); + return (error); +} + +SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, ""); + +/* + * Default "handler" functions. + */ + +/* + * Handle an int, signed or unsigned. + * Two cases: + * a variable: point arg1 at it. + * a constant: pass it in arg2. + */ + +int +sysctl_handle_int(SYSCTL_HANDLER_ARGS) +{ + int tmpout, error = 0; + + /* + * Attempt to get a coherent snapshot by making a copy of the data. + */ + if (arg1) + tmpout = *(int *)arg1; + else + tmpout = arg2; + error = SYSCTL_OUT(req, &tmpout, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + return (error); +} + +/* + * Handle a long, signed or unsigned. arg1 points to it. + */ + +int +sysctl_handle_long(SYSCTL_HANDLER_ARGS) +{ + int error = 0; + long tmpout; + + /* + * Attempt to get a coherent snapshot by making a copy of the data. + */ + if (!arg1) + return (EINVAL); + tmpout = *(long *)arg1; + error = SYSCTL_OUT(req, &tmpout, sizeof(long)); + + if (error || !req->newptr) + return (error); + + error = SYSCTL_IN(req, arg1, sizeof(long)); + return (error); +} + +/* + * Handle our generic '\0' terminated 'C' string. + * Two cases: + * a variable string: point arg1 at it, arg2 is max length. + * a constant string: point arg1 at it, arg2 is zero. + */ + +int +sysctl_handle_string(SYSCTL_HANDLER_ARGS) +{ + int error=0; + char *tmparg; + size_t outlen; + + /* + * Attempt to get a coherent snapshot by copying to a + * temporary kernel buffer. + */ +retry: + outlen = strlen((char *)arg1)+1; + tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK); + + if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) { + free(tmparg, M_SYSCTLTMP); + goto retry; + } + + error = SYSCTL_OUT(req, tmparg, outlen); + free(tmparg, M_SYSCTLTMP); + + if (error || !req->newptr) + return (error); + + if ((req->newlen - req->newidx) >= arg2) { + error = EINVAL; + } else { + arg2 = (req->newlen - req->newidx); + error = SYSCTL_IN(req, arg1, arg2); + ((char *)arg1)[arg2] = '\0'; + } + + return (error); +} + +/* + * Handle any kind of opaque data. + * arg1 points to it, arg2 is the size. + */ + +int +sysctl_handle_opaque(SYSCTL_HANDLER_ARGS) +{ + int error; + void *tmparg; + + /* + * Attempt to get a coherent snapshot, either by wiring the + * user space buffer or copying to a temporary kernel buffer + * depending on the size of the data. + */ + if (arg2 > PAGE_SIZE) { + sysctl_wire_old_buffer(req, arg2); + error = SYSCTL_OUT(req, arg1, arg2); + } else { + tmparg = malloc(arg2, M_SYSCTLTMP, M_WAITOK); + bcopy(arg1, tmparg, arg2); + error = SYSCTL_OUT(req, tmparg, arg2); + free(tmparg, M_SYSCTLTMP); + } + + if (error || !req->newptr) + return (error); + + error = SYSCTL_IN(req, arg1, arg2); + + return (error); +} + +/* + * Transfer functions to/from kernel space. + * XXX: rather untested at this point + */ +static int +sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) +{ + size_t i = 0; + + if (req->oldptr) { + i = l; + if (req->oldlen <= req->oldidx) + i = 0; + else + if (i > req->oldlen - req->oldidx) + i = req->oldlen - req->oldidx; + if (i > 0) + bcopy(p, (char *)req->oldptr + req->oldidx, i); + } + req->oldidx += l; + if (req->oldptr && i != l) + return (ENOMEM); + return (0); +} + +static int +sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) +{ + if (!req->newptr) + return 0; + if (req->newlen - req->newidx < l) + return (EINVAL); + bcopy((char *)req->newptr + req->newidx, p, l); + req->newidx += l; + return (0); +} + +int +kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, + size_t *oldlenp, void *new, size_t newlen, size_t *retval) +{ + int error = 0; + struct sysctl_req req; + + bzero(&req, sizeof req); + + req.td = td; + + if (oldlenp) { + req.oldlen = *oldlenp; + } + + if (old) { + req.oldptr= old; + } + + if (new != NULL) { + req.newlen = newlen; + req.newptr = new; + } + + req.oldfunc = sysctl_old_kernel; + req.newfunc = sysctl_new_kernel; + req.lock = 1; + + SYSCTL_LOCK(); + + error = sysctl_root(0, name, namelen, &req); + + if (req.lock == 2) +#ifdef __rtems__ + printf ("kern_sysctl: vsunlock needs to be called!\n"); +#else + vsunlock(req.oldptr, req.oldlen); +#endif + + SYSCTL_UNLOCK(); + + if (error && error != ENOMEM) + return (error); + + if (retval) { + if (req.oldptr && req.oldidx > req.oldlen) + *retval = req.oldlen; + else + *retval = req.oldidx; + } + return (error); +} + +int +kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp, + void *new, size_t newlen, size_t *retval) +{ + int oid[CTL_MAXNAME]; + size_t oidlen, plen; + int error; + + oid[0] = 0; /* sysctl internal magic */ + oid[1] = 3; /* name2oid */ + oidlen = sizeof(oid); + + error = kernel_sysctl(td, oid, 2, oid, &oidlen, + (void *)name, strlen(name), &plen); + if (error) + return (error); + + error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp, + new, newlen, retval); + return (error); +} + +/* + * Transfer function to/from user space. + */ +static int +sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) +{ + int error = 0; + size_t i = 0; + +#ifndef __rtems__ + if (req->lock == 1 && req->oldptr) + WITNESS_SLEEP(1, NULL); +#endif + if (req->oldptr) { + i = l; + if (req->oldlen <= req->oldidx) + i = 0; + else + if (i > req->oldlen - req->oldidx) + i = req->oldlen - req->oldidx; + if (i > 0) + error = copyout(p, (char *)req->oldptr + req->oldidx, + i); + } + req->oldidx += l; + if (error) + return (error); + if (req->oldptr && i < l) + return (ENOMEM); + return (0); +} + +static int +sysctl_new_user(struct sysctl_req *req, void *p, size_t l) +{ + int error; + + if (!req->newptr) + return 0; + if (req->newlen - req->newidx < l) + return (EINVAL); + error = copyin((char *)req->newptr + req->newidx, p, l); + req->newidx += l; + return (error); +} + +/* + * Wire the user space destination buffer. If set to a value greater than + * zero, the len parameter limits the maximum amount of wired memory. + * + * XXX - The len parameter is currently ignored due to the lack of + * a place to save it in the sysctl_req structure so that the matching + * amount of memory can be unwired in the sysctl exit code. + */ +void +sysctl_wire_old_buffer(struct sysctl_req *req, size_t len) +{ + if (req->lock == 1 && req->oldptr && req->oldfunc == sysctl_old_user) { +#ifndef __rtems__ + vslock(req->oldptr, req->oldlen); +#endif + req->lock = 2; + } +} + +int +sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, + int *nindx, struct sysctl_req *req) +{ + struct sysctl_oid *oid; + int indx; + + oid = SLIST_FIRST(&sysctl__children); + indx = 0; + while (oid && indx < CTL_MAXNAME) { + if (oid->oid_number == name[indx]) { + indx++; + if (oid->oid_kind & CTLFLAG_NOLOCK) + req->lock = 0; + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + if (oid->oid_handler != NULL || + indx == namelen) { + *noid = oid; + if (nindx != NULL) + *nindx = indx; + return (0); + } + oid = SLIST_FIRST( + (struct sysctl_oid_list *)oid->oid_arg1); + } else if (indx == namelen) { + *noid = oid; + if (nindx != NULL) + *nindx = indx; + return (0); + } else { + return (ENOTDIR); + } + } else { + oid = SLIST_NEXT(oid, oid_link); + } + } + return (ENOENT); +} + +/* + * Traverse our tree, and find the right node, execute whatever it points + * to, and return the resulting error code. + */ + +static int +sysctl_root(SYSCTL_HANDLER_ARGS) +{ + struct sysctl_oid *oid; + int error, indx; + + error = sysctl_find_oid(arg1, arg2, &oid, &indx, req); + if (error) + return (error); + + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + /* + * You can't call a sysctl when it's a node, but has + * no handler. Inform the user that it's a node. + * The indx may or may not be the same as namelen. + */ + if (oid->oid_handler == NULL) + return (EISDIR); + } + + /* Is this sysctl writable? */ + if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) + return (EPERM); + +#ifndef __rtems__ + KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL")); + + /* Is this sysctl sensitive to securelevels? */ + if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) { + error = securelevel_gt(req->td->td_ucred, 0); + if (error) + return (error); + } + + /* Is this sysctl writable by only privileged users? */ + if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) { + int flags; + + if (oid->oid_kind & CTLFLAG_PRISON) + flags = PRISON_ROOT; + else + flags = 0; + error = suser_cred(req->td->td_ucred, flags); + if (error) + return (error); + } +#endif + + if (!oid->oid_handler) + return EINVAL; + + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) + error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx, + req); + else + error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2, + req); + return (error); +} + +#ifndef _SYS_SYSPROTO_H_ +struct sysctl_args { + int *name; + u_int namelen; + void *old; + size_t *oldlenp; + void *new; + size_t newlen; +}; +#endif + +/* + * MPSAFE + */ +int +__sysctl(struct thread *td, struct sysctl_args *uap) +{ + int error, name[CTL_MAXNAME]; + size_t j; + + if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) + return (EINVAL); + + error = copyin(uap->name, &name, uap->namelen * sizeof(int)); + if (error) + return (error); + + mtx_lock(&Giant); + + error = userland_sysctl(td, name, uap->namelen, + uap->old, uap->oldlenp, 0, + uap->new, uap->newlen, &j); + if (error && error != ENOMEM) + goto done2; + if (uap->oldlenp) { + int i = copyout(&j, uap->oldlenp, sizeof(j)); + if (i) + error = i; + } +done2: + mtx_unlock(&Giant); + return (error); +} + +/* + * This is used from various compatibility syscalls too. That's why name + * must be in kernel space. + */ +int +userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, + size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval) +{ + int error = 0; + struct sysctl_req req, req2; + + bzero(&req, sizeof req); + + req.td = td; + + if (oldlenp) { + if (inkernel) { + req.oldlen = *oldlenp; + } else { + error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); + if (error) + return (error); + } + } + + if (old) { +#ifndef __rtems__ + if (!useracc(old, req.oldlen, VM_PROT_WRITE)) + return (EFAULT); +#endif + req.oldptr= old; + } + + if (new != NULL) { +#ifndef __rtems__ + if (!useracc(new, req.newlen, VM_PROT_READ)) + return (EFAULT); +#endif + req.newlen = newlen; + req.newptr = new; + } + + req.oldfunc = sysctl_old_user; + req.newfunc = sysctl_new_user; + req.lock = 1; + + SYSCTL_LOCK(); + +#ifdef MAC + error = mac_check_system_sysctl(td->td_ucred, name, namelen, old, + oldlenp, inkernel, new, newlen); + if (error) { + SYSCTL_UNLOCK(); + return (error); + } +#endif + + do { + req2 = req; + error = sysctl_root(0, name, namelen, &req2); + } while (error == EAGAIN); + + req = req2; +#ifndef __rtems__ + if (req.lock == 2) + vsunlock(req.oldptr, req.oldlen); +#endif + + SYSCTL_UNLOCK(); + + if (error && error != ENOMEM) + return (error); + + if (retval) { + if (req.oldptr && req.oldidx > req.oldlen) + *retval = req.oldlen; + else + *retval = req.oldidx; + } + return (error); +} + +#ifdef COMPAT_43 +#include <sys/socket.h> +#include <vm/vm_param.h> + +#define KINFO_PROC (0<<8) +#define KINFO_RT (1<<8) +#define KINFO_VNODE (2<<8) +#define KINFO_FILE (3<<8) +#define KINFO_METER (4<<8) +#define KINFO_LOADAVG (5<<8) +#define KINFO_CLOCKRATE (6<<8) + +/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ +#define KINFO_BSDI_SYSINFO (101<<8) + +/* + * XXX this is bloat, but I hope it's better here than on the potentially + * limited kernel stack... -Peter + */ + +static struct { + int bsdi_machine; /* "i386" on BSD/386 */ +/* ^^^ this is an offset to the string, relative to the struct start */ + char *pad0; + long pad1; + long pad2; + long pad3; + u_long pad4; + u_long pad5; + u_long pad6; + + int bsdi_ostype; /* "BSD/386" on BSD/386 */ + int bsdi_osrelease; /* "1.1" on BSD/386 */ + long pad7; + long pad8; + char *pad9; + + long pad10; + long pad11; + int pad12; + long pad13; + quad_t pad14; + long pad15; + + struct timeval pad16; + /* we dont set this, because BSDI's uname used gethostname() instead */ + int bsdi_hostname; /* hostname on BSD/386 */ + + /* the actual string data is appended here */ + +} bsdi_si; +/* + * this data is appended to the end of the bsdi_si structure during copyout. + * The "char *" offsets are relative to the base of the bsdi_si struct. + * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings + * should not exceed the length of the buffer here... (or else!! :-) + */ +static char bsdi_strings[80]; /* It had better be less than this! */ + +#ifndef _SYS_SYSPROTO_H_ +struct getkerninfo_args { + int op; + char *where; + size_t *size; + int arg; +}; +#endif + +/* + * MPSAFE + */ +int +ogetkerninfo(struct thread *td, struct getkerninfo_args *uap) +{ + int error, name[6]; + size_t size; + u_int needed = 0; + + mtx_lock(&Giant); + + switch (uap->op & 0xff00) { + + case KINFO_RT: + name[0] = CTL_NET; + name[1] = PF_ROUTE; + name[2] = 0; + name[3] = (uap->op & 0xff0000) >> 16; + name[4] = uap->op & 0xff; + name[5] = uap->arg; + error = userland_sysctl(td, name, 6, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_VNODE: + name[0] = CTL_KERN; + name[1] = KERN_VNODE; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_PROC: + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = uap->op & 0xff; + name[3] = uap->arg; + error = userland_sysctl(td, name, 4, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_FILE: + name[0] = CTL_KERN; + name[1] = KERN_FILE; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_METER: + name[0] = CTL_VM; + name[1] = VM_METER; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_LOADAVG: + name[0] = CTL_VM; + name[1] = VM_LOADAVG; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_CLOCKRATE: + name[0] = CTL_KERN; + name[1] = KERN_CLOCKRATE; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_BSDI_SYSINFO: { + /* + * this is pretty crude, but it's just enough for uname() + * from BSDI's 1.x libc to work. + * + * *size gives the size of the buffer before the call, and + * the amount of data copied after a successful call. + * If successful, the return value is the amount of data + * available, which can be larger than *size. + * + * BSDI's 2.x product apparently fails with ENOMEM if *size + * is too small. + */ + + u_int left; + char *s; + + bzero((char *)&bsdi_si, sizeof(bsdi_si)); + bzero(bsdi_strings, sizeof(bsdi_strings)); + + s = bsdi_strings; + + bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); + strcpy(s, ostype); + s += strlen(s) + 1; + + bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); + strcpy(s, osrelease); + s += strlen(s) + 1; + + bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); + strcpy(s, machine); + s += strlen(s) + 1; + + needed = sizeof(bsdi_si) + (s - bsdi_strings); + + if ((uap->where == NULL) || (uap->size == NULL)) { + /* process is asking how much buffer to supply.. */ + size = needed; + error = 0; + break; + } + + if ((error = copyin(uap->size, &size, sizeof(size))) != 0) + break; + + /* if too much buffer supplied, trim it down */ + if (size > needed) + size = needed; + + /* how much of the buffer is remaining */ + left = size; + + if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) + break; + + /* is there any point in continuing? */ + if (left > sizeof(bsdi_si)) { + left -= sizeof(bsdi_si); + error = copyout(&bsdi_strings, + uap->where + sizeof(bsdi_si), left); + } + break; + } + + default: + error = EOPNOTSUPP; + break; + } + if (error == 0) { + td->td_retval[0] = needed ? needed : size; + if (uap->size) { + error = copyout(&size, uap->size, sizeof(size)); + } + } + mtx_unlock(&Giant); + return (error); +} +#endif /* COMPAT_43 */ diff --git a/cpukit/libnetworking/kern/uipc_socket.c b/cpukit/libnetworking/kern/uipc_socket.c index a002e61476..a580cfea18 100644 --- a/cpukit/libnetworking/kern/uipc_socket.c +++ b/cpukit/libnetworking/kern/uipc_socket.c @@ -52,7 +52,7 @@ #include <limits.h> static int somaxconn = SOMAXCONN; -SYSCTL_INT(_kern, KERN_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, 0, ""); +SYSCTL_INT(_kern, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, 0, ""); /* * Socket operation routines. diff --git a/cpukit/libnetworking/kern/uipc_socket2.c b/cpukit/libnetworking/kern/uipc_socket2.c index 0539d2c5f3..466a7c9839 100644 --- a/cpukit/libnetworking/kern/uipc_socket2.c +++ b/cpukit/libnetworking/kern/uipc_socket2.c @@ -59,7 +59,7 @@ */ u_long sb_max = SB_MAX; /* XXX should be static */ -SYSCTL_INT(_kern, KERN_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, "") +SYSCTL_INT(_kern, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, ""); static u_long sb_efficiency = 8; /* parameter for sbreserve() */ SYSCTL_INT(_kern, OID_AUTO, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency, diff --git a/cpukit/libnetworking/net/if_ethersubr.c b/cpukit/libnetworking/net/if_ethersubr.c index 1c68ef74e0..bff084b0f8 100644 --- a/cpukit/libnetworking/net/if_ethersubr.c +++ b/cpukit/libnetworking/net/if_ethersubr.c @@ -895,6 +895,7 @@ ether_delmulti(ifr, ac) return (ENETRESET); } +SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); int diff --git a/cpukit/libnetworking/net/if_ppp.c b/cpukit/libnetworking/net/if_ppp.c index d4e0847655..3e4f8b25ff 100644 --- a/cpukit/libnetworking/net/if_ppp.c +++ b/cpukit/libnetworking/net/if_ppp.c @@ -179,8 +179,9 @@ struct compressor *ppp_compressors[8] = { extern struct ifqueue ipintrq; static struct timeval ppp_time; +#ifndef __rtems__ TEXT_SET(pseudo_set, ppp_rxdaemon); - +#endif static rtems_task ppp_rxdaemon(rtems_task_argument arg) { diff --git a/cpukit/libnetworking/net/rtsock.c b/cpukit/libnetworking/net/rtsock.c index 274f6fccff..af45607a3e 100644 --- a/cpukit/libnetworking/net/rtsock.c +++ b/cpukit/libnetworking/net/rtsock.c @@ -67,10 +67,8 @@ static struct mbuf * static int rt_msg2 __P((int, struct rt_addrinfo *, caddr_t, struct walkarg *)); static int rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); -#if !defined(__rtems__) static int sysctl_dumpentry __P((struct radix_node *rn, void *vw)); static int sysctl_iflist __P((int af, struct walkarg *w)); -#endif static int route_output __P((struct mbuf *, struct socket *)); static int route_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); @@ -677,7 +675,6 @@ rt_newaddrmsg(cmd, ifa, error, rt) /* * This is used in dumping the kernel table via sysctl(). */ -#if !defined(__rtems__) int sysctl_dumpentry(rn, vw) struct radix_node *rn; @@ -710,9 +707,7 @@ sysctl_dumpentry(rn, vw) } return (error); } -#endif -#if !defined(__rtems__) int sysctl_iflist(af, w) int af; @@ -739,7 +734,7 @@ sysctl_iflist(af, w) ifm->ifm_flags = (u_short)ifp->if_flags; ifm->ifm_data = ifp->if_data; ifm->ifm_addrs = info.rti_addrs; - error =0; + error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len); if (error) return (error); } @@ -758,7 +753,7 @@ sysctl_iflist(af, w) ifam->ifam_flags = ifa->ifa_flags; ifam->ifam_metric = ifa->ifa_metric; ifam->ifam_addrs = info.rti_addrs; - error = 0; + error = SYSCTL_OUT(w->w_req, w->w_tmem, len); if (error) return (error); } @@ -767,11 +762,9 @@ sysctl_iflist(af, w) } return (0); } -#endif -#if !defined(__rtems__) static int -sysctl_rtsock SYSCTL_HANDLER_ARGS +sysctl_rtsock(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; @@ -814,7 +807,6 @@ sysctl_rtsock SYSCTL_HANDLER_ARGS } SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock,""); -#endif /* * Definitions of protocols supported in the ROUTE domain. diff --git a/cpukit/libnetworking/netinet/icmp_var.h b/cpukit/libnetworking/netinet/icmp_var.h index 7657f31acf..e091ca2c61 100644 --- a/cpukit/libnetworking/netinet/icmp_var.h +++ b/cpukit/libnetworking/netinet/icmp_var.h @@ -72,6 +72,7 @@ struct icmpstat { } #ifdef KERNEL +SYSCTL_DECL(_net_inet_icmp); extern struct icmpstat icmpstat; #endif diff --git a/cpukit/libnetworking/netinet/if_ether.c b/cpukit/libnetworking/netinet/if_ether.c index 985ce6e7d9..c4b85aa38e 100644 --- a/cpukit/libnetworking/netinet/if_ether.c +++ b/cpukit/libnetworking/netinet/if_ether.c @@ -62,6 +62,7 @@ #define SIN(s) ((struct sockaddr_in *)s) #define SDL(s) ((struct sockaddr_dl *)s) +SYSCTL_DECL(_net_link_ether); SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); /* timer values */ diff --git a/cpukit/libnetworking/netinet/igmp_var.h b/cpukit/libnetworking/netinet/igmp_var.h index f408bf2bc1..9618dbd50c 100644 --- a/cpukit/libnetworking/netinet/igmp_var.h +++ b/cpukit/libnetworking/netinet/igmp_var.h @@ -93,6 +93,9 @@ void igmp_joingroup __P((struct in_multi *)); void igmp_leavegroup __P((struct in_multi *)); void igmp_fasttimo __P((void)); void igmp_slowtimo __P((void)); + +SYSCTL_DECL(_net_inet_igmp); + #endif /* diff --git a/cpukit/libnetworking/netinet/in_pcb.c b/cpukit/libnetworking/netinet/in_pcb.c index 116f70eebf..312594dae2 100644 --- a/cpukit/libnetworking/netinet/in_pcb.c +++ b/cpukit/libnetworking/netinet/in_pcb.c @@ -79,9 +79,8 @@ static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 44999 */ if ((var) < (min)) { (var) = (min); } \ else if ((var) > (max)) { (var) = (max); } -#if 0 static int -sysctl_net_ipport_check SYSCTL_HANDLER_ARGS +sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); @@ -95,7 +94,6 @@ sysctl_net_ipport_check SYSCTL_HANDLER_ARGS } return error; } -#endif #undef RANGECHK @@ -126,10 +124,12 @@ in_pcballoc(so, pcbinfo) if (inp == NULL) return (ENOBUFS); bzero((caddr_t)inp, sizeof(*inp)); + inp->inp_gencnt = ++pcbinfo->ipi_gencnt; inp->inp_pcbinfo = pcbinfo; inp->inp_socket = so; s = splnet(); LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); + pcbinfo->ipi_count++; in_pcbinshash(inp); splx(s); so->so_pcb = (caddr_t)inp; @@ -445,8 +445,10 @@ in_pcbdetach(inp) struct inpcb *inp; { struct socket *so = inp->inp_socket; + struct inpcbinfo *ipi = inp->inp_pcbinfo; int s; + inp->inp_gencnt = ++ipi->ipi_gencnt; so->so_pcb = 0; sofree(so); if (inp->inp_options) @@ -753,5 +755,6 @@ in_pcbrehash(inp) inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; LIST_INSERT_HEAD(head, inp, inp_hash); + inp->inp_pcbinfo->ipi_count--; splx(s); } diff --git a/cpukit/libnetworking/netinet/in_pcb.h b/cpukit/libnetworking/netinet/in_pcb.h index 9390cfda6c..df1eeead89 100644 --- a/cpukit/libnetworking/netinet/in_pcb.h +++ b/cpukit/libnetworking/netinet/in_pcb.h @@ -48,6 +48,8 @@ */ LIST_HEAD(inpcbhead, inpcb); +typedef u_int64_t inp_gen_t; + struct inpcb { LIST_ENTRY(inpcb) inp_list; /* list for all PCBs of this proto */ LIST_ENTRY(inpcb) inp_hash; /* hash list */ @@ -66,11 +68,40 @@ struct inpcb { u_char inp_ip_p; /* protocol proto */ u_char pad[1]; /* alignment */ struct ip_moptions *inp_moptions; /* IP multicast options */ + inp_gen_t inp_gencnt; /* generation count of this instance */ #if 0 /* Someday, perhaps... */ struct ip inp_ip; /* header prototype; should have more */ #endif }; +/* + * Interface exported to userland by various protocols which use + * inpcbs. Hack alert -- only define if struct xsocket is in scope. + * + * ccj - 20 Nov 2002 + * Double hack alert. This is taken from the pre 5.0 sources and + * merged into RTEMS. This allows the TCPCTL_PCBLIST code in + * net-snmp to work. + */ +#ifdef _SYS_SOCKETVAR_H_ +typedef u_int64_t so_gen_t; /* should be in sys/sockvar.h */ + +struct xinpcb { + size_t xi_len; /* length of this structure */ + struct inpcb xi_inp; +/* struct xsocket xi_socket; ccj removed */ + u_int64_t xi_alignment_hack; +}; + + +struct xinpgen { + size_t xig_len; /* length of this structure */ + u_int xig_count; /* number of PCBs at this time */ + inp_gen_t xig_gen; /* generation count at this time */ + so_gen_t xig_sogen; /* socket generation count at this time */ +}; +#endif /* _SYS_SOCKETVAR_H_ */ + struct inpcbinfo { struct inpcbhead *listhead; struct inpcbhead *hashbase; @@ -78,6 +109,8 @@ struct inpcbinfo { unsigned short lastport; unsigned short lastlow; unsigned short lasthi; + u_int ipi_count; /* number of pcbs in this list */ + u_int64_t ipi_gencnt; /* current generation count */ }; #define INP_PCBHASH(faddr, lport, fport, mask) \ diff --git a/cpukit/libnetworking/netinet/in_var.h b/cpukit/libnetworking/netinet/in_var.h index e7a54d5e85..b64448d2fb 100644 --- a/cpukit/libnetworking/netinet/in_var.h +++ b/cpukit/libnetworking/netinet/in_var.h @@ -161,6 +161,12 @@ struct in_multi { }; #ifdef KERNEL + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet_ip); +SYSCTL_DECL(_net_inet_raw); +#endif + /* * Structure used by macros below to remember position when stepping through * all of the in_multi records. diff --git a/cpukit/libnetworking/netinet/ip_fw.c b/cpukit/libnetworking/netinet/ip_fw.c index aeb09b0bbe..4bad293e7d 100644 --- a/cpukit/libnetworking/netinet/ip_fw.c +++ b/cpukit/libnetworking/netinet/ip_fw.c @@ -60,12 +60,17 @@ static int fw_verbose_limit = 0; LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; +/* + * ccj - No current need for firewall so have provided the MIB. + */ +#if 0 #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); #endif +#endif #define dprintf(a) if (!fw_debug); else printf a diff --git a/cpukit/libnetworking/netinet/tcp_subr.c b/cpukit/libnetworking/netinet/tcp_subr.c index 9e7e57611d..7f97e20eed 100644 --- a/cpukit/libnetworking/netinet/tcp_subr.c +++ b/cpukit/libnetworking/netinet/tcp_subr.c @@ -457,6 +457,130 @@ tcp_notify(inp, error) sowwakeup(so); } +#ifdef __rtems__ +#define INP_INFO_RLOCK +#define INP_INFO_RUNLOCK +#define INP_LOCK +#define INP_UNLOCK +#endif + +static int +tcp_pcblist(SYSCTL_HANDLER_ARGS) +{ + int error, i, n, s; + struct inpcb *inp, **inp_list; + inp_gen_t gencnt; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == 0) { + n = tcbinfo.ipi_count; + req->oldidx = 2 * (sizeof xig) + + (n + n/8) * sizeof(struct xtcpcb); + return 0; + } + + if (req->newptr != 0) + return EPERM; + + /* + * OK, now we're committed to doing something. + */ + s = splnet(); + INP_INFO_RLOCK(&tcbinfo); + gencnt = tcbinfo.ipi_gencnt; + n = tcbinfo.ipi_count; + INP_INFO_RUNLOCK(&tcbinfo); + splx(s); + + sysctl_wire_old_buffer(req, 2 * (sizeof xig) + + n * sizeof(struct xtcpcb)); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = gencnt; +/* xig.xig_sogen = so_gencnt; remove by ccj */ + error = SYSCTL_OUT(req, &xig, sizeof xig); + if (error) + return error; + + /* ccj add exit if the count is 0 */ + if (!n) + return error; + + inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); + if (inp_list == 0) + return ENOMEM; + + s = splnet(); + INP_INFO_RLOCK(&tcbinfo); + for (inp = LIST_FIRST(tcbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) +#if 0 + && + cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) +#endif + inp_list[i++] = inp; + INP_UNLOCK(inp); + } + INP_INFO_RUNLOCK(&tcbinfo); + splx(s); + n = i; + + error = 0; + for (i = 0; i < n; i++) { + inp = inp_list[i]; + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) { + struct xtcpcb xt; + caddr_t inp_ppcb; + xt.xt_len = sizeof xt; + /* XXX should avoid extra copy */ + bcopy(inp, &xt.xt_inp, sizeof *inp); + inp_ppcb = inp->inp_ppcb; + if (inp_ppcb != NULL) + bcopy(inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp); + else + bzero((char *) &xt.xt_tp, sizeof xt.xt_tp); +#if 0 + if (inp->inp_socket) + sotoxsocket(inp->inp_socket, &xt.xt_socket); +#endif + error = SYSCTL_OUT(req, &xt, sizeof xt); + } + INP_UNLOCK(inp); + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + s = splnet(); + INP_INFO_RLOCK(&tcbinfo); + xig.xig_gen = tcbinfo.ipi_gencnt; +#if 0 + xig.xig_sogen = so_gencnt; +#endif + xig.xig_count = tcbinfo.ipi_count; + INP_INFO_RUNLOCK(&tcbinfo); + splx(s); + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + free(inp_list, M_TEMP); + return error; +} + +SYSCTL_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, + tcp_pcblist, "S,xtcpcb", "List of active TCP connections"); + void tcp_ctlinput(cmd, sa, vip) int cmd; diff --git a/cpukit/libnetworking/netinet/tcp_var.h b/cpukit/libnetworking/netinet/tcp_var.h index 113ec9a6ff..fdd3a17ccd 100644 --- a/cpukit/libnetworking/netinet/tcp_var.h +++ b/cpukit/libnetworking/netinet/tcp_var.h @@ -307,6 +307,23 @@ struct tcpstat { }; /* + * TCB structure exported to user-land via sysctl(3). + * Evil hack: declare only if in_pcb.h and sys/socketvar.h have been + * included. Not all of our clients do. + */ +#if defined(_NETINET_IN_PCB_H_) && defined(_SYS_SOCKETVAR_H_) +struct xtcpcb { + size_t xt_len; + struct inpcb xt_inp; + struct tcpcb xt_tp; +#if 0 + struct xsocket xt_socket; + u_quad_t xt_alignment_hack; +#endif +}; +#endif + +/* * Names for TCP sysctl objects */ #define TCPCTL_DO_RFC1323 1 /* use RFC-1323 extensions */ @@ -319,7 +336,8 @@ struct tcpstat { #define TCPCTL_SENDSPACE 8 /* send buffer space */ #define TCPCTL_RECVSPACE 9 /* receive buffer space */ #define TCPCTL_KEEPINIT 10 /* receive buffer space */ -#define TCPCTL_MAXID 11 +#define TCPCTL_PCBLIST 11 /* list of all outstanding PCBs */ +#define TCPCTL_MAXID 12 #define TCPCTL_NAMES { \ { 0, 0 }, \ @@ -336,6 +354,10 @@ struct tcpstat { } #ifdef KERNEL +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet_tcp); +#endif + extern struct inpcbhead tcb; /* head of queue of active tcpcb's */ extern struct inpcbinfo tcbinfo; extern struct tcpstat tcpstat; /* tcp statistics */ diff --git a/cpukit/libnetworking/netinet/udp_usrreq.c b/cpukit/libnetworking/netinet/udp_usrreq.c index 16c5fce2df..8e28bddc25 100644 --- a/cpukit/libnetworking/netinet/udp_usrreq.c +++ b/cpukit/libnetworking/netinet/udp_usrreq.c @@ -455,6 +455,124 @@ release: return (error); } +#ifdef __rtems__ +#define INP_INFO_RLOCK +#define INP_INFO_RUNLOCK +#define INP_LOCK +#define INP_UNLOCK +#endif + +static int +udp_pcblist(SYSCTL_HANDLER_ARGS) +{ + int error, i, n, s; + struct inpcb *inp, **inp_list; + inp_gen_t gencnt; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == 0) { + n = udbinfo.ipi_count; + req->oldidx = 2 * (sizeof xig) + + (n + n/8) * sizeof(struct xinpcb); + return 0; + } + + if (req->newptr != 0) + return EPERM; + + /* + * OK, now we're committed to doing something. + */ + s = splnet(); + gencnt = udbinfo.ipi_gencnt; + n = udbinfo.ipi_count; + splx(s); + + sysctl_wire_old_buffer(req, 2 * (sizeof xig) + + n * sizeof(struct xinpcb)); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = gencnt; +#if 0 + xig.xig_sogen = so_gencnt; +#endif + error = SYSCTL_OUT(req, &xig, sizeof xig); + if (error) + return error; + + /* ccj add the exit if count is 0 */ + if (!n) + return error; + + inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); + if (inp_list == 0) + return ENOMEM; + + s = splnet(); + INP_INFO_RLOCK(&udbinfo); + for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) +#if 0 + && + cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) +#endif + inp_list[i++] = inp; + INP_UNLOCK(inp); + } + INP_INFO_RUNLOCK(&udbinfo); + splx(s); + n = i; + + error = 0; + for (i = 0; i < n; i++) { + inp = inp_list[i]; + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) { + struct xinpcb xi; + xi.xi_len = sizeof xi; + /* XXX should avoid extra copy */ + bcopy(inp, &xi.xi_inp, sizeof *inp); +#if 0 + if (inp->inp_socket) + sotoxsocket(inp->inp_socket, &xi.xi_socket); +#endif + error = SYSCTL_OUT(req, &xi, sizeof xi); + } + INP_UNLOCK(inp); + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + s = splnet(); + INP_INFO_RLOCK(&udbinfo); + xig.xig_gen = udbinfo.ipi_gencnt; +#if 0 + xig.xig_sogen = so_gencnt; +#endif + xig.xig_count = udbinfo.ipi_count; + INP_INFO_RUNLOCK(&udbinfo); + splx(s); + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + free(inp_list, M_TEMP); + return error; +} + +SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, + udp_pcblist, "S,xinpcb", "List of active UDP sockets"); + static u_long udp_sendspace = 9216; /* really max datagram size */ /* 40 1K datagrams */ SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, diff --git a/cpukit/libnetworking/netinet/udp_var.h b/cpukit/libnetworking/netinet/udp_var.h index 90785b53de..b010e56348 100644 --- a/cpukit/libnetworking/netinet/udp_var.h +++ b/cpukit/libnetworking/netinet/udp_var.h @@ -78,7 +78,8 @@ struct udpstat { #define UDPCTL_STATS 2 /* statistics (read-only) */ #define UDPCTL_MAXDGRAM 3 /* max datagram size */ #define UDPCTL_RECVSPACE 4 /* default receive buffer space */ -#define UDPCTL_MAXID 5 +#define UDPCTL_PCBLIST 5 /* list of PCBs for UDP sockets */ +#define UDPCTL_MAXID 6 #define UDPCTL_NAMES { \ { 0, 0 }, \ @@ -89,6 +90,8 @@ struct udpstat { } #ifdef KERNEL +SYSCTL_DECL(_net_inet_udp); + extern struct inpcbhead udb; extern struct inpcbinfo udbinfo; extern struct udpstat udpstat; diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 31e87e1587..cf3b0925c8 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -37,6 +37,11 @@ #include <net/route.h> /* + * Sysctl init all. + */ +void sysctl_register_all(void *arg); + +/* * Memory allocation */ static int nmbuf = (64 * 1024) / MSIZE; @@ -196,6 +201,11 @@ bsd_init (void) domaininit (NULL); } + /* + * Setup the sysctl, normally done by a SYSINIT call. + */ + sysctl_register_all(0); + /* * Set up interfaces */ diff --git a/cpukit/libnetworking/rtems/rtems_syscall.c b/cpukit/libnetworking/rtems/rtems_syscall.c index 7e6210c091..429e47b511 100644 --- a/cpukit/libnetworking/rtems/rtems_syscall.c +++ b/cpukit/libnetworking/rtems/rtems_syscall.c @@ -6,6 +6,7 @@ #include <stdarg.h> /* #include <stdlib.h> */ #include <stdio.h> +#include <errno.h> #include <rtems.h> #include <rtems/libio.h> @@ -633,6 +634,28 @@ getsockname (int s, struct sockaddr *name, int *namelen) return getpeersockname (s, name, namelen, 0); } +int +sysctl(int *name, u_int namelen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int error; + size_t j; + + rtems_bsdnet_semaphore_obtain (); + error = userland_sysctl (0, name, namelen, oldp, oldlenp, 1, newp, newlen, &j); + rtems_bsdnet_semaphore_release (); + + if (oldlenp) + *oldlenp = j; + + if (error) + { + errno = error; + return -1; + } + return 0; +} + /* ************************************************************************ * RTEMS I/O HANDLER ROUTINES * diff --git a/cpukit/libnetworking/sys/kernel.h b/cpukit/libnetworking/sys/kernel.h index 35bce70bd6..25e483809a 100644 --- a/cpukit/libnetworking/sys/kernel.h +++ b/cpukit/libnetworking/sys/kernel.h @@ -72,6 +72,7 @@ extern int lbolt; /* once a second sleep address */ extern int tickdelta; extern long timedelta; +#if FREEBSD_RELENG_2_2_2_BASE /* * The following macros are used to declare global sets of objects, which * are collected by the linker into a `struct linker_set' as defined below. @@ -86,6 +87,18 @@ extern long timedelta; #define BSS_SET(set, sym) MAKE_SET(set, sym, 27) #define ABS_SET(set, sym) MAKE_SET(set, sym, 21) +#else + +/* + * RTEMS specific port using the updated sys/linker_set.h + * from the lastest FreeBSD (2002-Nov-15). This is a better + * way. + * + * Chris Johns (ccj@acm.org> 18 Nov 2002. + */ +#include <sys/linker_set.h> + +#endif /* * Enumerated types for known system startup interfaces. diff --git a/cpukit/libnetworking/sys/linker_set.h b/cpukit/libnetworking/sys/linker_set.h new file mode 100644 index 0000000000..2de93e91e0 --- /dev/null +++ b/cpukit/libnetworking/sys/linker_set.h @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1999 John D. Polstra + * Copyright (c) 1999,2001 Peter Wemm <peter@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/linker_set.h,v 1.13 2002/09/23 06:11:29 peter Exp $ + */ + +#ifndef _SYS_LINKER_SET_H_ +#define _SYS_LINKER_SET_H_ + +/* + * The following macros are used to declare global sets of objects, which + * are collected by the linker into a `linker_set' as defined below. + * For ELF, this is done by constructing a separate segment for each set. + */ + +/* + * Private macros, not to be used outside this header file. + */ +#ifdef __GNUC__ +#define __MAKE_SET(set, sym) \ + static void const * const __set_##set##_sym_##sym \ + __attribute((section("set_" #set))) __unused = &sym +#else /* !__GNUC__ */ +#ifndef lint +#error "This file needs to be compiled by GCC or lint" +#endif /* lint */ +#define __MAKE_SET(set, sym) extern void const * const (__set_##set##_sym_##sym) +#endif /* __GNUC__ */ + +/* + * Public macros. + */ +#define TEXT_SET(set, sym) __MAKE_SET(set, sym) +#define DATA_SET(set, sym) __MAKE_SET(set, sym) +#define BSS_SET(set, sym) __MAKE_SET(set, sym) +#define ABS_SET(set, sym) __MAKE_SET(set, sym) +#define SET_ENTRY(set, sym) __MAKE_SET(set, sym) + +/* + * Initialize before referring to a give linker set + */ +#define SET_DECLARE(set, ptype) \ + extern ptype *__CONCAT(__start_set_,set); \ + extern ptype *__CONCAT(__stop_set_,set) + +#define SET_BEGIN(set) \ + (&__CONCAT(__start_set_,set)) +#define SET_LIMIT(set) \ + (&__CONCAT(__stop_set_,set)) + +/* + * Iterate over all the elements of a set. + * + * Sets always contain addresses of things, and "pvar" points to words + * containing those addresses. Thus is must be declared as "type **pvar", + * and the address of each set item is obtained inside the loop by "*pvar". + */ +#define SET_FOREACH(pvar, set) \ + for (pvar = SET_BEGIN(set); pvar < SET_LIMIT(set); pvar++) + +#define SET_ITEM(set, i) \ + ((SET_BEGIN(set))[i]) + +/* + * Provide a count of the items in a set. + */ +#define SET_COUNT(set) \ + (SET_LIMIT(set) - SET_BEGIN(set)) + +#endif /* _SYS_LINKER_SET_H_ */ diff --git a/cpukit/libnetworking/sys/queue.h b/cpukit/libnetworking/sys/queue.h index 6ebc7dce3d..75ad0aa90e 100644 --- a/cpukit/libnetworking/sys/queue.h +++ b/cpukit/libnetworking/sys/queue.h @@ -31,15 +31,17 @@ * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $Id$ + * $FreeBSD: src/sys/sys/queue.h,v 1.54 2002/08/05 05:18:43 alfred Exp $ */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#include <sys/cdefs.h> + /* - * This file defines five types of data structures: singly-linked lists, - * slingly-linked tail queues, lists, tail queues, and circular queues. + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at @@ -74,28 +76,78 @@ * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may only be traversed in the forward direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. + * the list. A tail queue may be traversed in either direction. * * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_REVERSE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ /* - * Singly-linked List definitions. + * Singly-linked List declarations. */ -#define SLIST_HEAD(name, type) \ +#define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } -#define SLIST_ENTRY(type) \ +#define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } @@ -103,47 +155,66 @@ struct { \ /* * Singly-linked List functions. */ -#define SLIST_INIT(head) { \ - (head)->slh_first = NULL; \ -} +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) -#define SLIST_INSERT_AFTER(slistelm, elm, field) { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} +#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_INSERT_HEAD(head, elm, field) { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) -#define SLIST_REMOVE_HEAD(head, field) { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) -#define SLIST_REMOVE(head, elm, type, field) { \ - if ((head)->slh_first == (elm)) { \ +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ - struct type *curelm = (head)->slh_first; \ - while( curelm->field.sle_next != (elm) ) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ } \ -} +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) /* - * Singly-linked Tail queue definitions. + * Singly-linked Tail queue declarations. */ -#define STAILQ_HEAD(name, type) \ +#define STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first;/* first element */ \ struct type **stqh_last;/* addr of last next element */ \ } -#define STAILQ_ENTRY(type) \ +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } @@ -151,58 +222,91 @@ struct { \ /* * Singly-linked Tail queue functions. */ -#define STAILQ_INIT(head) { \ - (head)->stqh_first = NULL; \ - (head)->stqh_last = &(head)->stqh_first; \ -} +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) -#define STAILQ_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (head)->stqh_first = (elm); \ -} +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) -#define STAILQ_INSERT_TAIL(head, elm, field) { \ - (elm)->field.stqe_next = NULL; \ +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ *(head)->stqh_last = (elm); \ - (head)->stqh_last = &(elm)->field.stqe_next; \ -} + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) { \ - if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (tqelm)->field.stqe_next = (elm); \ -} +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) -#define STAILQ_REMOVE_HEAD(head, field) { \ - if (((head)->stqh_first = \ - (head)->stqh_first->field.stqe_next) == NULL) \ - (head)->stqh_last = &(head)->stqh_first; \ -} +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) -#define STAILQ_REMOVE(head, elm, type, field) { \ - if ((head)->stqh_first == (elm)) { \ - STAILQ_REMOVE_HEAD(head, field); \ +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ } \ else { \ - struct type *curelm = (head)->stqh_first; \ - while( curelm->field.stqe_next != (elm) ) \ - curelm = curelm->field.stqe_next; \ - if((curelm->field.stqe_next = \ - curelm->field.stqe_next->field.stqe_next) == NULL) \ - (head)->stqh_last = &(curelm)->field.stqe_next; \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ } \ -} +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) /* - * List definitions. + * List declarations. */ -#define LIST_HEAD(name, type) \ +#define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } -#define LIST_ENTRY(type) \ +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ @@ -211,117 +315,171 @@ struct { \ /* * List functions. */ -#define LIST_INIT(head) { \ - (head)->lh_first = NULL; \ -} -#define LIST_INSERT_AFTER(listelm, elm, field) { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) -#define LIST_INSERT_BEFORE(listelm, elm, field) { \ +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ + LIST_NEXT((elm), field) = (listelm); \ *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) -#define LIST_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) -#define LIST_REMOVE(elm, field) { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ -} + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) /* - * Tail queue definitions. + * Tail queue declarations. */ -#define TAILQ_HEAD(name, type) \ +#define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ } -#define TAILQ_HEAD_INITIALIZER(head) \ +#define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } -#define TAILQ_ENTRY(type) \ +#define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ } /* * Tail queue functions. */ -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) -#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) -#define TAILQ_LAST(head) ((head)->tqh_last) +#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) -#define TAILQ_PREV(elm, field) ((elm)->field.tqe_prev) +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) -#define TAILQ_INIT(head) { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) -#define TAILQ_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) -#define TAILQ_INSERT_TAIL(head, elm, field) { \ - (elm)->field.tqe_next = NULL; \ +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) -#define TAILQ_INSERT_BEFORE(listelm, elm, field) { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_REMOVE(head, elm, field) { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ (elm)->field.tqe_prev; \ - else \ + else { \ (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ -} + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + /* * Circular queue definitions. @@ -413,39 +571,11 @@ struct quehead { #ifdef __GNUC__ -#if (defined(__GNUC__) && defined(__arm__)) -static __inline void -insque(void *a, void *b) -{ - struct quehead *element; - struct quehead *head; - element = (struct quehead *) (((unsigned int) a + 0x3) & ~0x3); - head = (struct quehead *) (((unsigned int) b + 0x3) & ~0x3); - - element->qh_link = head->qh_link; - element->qh_rlink = head; - head->qh_link = element; - element->qh_link->qh_rlink = element; -} - -static __inline void -remque(void *a) -{ - struct quehead *element; - - element = (struct quehead *) (((unsigned int) a + 0x3) & ~0x3); - - element->qh_link->qh_rlink = element->qh_rlink; - element->qh_rlink->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -#else /*if (defined(__GNUC__) && defined(__arm__))*/ - static __inline void insque(void *a, void *b) { - struct quehead *element = a, *head = b; + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; element->qh_link = head->qh_link; element->qh_rlink = head; @@ -456,21 +586,20 @@ insque(void *a, void *b) static __inline void remque(void *a) { - struct quehead *element = a; + struct quehead *element = (struct quehead *)a; element->qh_link->qh_rlink = element->qh_rlink; element->qh_rlink->qh_link = element->qh_link; element->qh_rlink = 0; } -#endif /*if-else (defined(__GNUC__) && defined(__arm__))*/ #else /* !__GNUC__ */ -void insque __P((void *a, void *b)); -void remque __P((void *a)); +void insque(void *a, void *b); +void remque(void *a); #endif /* __GNUC__ */ -#endif /* KERNEL */ +#endif /* _KERNEL */ #endif /* !_SYS_QUEUE_H_ */ diff --git a/cpukit/libnetworking/sys/sysctl.h b/cpukit/libnetworking/sys/sysctl.h index b25ba43c4f..063f88a880 100644 --- a/cpukit/libnetworking/sys/sysctl.h +++ b/cpukit/libnetworking/sys/sysctl.h @@ -34,12 +34,15 @@ * SUCH DAMAGE. * * @(#)sysctl.h 8.1 (Berkeley) 6/2/93 - * $Id$ + * $FreeBSD: src/sys/sys/sysctl.h,v 1.110 2002/10/20 22:48:08 phk Exp $ */ #ifndef _SYS_SYSCTL_H_ #define _SYS_SYSCTL_H_ +#include <sys/queue.h> + +struct thread; /* * Definitions for sysctl call. The sysctl call uses a hierarchical name * for objects that can be examined or modified. The name is expressed as @@ -70,84 +73,205 @@ struct ctlname { #define CTLTYPE_QUAD 4 /* name describes a 64-bit number */ #define CTLTYPE_OPAQUE 5 /* name describes a structure */ #define CTLTYPE_STRUCT CTLTYPE_OPAQUE /* name describes a structure */ +#define CTLTYPE_UINT 6 /* name describes an unsigned integer */ +#define CTLTYPE_LONG 7 /* name describes a long */ +#define CTLTYPE_ULONG 8 /* name describes an unsigned long */ #define CTLFLAG_RD 0x80000000 /* Allow reads of variable */ #define CTLFLAG_WR 0x40000000 /* Allow writes to the variable */ #define CTLFLAG_RW (CTLFLAG_RD|CTLFLAG_WR) #define CTLFLAG_NOLOCK 0x20000000 /* XXX Don't Lock */ #define CTLFLAG_ANYBODY 0x10000000 /* All users can set this var */ +#define CTLFLAG_SECURE 0x08000000 /* Permit set only if securelevel<=0 */ +#define CTLFLAG_PRISON 0x04000000 /* Prisoned roots can fiddle */ +#define CTLFLAG_DYN 0x02000000 /* Dynamic oid - can be freed */ +#define CTLFLAG_SKIP 0x01000000 /* Skip this sysctl when listing */ /* * USE THIS instead of a hardwired number from the categories below * to get dynamically assigned sysctl entries using the linker-set * technology. This is the way nearly all new sysctl variables should - * be implimented. + * be implemented. * e.g. SYSCTL_INT(_parent, OID_AUTO, name, CTLFLAG_RW, &variable, 0, ""); */ #define OID_AUTO (-1) +/* + * The starting number for dynamically-assigned entries. WARNING! + * ALL static sysctl entries should have numbers LESS than this! + */ +#define CTL_AUTO_START 0x100 + #ifdef KERNEL -#define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, void *arg1, int arg2, \ - struct sysctl_req *req) +#define SYSCTL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, int arg2, \ + struct sysctl_req *req /* * This describes the access space for a sysctl request. This is needed * so that we can use the interface from the kernel or from user-space. */ struct sysctl_req { - struct proc *p; + struct thread *td; /* used for access checking */ int lock; void *oldptr; - int oldlen; - int oldidx; - int (*oldfunc)(struct sysctl_req *, const void *, int); + size_t oldlen; + size_t oldidx; + int (*oldfunc)(struct sysctl_req *, const void *, size_t); void *newptr; - int newlen; - int newidx; - int (*newfunc)(struct sysctl_req *, void *, int); + size_t newlen; + size_t newidx; + int (*newfunc)(struct sysctl_req *, void *, size_t); }; +SLIST_HEAD(sysctl_oid_list, sysctl_oid); + /* * This describes one "oid" in the MIB tree. Potentially more nodes can * be hidden behind it, expanded by the handler. */ struct sysctl_oid { + struct sysctl_oid_list *oid_parent; + SLIST_ENTRY(sysctl_oid) oid_link; int oid_number; - int oid_kind; + u_int oid_kind; void *oid_arg1; int oid_arg2; const char *oid_name; - int (*oid_handler) SYSCTL_HANDLER_ARGS; + int (*oid_handler)(SYSCTL_HANDLER_ARGS); const char *oid_fmt; + int oid_refcnt; + const char *descr; }; -#define SYSCTL_IN(r, p, l) -#define SYSCTL_OUT(r, p, l) +#define SYSCTL_IN(r, p, l) (r->newfunc)(r, p, l) +#define SYSCTL_OUT(r, p, l) (r->oldfunc)(r, p, l) -int sysctl_handle_int SYSCTL_HANDLER_ARGS; -int sysctl_handle_string SYSCTL_HANDLER_ARGS; -int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; +int sysctl_handle_int(SYSCTL_HANDLER_ARGS); +int sysctl_handle_long(SYSCTL_HANDLER_ARGS); +int sysctl_handle_intptr(SYSCTL_HANDLER_ARGS); +int sysctl_handle_string(SYSCTL_HANDLER_ARGS); +int sysctl_handle_opaque(SYSCTL_HANDLER_ARGS); -/* This is the "raw" function for a mib-oid */ -#define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) +/* + * These functions are used to add/remove an oid from the mib. + */ +void sysctl_register_oid(struct sysctl_oid *oidp); +void sysctl_unregister_oid(struct sysctl_oid *oidp); -/* This makes a node from which other oids can hang */ -#define SYSCTL_NODE(parent, nbr, name, access, handler, descr) +/* Declare a static oid to allow child oids to be added to it. */ +#define SYSCTL_DECL(name) \ + extern struct sysctl_oid_list sysctl_##name##_children -/* This is a string len can be 0 to indicate '\0' termination */ -#define SYSCTL_STRING(parent, nbr, name, access, arg, len, descr) +/* Hide these in macros */ +#define SYSCTL_CHILDREN(oid_ptr) (struct sysctl_oid_list *) \ + (oid_ptr)->oid_arg1 +#define SYSCTL_STATIC_CHILDREN(oid_name) \ + (&sysctl_##oid_name##_children) -/* This is a integer, if ptr is NULL, val is returned */ -#define SYSCTL_INT(parent, nbr, name, access, ptr, val, descr) +/* === Structs and macros related to context handling === */ -/* This is anything, specified by a pointer and a lenth */ -#define SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr) +/* All dynamically created sysctls can be tracked in a context list. */ +struct sysctl_ctx_entry { + struct sysctl_oid *entry; + TAILQ_ENTRY(sysctl_ctx_entry) link; +}; -/* This is a struct, specified by a pointer and type */ -#define SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr) +TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); + +/* This constructs a "raw" MIB oid. */ +#define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) \ + static struct sysctl_oid sysctl__##parent##_##name = { \ + &sysctl_##parent##_children, { 0 }, \ + nbr, kind, a1, a2, #name, handler, fmt, 0, descr }; \ + DATA_SET(sysctl_set, sysctl__##parent##_##name) + +#define SYSCTL_ADD_OID(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr) + +/* This constructs a node from which other oids can hang. */ +#define SYSCTL_NODE(parent, nbr, name, access, handler, descr) \ + struct sysctl_oid_list sysctl_##parent##_##name##_children; \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_NODE|(access), \ + (void*)&sysctl_##parent##_##name##_children, 0, handler, \ + "N", descr) + +#define SYSCTL_ADD_NODE(ctx, parent, nbr, name, access, handler, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_NODE|(access), \ + 0, 0, handler, "N", descr) + +/* Oid for a string. len can be 0 to indicate '\0' termination. */ +#define SYSCTL_STRING(parent, nbr, name, access, arg, len, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_STRING|(access), \ + arg, len, sysctl_handle_string, "A", descr) + +#define SYSCTL_ADD_STRING(ctx, parent, nbr, name, access, arg, len, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_STRING|(access), \ + arg, len, sysctl_handle_string, "A", descr) + +/* Oid for an int. If ptr is NULL, val is returned. */ +#define SYSCTL_INT(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|(access), \ + ptr, val, sysctl_handle_int, "I", descr) + +#define SYSCTL_ADD_INT(ctx, parent, nbr, name, access, ptr, val, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_INT|(access), \ + ptr, val, sysctl_handle_int, "I", descr) + +/* Oid for an unsigned int. If ptr is NULL, val is returned. */ +#define SYSCTL_UINT(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_UINT|(access), \ + ptr, val, sysctl_handle_int, "IU", descr) + +#define SYSCTL_ADD_UINT(ctx, parent, nbr, name, access, ptr, val, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_UINT|(access), \ + ptr, val, sysctl_handle_int, "IU", descr) + +/* Oid for a long. The pointer must be non NULL. */ +#define SYSCTL_LONG(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_LONG|(access), \ + ptr, val, sysctl_handle_long, "L", descr) + +#define SYSCTL_ADD_LONG(ctx, parent, nbr, name, access, ptr, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_LONG|(access), \ + ptr, 0, sysctl_handle_long, "L", descr) + +/* Oid for a long. The pointer must be non NULL. */ +#define SYSCTL_ULONG(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_ULONG|(access), \ + ptr, val, sysctl_handle_long, "LU", descr) + +#define SYSCTL_ADD_ULONG(ctx, parent, nbr, name, access, ptr, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_ULONG|(access), \ + ptr, 0, sysctl_handle_long, "LU", descr) + +/* Oid for an opaque object. Specified by a pointer and a length. */ +#define SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, len, sysctl_handle_opaque, fmt, descr) + +#define SYSCTL_ADD_OPAQUE(ctx, parent, nbr, name, access, ptr, len, fmt, descr)\ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, len, sysctl_handle_opaque, fmt, descr) + +/* Oid for a struct. Specified by a pointer and a type. */ +#define SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, sizeof(struct type), sysctl_handle_opaque, \ + "S," #type, descr) + +#define SYSCTL_ADD_STRUCT(ctx, parent, nbr, name, access, ptr, type, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, sizeof(struct type), sysctl_handle_opaque, "S," #type, descr) + +/* Oid for a procedure. Specified by a pointer and an arg. */ +#define SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) \ + SYSCTL_OID(parent, nbr, name, (access), \ + ptr, arg, handler, fmt, descr) + +#define SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, (access), \ + ptr, arg, handler, fmt, descr) -/* Needs a proc. Specify by pointer and arg */ -#define SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) #endif /* KERNEL */ /* @@ -156,13 +280,14 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; #define CTL_UNSPEC 0 /* unused */ #define CTL_KERN 1 /* "high kernel": proc, limits */ #define CTL_VM 2 /* virtual memory */ -#define CTL_VFS 3 /* file system, mount type is next */ +#define CTL_VFS 3 /* filesystem, mount type is next */ #define CTL_NET 4 /* network, see socket.h */ #define CTL_DEBUG 5 /* debugging parameters */ #define CTL_HW 6 /* generic cpu/io */ #define CTL_MACHDEP 7 /* machine dependent */ #define CTL_USER 8 /* user-level */ -#define CTL_MAXID 9 /* number of valid top-level ids */ +#define CTL_P1003_1B 9 /* POSIX 1003.1B */ +#define CTL_MAXID 10 /* number of valid top-level ids */ #define CTL_NAMES { \ { 0, 0 }, \ @@ -174,6 +299,7 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; { "hw", CTLTYPE_NODE }, \ { "machdep", CTLTYPE_NODE }, \ { "user", CTLTYPE_NODE }, \ + { "p1003_1b", CTLTYPE_NODE }, \ } /* @@ -208,11 +334,13 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; #define KERN_MAXFILESPERPROC 27 /* int: max open files per proc */ #define KERN_MAXPROCPERUID 28 /* int: max processes per uid */ #define KERN_DUMPDEV 29 /* dev_t: device to dump on */ -#define KERN_SOMAXCONN 30 /* int: max connections in listen q */ -#define KERN_MAXSOCKBUF 31 /* int: max size of a socket buffer */ +#define KERN_IPC 30 /* node: anything related to IPC */ +#define KERN_DUMMY 31 /* unused */ #define KERN_PS_STRINGS 32 /* int: address of PS_STRINGS */ #define KERN_USRSTACK 33 /* int: address of USRSTACK */ -#define KERN_MAXID 34 /* number of valid kern ids */ +#define KERN_LOGSIGEXIT 34 /* int: do we log sigexit procs? */ +#define KERN_IOV_MAX 35 /* int: value of UIO_MAXIOV */ +#define KERN_MAXID 36 /* number of valid kern ids */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -226,7 +354,7 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; { "argmax", CTLTYPE_INT }, \ { "securelevel", CTLTYPE_INT }, \ { "hostname", CTLTYPE_STRING }, \ - { "hostid", CTLTYPE_INT }, \ + { "hostid", CTLTYPE_UINT }, \ { "clockrate", CTLTYPE_STRUCT }, \ { "vnode", CTLTYPE_STRUCT }, \ { "proc", CTLTYPE_STRUCT }, \ @@ -240,23 +368,21 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; { "nisdomainname", CTLTYPE_STRING }, \ { "update", CTLTYPE_INT }, \ { "osreldate", CTLTYPE_INT }, \ - { "ntp_pll", CTLTYPE_NODE }, \ + { "ntp_pll", CTLTYPE_NODE }, \ { "bootfile", CTLTYPE_STRING }, \ { "maxfilesperproc", CTLTYPE_INT }, \ { "maxprocperuid", CTLTYPE_INT }, \ - { "dumpdev", CTLTYPE_STRUCT }, /* we lie; don't print as int */ \ - { "somaxconn", CTLTYPE_INT }, \ - { "maxsockbuf", CTLTYPE_INT }, \ + { "ipc", CTLTYPE_NODE }, \ + { "dummy", CTLTYPE_INT }, \ { "ps_strings", CTLTYPE_INT }, \ { "usrstack", CTLTYPE_INT }, \ + { "logsigexit", CTLTYPE_INT }, \ + { "iov_max", CTLTYPE_INT }, \ } /* * CTL_VFS identifiers */ -#define VFS_VFSCONF 0 /* get configured filesystems */ -#define VFS_MAXID 1 /* number of items */ - #define CTL_VFS_NAMES { \ { "vfsconf", CTLTYPE_STRUCT }, \ } @@ -271,6 +397,18 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; #define KERN_PROC_TTY 4 /* by controlling tty */ #define KERN_PROC_UID 5 /* by effective uid */ #define KERN_PROC_RUID 6 /* by real uid */ +#define KERN_PROC_ARGS 7 /* get/set arguments/proctitle */ + +/* + * KERN_IPC identifiers + */ +#define KIPC_MAXSOCKBUF 1 /* int: max size of a socket buffer */ +#define KIPC_SOCKBUF_WASTE 2 /* int: wastage factor in sockbuf */ +#define KIPC_SOMAXCONN 3 /* int: max length of connection q */ +#define KIPC_MAX_LINKHDR 4 /* int: max length of link header */ +#define KIPC_MAX_PROTOHDR 5 /* int: max length of network header */ +#define KIPC_MAX_HDR 6 /* int: max total length of headers */ +#define KIPC_MAX_DATALEN 7 /* int: max length of data? */ /* * CTL_HW identifiers @@ -294,8 +432,8 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; { "model", CTLTYPE_STRING }, \ { "ncpu", CTLTYPE_INT }, \ { "byteorder", CTLTYPE_INT }, \ - { "physmem", CTLTYPE_INT }, \ - { "usermem", CTLTYPE_INT }, \ + { "physmem", CTLTYPE_ULONG }, \ + { "usermem", CTLTYPE_ULONG }, \ { "pagesize", CTLTYPE_INT }, \ { "disknames", CTLTYPE_STRUCT }, \ { "diskstats", CTLTYPE_STRUCT }, \ @@ -351,28 +489,121 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; { "tzname_max", CTLTYPE_INT }, \ } +#define CTL_P1003_1B_ASYNCHRONOUS_IO 1 /* boolean */ +#define CTL_P1003_1B_MAPPED_FILES 2 /* boolean */ +#define CTL_P1003_1B_MEMLOCK 3 /* boolean */ +#define CTL_P1003_1B_MEMLOCK_RANGE 4 /* boolean */ +#define CTL_P1003_1B_MEMORY_PROTECTION 5 /* boolean */ +#define CTL_P1003_1B_MESSAGE_PASSING 6 /* boolean */ +#define CTL_P1003_1B_PRIORITIZED_IO 7 /* boolean */ +#define CTL_P1003_1B_PRIORITY_SCHEDULING 8 /* boolean */ +#define CTL_P1003_1B_REALTIME_SIGNALS 9 /* boolean */ +#define CTL_P1003_1B_SEMAPHORES 10 /* boolean */ +#define CTL_P1003_1B_FSYNC 11 /* boolean */ +#define CTL_P1003_1B_SHARED_MEMORY_OBJECTS 12 /* boolean */ +#define CTL_P1003_1B_SYNCHRONIZED_IO 13 /* boolean */ +#define CTL_P1003_1B_TIMERS 14 /* boolean */ +#define CTL_P1003_1B_AIO_LISTIO_MAX 15 /* int */ +#define CTL_P1003_1B_AIO_MAX 16 /* int */ +#define CTL_P1003_1B_AIO_PRIO_DELTA_MAX 17 /* int */ +#define CTL_P1003_1B_DELAYTIMER_MAX 18 /* int */ +#define CTL_P1003_1B_MQ_OPEN_MAX 19 /* int */ +#define CTL_P1003_1B_PAGESIZE 20 /* int */ +#define CTL_P1003_1B_RTSIG_MAX 21 /* int */ +#define CTL_P1003_1B_SEM_NSEMS_MAX 22 /* int */ +#define CTL_P1003_1B_SEM_VALUE_MAX 23 /* int */ +#define CTL_P1003_1B_SIGQUEUE_MAX 24 /* int */ +#define CTL_P1003_1B_TIMER_MAX 25 /* int */ + +#define CTL_P1003_1B_MAXID 26 + +#define CTL_P1003_1B_NAMES { \ + { 0, 0 }, \ + { "asynchronous_io", CTLTYPE_INT }, \ + { "mapped_files", CTLTYPE_INT }, \ + { "memlock", CTLTYPE_INT }, \ + { "memlock_range", CTLTYPE_INT }, \ + { "memory_protection", CTLTYPE_INT }, \ + { "message_passing", CTLTYPE_INT }, \ + { "prioritized_io", CTLTYPE_INT }, \ + { "priority_scheduling", CTLTYPE_INT }, \ + { "realtime_signals", CTLTYPE_INT }, \ + { "semaphores", CTLTYPE_INT }, \ + { "fsync", CTLTYPE_INT }, \ + { "shared_memory_objects", CTLTYPE_INT }, \ + { "synchronized_io", CTLTYPE_INT }, \ + { "timers", CTLTYPE_INT }, \ + { "aio_listio_max", CTLTYPE_INT }, \ + { "aio_max", CTLTYPE_INT }, \ + { "aio_prio_delta_max", CTLTYPE_INT }, \ + { "delaytimer_max", CTLTYPE_INT }, \ + { "mq_open_max", CTLTYPE_INT }, \ + { "pagesize", CTLTYPE_INT }, \ + { "rtsig_max", CTLTYPE_INT }, \ + { "nsems_max", CTLTYPE_INT }, \ + { "sem_value_max", CTLTYPE_INT }, \ + { "sigqueue_max", CTLTYPE_INT }, \ + { "timer_max", CTLTYPE_INT }, \ +} + #ifdef KERNEL -extern char cpu_model[]; +/* + * Declare some common oids. + */ +extern struct sysctl_oid_list sysctl__children; +SYSCTL_DECL(_kern); +SYSCTL_DECL(_sysctl); +SYSCTL_DECL(_vm); +SYSCTL_DECL(_vfs); +SYSCTL_DECL(_net); +SYSCTL_DECL(_debug); +SYSCTL_DECL(_debug_sizeof); +SYSCTL_DECL(_hw); +SYSCTL_DECL(_machdep); +SYSCTL_DECL(_user); +SYSCTL_DECL(_compat); + extern char machine[]; extern char osrelease[]; extern char ostype[]; -int kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, int *retval); -int userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval); -/* -int sysctl_clockrate __P((char *, size_t*)); -int sysctl_file __P((char *, size_t*)); -int sysctl_doproc __P((int *, u_int, char *, size_t*)); -int sysctl_doprof __P((int *, u_int, void *, size_t *, void *, size_t)); -*/ +/* Dynamic oid handling */ +struct sysctl_oid *sysctl_add_oid(struct sysctl_ctx_list *clist, + struct sysctl_oid_list *parent, int nbr, const char *name, + int kind, void *arg1, int arg2, + int (*handler) (SYSCTL_HANDLER_ARGS), + const char *fmt, const char *descr); +int sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse); +int sysctl_ctx_init(struct sysctl_ctx_list *clist); +int sysctl_ctx_free(struct sysctl_ctx_list *clist); +struct sysctl_ctx_entry *sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, + struct sysctl_oid *oidp); +struct sysctl_ctx_entry *sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, + struct sysctl_oid *oidp); +int sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, + struct sysctl_oid *oidp); + +int kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, + size_t *oldlenp, void *new, size_t newlen, + size_t *retval); +int kernel_sysctlbyname(struct thread *td, char *name, + void *old, size_t *oldlenp, void *new, size_t newlen, + size_t *retval); +int userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, + size_t *oldlenp, int inkernel, void *new, size_t newlen, + size_t *retval); +int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, + int *nindx, struct sysctl_req *req); +void sysctl_wire_old_buffer(struct sysctl_req *req, size_t len); #else /* !KERNEL */ #include <sys/cdefs.h> __BEGIN_DECLS -int sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -int sysctlbyname __P((const char *, void *, size_t *, void *, size_t)); +int sysctl(int *, u_int, void *, size_t *, void *, size_t); +int sysctlbyname(const char *, void *, size_t *, void *, size_t); +int sysctlnametomib(const char *, int *, size_t *); __END_DECLS #endif /* KERNEL */ |