Remove NetBSD references – batch 1

This commit is contained in:
Eirikr Hinngart 2025-05-31 17:06:32 -07:00
parent fcf253e1cf
commit f6513902aa
50 changed files with 0 additions and 27019 deletions

View File

@ -1,4 +0,0 @@
# MINIX Specifics sources
.PATH: ${NETBSDSRCDIR}/minix/lib/libc
SRCS+= configfile.c mtab.c stderr.c

View File

@ -1,5 +0,0 @@
C_HERE=${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}
.PATH: ${C_HERE}
SRCS+= get_bp.S \
read_tsc.c

View File

@ -1,29 +0,0 @@
# rts sources
HERE=${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}/sys
.PATH: ${HERE}
TMP=ucontextoffsets.h.tmp
CF=${HERE}/ucontextoffsets.cf
INCS+=ucontextoffsets.h
ucontext.o: ucontextoffsets.h
SRCS+= \
__sigreturn.S \
_do_kernel_call_intr.S \
_ipc.S \
brksize.S \
ipc_minix_kerninfo.S \
ucontext.S
ucontextoffsets.h: ${CF}
ucontextoffsets.h: ${NETBSDSRCDIR}/sys/sys/ucontext.h
ucontextoffsets.h: ${NETBSDSRCDIR}/minix/include/arch/${MACHINE_ARCH}/include/stackframe.h
ucontextoffsets.h:
${_MKTARGET_CREATE}
${TOOL_CAT} ${CF} | \
${TOOL_GENASSYM} -- ${CC} ${CFLAGS:N-Wa,*} \
${CPPFLAGS} ${PROF} ${GENASSYM_CPPFLAGS} >$TMP && \
mv -f $TMP $@

View File

@ -1,9 +0,0 @@
C_HERE=${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}
.PATH: ${C_HERE}
SRCS+= _cpuid.S \
get_bp.S \
getprocessor.S \
read_tsc.S \
_cpufeature.c

View File

@ -1,29 +0,0 @@
# rts sources
HERE=${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}/sys
.PATH: ${HERE}
TMP=ucontextoffsets.h.tmp
CF=${HERE}/ucontextoffsets.cf
INCS+=ucontextoffsets.h
ucontext.o: ucontextoffsets.h
SRCS+= \
__sigreturn.S \
_do_kernel_call_intr.S \
_ipc.S \
brksize.S \
ipc_minix_kerninfo.S \
ucontext.S
ucontextoffsets.h: ${CF}
ucontextoffsets.h: ${NETBSDSRCDIR}/sys/sys/ucontext.h
ucontextoffsets.h: ${NETBSDSRCDIR}/minix/include/arch/${MACHINE_ARCH}/include/stackframe.h
ucontextoffsets.h:
${_MKTARGET_CREATE}
${TOOL_CAT} ${CF} | \
${TOOL_GENASSYM} -- ${CC} ${CFLAGS:N-Wa,*} \
${CPPFLAGS} ${PROF} ${GENASSYM_CPPFLAGS} >$TMP && \
mv -f $TMP $@

View File

@ -1,38 +0,0 @@
.PATH: ${NETBSDSRCDIR}/minix/lib/libc/sys
SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
chdir.c chmod.c fchmod.c chown.c fchown.c chroot.c close.c \
clock_getres.c clock_gettime.c clock_settime.c \
connect.c dup.c dup2.c execve.c fcntl.c flock.c fpathconf.c fork.c \
fstatfs.c fstatvfs.c fsync.c ftruncate.c gcov_flush_sys.c getdents.c \
getegid.c getgid.c \
getgroups.c getitimer.c setitimer.c __getlogin.c getpeername.c \
getpgrp.c getpid.c getppid.c priority.c getrlimit.c getsockname.c \
getsockopt.c setsockopt.c gettimeofday.c geteuid.c getuid.c \
getvfsstat.c \
ioctl.c issetugid.c kill.c link.c listen.c loadname.c lseek.c \
minix_rs.c mkdir.c mkfifo.c mknod.c mmap.c mount.c nanosleep.c \
open.c pathconf.c pipe.c poll.c posix_spawn.c pread.c ptrace.c pwrite.c \
read.c readlink.c reboot.c recvfrom.c recvmsg.c rename.c \
rmdir.c select.c sem.c sendmsg.c sendto.c setgroups.c setsid.c \
setgid.c settimeofday.c setuid.c shmat.c shmctl.c shmget.c stime.c \
vectorio.c shutdown.c sigaction.c sigpending.c sigreturn.c sigsuspend.c\
sigprocmask.c socket.c socketpair.c stat.c statvfs.c svrctl.c \
symlink.c \
sync.c syscall.c truncate.c umask.c unlink.c \
wait4.c write.c \
utimensat.c utimes.c futimes.c lutimes.c futimens.c \
_exit.c _ucontext.c environ.c __getcwd.c vfork.c sizeup.c init.c \
getrusage.c setrlimit.c setpgid.c __sysctl.c
# Minix specific syscalls / utils.
SRCS+= kernel_utils.c sprofile.c stack_utils.c _mcontext.c
# Emulation for missing lchown/lchmod/lchflags
OBJS+= lchflags.o lchmod.o lchown.o
lchflags.go lchflags.o lchflags.pico lchflags.bc: ${NETBSDSRCDIR}/tools/compat/lchflags.c
lchmod.go lchmod.o lchmod.pico lchmod.bc: ${NETBSDSRCDIR}/tools/compat/lchmod.c
lchown.go lchown.o lchown.pico lchown.bc: ${NETBSDSRCDIR}/tools/compat/lchown.c
.include "${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}/sys/Makefile.inc"
.include "${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}/Makefile.inc"

View File

@ -1,40 +0,0 @@
#include <sys/cdefs.h>
#include <lib.h>
#include "namespace.h"
#include "extern.h"
#include <string.h>
/*
* The sysctl(2) system call, handled by the MIB service.
*/
int
__sysctl(const int * name, unsigned int namelen, void * oldp, size_t * oldlenp,
const void * newp, size_t newlen)
{
message m;
int r;
memset(&m, 0, sizeof(m));
m.m_lc_mib_sysctl.oldp = (vir_bytes)oldp;
m.m_lc_mib_sysctl.oldlen = (oldlenp != NULL) ? *oldlenp : 0;
m.m_lc_mib_sysctl.newp = (vir_bytes)newp;
m.m_lc_mib_sysctl.newlen = newlen;
m.m_lc_mib_sysctl.namelen = namelen;
m.m_lc_mib_sysctl.namep = (vir_bytes)name;
if (namelen <= CTL_SHORTNAME)
memcpy(m.m_lc_mib_sysctl.name, name, sizeof(*name) * namelen);
r = _syscall(MIB_PROC_NR, MIB_SYSCTL, &m);
/*
* We copy the NetBSD behavior of replying with the old length also if
* the call failed, typically with ENOMEM. This is undocumented
* behavior, but unfortunately relied on by sysctl(8) and other NetBSD
* userland code. If the call failed at the IPC level, the resulting
* value will be garbage, but it should then not be used anyway.
*/
if (oldlenp != NULL)
*oldlenp = m.m_mib_lc_sysctl.oldlen;
return r;
}

View File

@ -1,172 +0,0 @@
/* Utilities to generate a proper C stack.
*
* Author: Lionel A. Sambuc.
*/
#define _MINIX_SYSTEM
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <sys/exec_elf.h>
#include <sys/exec.h>
/* Create a stack image that only needs to be patched up slightly by
* the kernel to be used for the process to be executed.
*
* Every pointers are stored here as offset from the frame base, and
* will be adapted as required for the new process address space.
*
* The following parameters are passed by register to either __start
* for static binaries, or _rtld_start for dynamic ones:
* *fct, *ObjEntry, *ps_string
*
* The following stack layout is expected by _rtld():
*
* | XXXXXXXXXX | 0x0000_00000
* | ... |
* | ... | Top of the stack
* | argc |
* | *argv1 | points to the first char of the argv1
* | ... |
* | *argvN |
* | NULL |
* | *env1 |
* | ... |
* | *envN |
* | NULL |
* | ElfAuxV1 |
* | ... |
* | ElfAuxVX |
* | AuxExecName| fully resolve executable name, as an ASCIIZ string,
* at most PMEF_EXECNAMELEN1 long.
*
* Here we put first the strings, then word-align, then ps_strings, to
* comply with the expected layout of NetBSD. This seems to matter for
* the NetBSD ps command, so let's make sure we are compatible...
*
* | strings | Maybe followed by some padding to word-align.
* | **argv | \
* | argc | +---> ps_string structure content.
* | **env | |
* | envc | /
* | sigcode | On NetBSD, there may be a compatibility stub here,
* +------------+ for native code, it is not present.
* Stack Base , 0xF000_0000, descending stack.
*/
/* The minimum size of the frame is composed of:
* argc, the NULL terminator for argv as well as one for
* environ, the ELF Aux vectors, executable name and the
* ps_strings struct. */
#define STACK_MIN_SZ \
( \
sizeof(int) + sizeof(void *) * 2 + \
sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
sizeof(struct ps_strings) \
)
/*****************************************************************************
* Computes stack size, argc, envc, for a given set of path, argv, envp. *
*****************************************************************************/
void minix_stack_params(const char *path, char * const *argv, char * const *envp,
size_t *stack_size, char *overflow, int *argc, int *envc)
{
char * const *p;
size_t const min_size = STACK_MIN_SZ;
*stack_size = min_size; /* Size of the new initial stack. */
*overflow = 0; /* No overflow yet. */
*argc = 0; /* Argument count. */
*envc = 0; /* Environment count */
/* Compute and add the size required to store argv and env. */
for (p = argv; *p != NULL; p++) {
size_t const n = sizeof(*p) + strlen(*p) + 1;
*stack_size += n;
if (*stack_size < n) {
*overflow = 1;
}
(*argc)++;
}
for (p = envp; p && *p != NULL; p++) {
size_t const n = sizeof(*p) + strlen(*p) + 1;
*stack_size += n;
if (*stack_size < n) {
*overflow = 1;
}
(*envc)++;
}
/* Compute the aligned frame size. */
*stack_size = (*stack_size + sizeof(void *) - 1) &
~(sizeof(void *) - 1);
if (*stack_size < min_size) {
/* This is possible only in case of overflow. */
*overflow = 1;
}
}
/*****************************************************************************
* Generate a stack in the buffer frame, ready to be used. *
*****************************************************************************/
void minix_stack_fill(const char *path, int argc, char * const *argv,
int envc, char * const *envp, size_t stack_size, char *frame,
int *vsp, struct ps_strings **psp)
{
char * const *p;
/* Frame pointers (a.k.a stack pointer within the buffer in current
* address space.) */
char *fp; /* byte aligned */
char **fpw; /* word aligned */
size_t const min_size = STACK_MIN_SZ;
/* Virtual address of the stack pointer, in new memory space. */
*vsp = minix_get_user_sp() - stack_size;
/* Fill in the frame now. */
fpw = (char **) frame;
*fpw++ = (char *) argc;
/* The strings themselves are stored after the aux vectors,
* cf. top comment. */
fp = frame + (min_size - sizeof(struct ps_strings)) +
(envc + argc) * sizeof(char *);
/* Fill in argv and the environment, as well as copy the strings
* themselves. */
for (p = argv; *p != NULL; p++) {
size_t const n = strlen(*p) + 1;
*fpw++= (char *)(*vsp + (fp - frame));
memcpy(fp, *p, n);
fp += n;
}
*fpw++ = NULL;
for (p = envp; p && *p != NULL; p++) {
size_t const n = strlen(*p) + 1;
*fpw++= (char *)(*vsp + (fp - frame));
memcpy(fp, *p, n);
fp += n;
}
*fpw++ = NULL;
/* Padding, because of the stack alignement. */
while ((size_t)fp % sizeof(void *)) *fp++= 0;
/* Fill in the ps_string struct*/
*psp = (struct ps_strings *) fp;
(*psp)->ps_argvstr = (char **)(*vsp + sizeof(argc));
(*psp)->ps_nargvstr = argc;
(*psp)->ps_envstr = (*psp)->ps_argvstr + argc + 1;
(*psp)->ps_nenvstr = envc;
}

View File

@ -1,13 +0,0 @@
LIB= ddekit
SRC_DIR = ${NETBSDSRCDIR}/minix/lib/libddekit/src
VPATH = ${SRC_DIR}
SRCS = pci.c printf.c mem.c pgtab.c dde.c initcall.c thread.c condvar.c \
lock.c semaphore.c timer.c panic.c irq.c resource.c msg_queue.c
CPPFLAGS += -D_NETBSD_SOURCE -D_MINIX_SYSTEM
.include <bsd.lib.mk>

View File

@ -1,12 +0,0 @@
LIB= ddekit_usb_client
SRC_DIR = ${NETBSDSRCDIR}/minix/lib/libddekit/src
VPATH = ${SRC_DIR}
SRCS = usb_client.c
CFLAGS += -Wall
.include <bsd.lib.mk>

View File

@ -1,11 +0,0 @@
LIB= ddekit_usb_server
SRC_DIR = ${NETBSDSRCDIR}/minix/lib/libddekit/src
VPATH = ${SRC_DIR}
SRCS = usb_server.c
CFLAGS += -Wall
.include <bsd.lib.mk>

View File

@ -1,179 +0,0 @@
/*****************************************************************************
* pppoe.h - PPP Over Ethernet implementation for lwIP.
*
* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE 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 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.
*
******************************************************************************
* REVISION HISTORY
*
* 06-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
*****************************************************************************/
/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Martin Husemann <martin@NetBSD.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */
#ifndef PPP_OE_H
#define PPP_OE_H
#include "ppp.h"
#include "lwip/etharp.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct pppoehdr {
PACK_STRUCT_FLD_8(u8_t vertype);
PACK_STRUCT_FLD_8(u8_t code);
PACK_STRUCT_FIELD(u16_t session);
PACK_STRUCT_FIELD(u16_t plen);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct pppoetag {
PACK_STRUCT_FIELD(u16_t tag);
PACK_STRUCT_FIELD(u16_t len);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define PPPOE_STATE_INITIAL 0
#define PPPOE_STATE_PADI_SENT 1
#define PPPOE_STATE_PADR_SENT 2
#define PPPOE_STATE_SESSION 3
/* passive */
#define PPPOE_STATE_PADO_SENT 1
#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
#define PPPOE_TAG_EOL 0x0000 /* end of list */
#define PPPOE_TAG_SNAME 0x0101 /* service name */
#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
#ifndef PPPOE_MAX_AC_COOKIE_LEN
#define PPPOE_MAX_AC_COOKIE_LEN 64
#endif
struct pppoe_softc {
struct pppoe_softc *next;
struct netif *sc_ethif; /* ethernet interface we are using */
ppp_pcb *pcb; /* PPP PCB */
struct eth_addr sc_dest; /* hardware address of concentrator */
u16_t sc_session; /* PPPoE session id */
u8_t sc_state; /* discovery phase or session connected */
#ifdef PPPOE_TODO
u8_t *sc_service_name; /* if != NULL: requested name of service */
u8_t *sc_concentrator_name; /* if != NULL: requested concentrator id */
#endif /* PPPOE_TODO */
u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */
u8_t sc_ac_cookie_len; /* length of cookie data */
#ifdef PPPOE_SERVER
u8_t *sc_hunique; /* content of host unique we must echo back */
u8_t sc_hunique_len; /* length of host unique */
#endif
u8_t sc_padi_retried; /* number of PADI retries already done */
u8_t sc_padr_retried; /* number of PADR retries already done */
};
#define pppoe_init() /* compatibility define, no initialization needed */
ppp_pcb *pppoe_create(struct netif *pppif,
struct netif *ethif,
const char *service_name, const char *concentrator_name,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb);
/*
* Functions called from lwIP
* DO NOT CALL FROM lwIP USER APPLICATION.
*/
void pppoe_disc_input(struct netif *netif, struct pbuf *p);
void pppoe_data_input(struct netif *netif, struct pbuf *p);
#endif /* PPP_OE_H */
#endif /* PPP_SUPPORT && PPPOE_SUPPORT */

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
.include <bsd.own.mk>
DISTDIR= ${NETBSDSRCDIR}/minix/lib/liblwip/dist
SRCDIR= ${DISTDIR}/src
LIB=lwip
.PATH: ${SRCDIR}/core ${SRCDIR}/core/ipv4 ${SRCDIR}/core/ipv6
.include "${.CURDIR}/core/Makefile.inc"
.PATH: ${SRCDIR}/netif
.include "${.CURDIR}/netif/Makefile.inc"
CPPFLAGS+= -D_MINIX_SYSTEM
CPPFLAGS+= -I${SRCDIR}/include -I${.CURDIR}
CPPFLAGS+= -Wno-empty-body
WARNS?= 5
.include <bsd.lib.mk>

View File

@ -1,101 +0,0 @@
From 7dd690e2c3f3350f5fd647ca52c3fdcc8ef17f4e Mon Sep 17 00:00:00 2001
From: David van Moolenbroek <david@minix3.org>
Date: Thu, 2 Feb 2017 18:21:57 +0000
Subject: [PATCH 2/4] MINIX 3 only: control IP forwarding at run time
The lwIP core supports IPv4 and IPv6 packet forwarding, but allows
this functionality to be enabled or disabled at compile time only.
For MINIX 3, this is not enough, as NetBSD userland (including the
network RC script) expects to be able to control this setting at run
time.
This patch adds run-time control over IPv4 and IPv6 forwarding with
the addition of two variables, lwip_ip4_forward and lwip_ip6_forward.
These variables are defined in the LWIP service and declared for lwIP
in arch/cc.h. The variables may be changed at any time. Any non-zero
value indicates that packets of the corresponding IP version should be
forwarded.
In addition, change lwIP such that if IPv6 forwarding is enabled,
meaning that the node acts as a (minimal, currently non RFC compliant)
router, the following adjustments are made (see RFC 4861):
- ICMPv6 Redirect messages are not accepted;
- ICMPv6 Neighbor Advertisement messages carry the Router flag.
---
src/core/ipv4/ip4.c | 7 +++++++
src/core/ipv6/ip6.c | 7 +++++++
src/core/ipv6/nd6.c | 14 ++++++++++++++
3 files changed, 28 insertions(+)
diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c
index d2b1751..d2fde03 100644
--- a/src/core/ipv4/ip4.c
+++ b/src/core/ipv4/ip4.c
@@ -272,6 +272,13 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
+#if defined(__minix)
+ /* MINIX 3 only: forward packets only when enabled through configuration. */
+ if (!lwip_ip4_forward) {
+ return;
+ }
+#endif /* defined(__minix) */
+
PERF_START;
LWIP_UNUSED_ARG(inp);
diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c
index 88d998b..24ecaaa 100644
--- a/src/core/ipv6/ip6.c
+++ b/src/core/ipv6/ip6.c
@@ -367,6 +367,13 @@ ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
+#if defined(__minix)
+ /* MINIX 3 only: forward packets only when enabled through configuration. */
+ if (!lwip_ip6_forward) {
+ return;
+ }
+#endif /* defined(__minix) */
+
/* do not forward link-local or loopback addresses */
if (ip6_addr_islinklocal(ip6_current_dest_addr()) ||
ip6_addr_isloopback(ip6_current_dest_addr())) {
diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c
index 0122d99..bd121f5 100644
--- a/src/core/ipv6/nd6.c
+++ b/src/core/ipv6/nd6.c
@@ -790,6 +790,14 @@ nd6_input(struct pbuf *p, struct netif *inp)
struct lladdr_option *lladdr_opt;
ip6_addr_t destination_address, target_address;
+#if defined(__minix)
+ /* MINIX 3 only: if forwarding is enabled, do not accept redirects. */
+ if (!lwip_ip6_forward) {
+ pbuf_free(p);
+ return;
+ }
+#endif /* defined(__minix) */
+
/* Check that Redir header fits in packet. */
if (p->len < sizeof(struct redirect_header)) {
/* @todo debug message */
@@ -1259,6 +1267,12 @@ nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags)
na_hdr->code = 0;
na_hdr->chksum = 0;
na_hdr->flags = flags & 0xf0;
+#if defined(__minix)
+ /* MINIX 3 only: if forwarding is enabled, set the router bit. */
+ if (lwip_ip6_forward) {
+ na_hdr->flags |= ND6_FLAG_ROUTER;
+ }
+#endif /* defined(__minix) */
na_hdr->reserved[0] = 0;
na_hdr->reserved[1] = 0;
na_hdr->reserved[2] = 0;
--
2.5.2

View File

@ -1,148 +0,0 @@
# Makefile for libsys
.include <bsd.own.mk>
CPPFLAGS+= -D_MINIX_SYSTEM -D_SYSTEM
LIB= sys
CFLAGS+= -fno-builtin
.include "arch/${MACHINE_ARCH}/Makefile.inc"
SRCS+= \
alloc_util.c \
assert.c \
asynsend.c \
clock_time.c \
closenb.c \
copyfd.c \
cpuavg.c \
ds.c \
env_get_prm.c \
env_panic.c \
env_parse.c \
fkey_ctl.c \
getepinfo.c \
getprocnr.c \
getticks.c \
getsysinfo.c \
getuptime.c \
kernel_call.c \
kprintf.c \
kputc.c \
kputs.c \
mapdriver.c \
optset.c \
panic.c \
proceventmask.c \
rmib.c \
safecopies.c \
sched_start.c \
sched_stop.c \
sef.c \
sef_fi.c \
sef_init.c \
sef_liveupdate.c \
sef_llvm.c \
sef_ping.c \
sef_signal.c \
sef_st.c \
socketpath.c \
sqrt_approx.c \
srv_fork.c \
srv_kill.c \
stacktrace.c \
sys_abort.c \
sys_clear.c \
sys_diagctl.c \
sys_endsig.c \
sys_exec.c \
sys_exit.c \
sys_fork.c \
sys_getinfo.c \
sys_getsig.c \
sys_hz.c \
sys_irqctl.c \
sys_kill.c \
sys_mcontext.c \
sys_memset.c \
sys_padconf.c \
sys_physcopy.c \
sys_privctl.c \
sys_runctl.c \
sys_safecopy.c \
sys_safememset.c \
sys_schedctl.c \
sys_schedule.c \
sys_setalarm.c \
sys_setgrant.c \
sys_settime.c \
sys_sigreturn.c \
sys_sigsend.c \
sys_sprof.c \
sys_statectl.c \
sys_stime.c \
sys_times.c \
sys_trace.c \
sys_umap.c \
sys_update.c \
sys_vircopy.c \
sys_vmctl.c \
sys_vsafecopy.c \
sys_vtimer.c \
sys_vumap.c \
taskcall.c \
tickdelay.c \
timers.c \
vm_cache.c \
vm_exit.c \
vm_fork.c \
vm_getrusage.c \
vm_info.c \
vm_map_phys.c \
vm_memctl.c \
vm_prepare.c \
vm_procctl.c \
vm_set_priv.c \
vm_update.c
.if ${MKPCI} != "no"
SRCS+= pci_attr_r16.c \
pci_attr_r32.c \
pci_attr_r8.c \
pci_attr_w16.c \
pci_attr_w32.c \
pci_attr_w8.c \
pci_del_acl.c \
pci_dev_name.c \
pci_find_dev.c \
pci_first_dev.c \
pci_get_bar.c \
pci_ids.c \
pci_init.c \
pci_next_dev.c \
pci_rescan_bus.c \
pci_reserve.c \
pci_set_acl.c \
pci_slot_name.c
.endif
.if ${MKCOVERAGE} != "no"
SRCS+= gcov.c \
sef_gcov.c \
llvm_gcov.c
CPPFLAGS+= -DUSE_COVERAGE
.endif
.if ${USE_LIVEUPDATE} != "no"
CPPFLAGS+= -DUSE_LIVEUPDATE
.endif
.if ${USE_SYSDEBUG} != "no"
CPPFLAGS+= -DUSE_SYSDEBUG
.endif
CPPFLAGS.sched_start.c+= -I${NETBSDSRCDIR}/minix
CPPFLAGS.sef_st.c+= -I${NETBSDSRCDIR}/minix
.include <bsd.lib.mk>

View File

@ -1,15 +0,0 @@
# Makefile for arch-dependent libsys code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS+= \
frclock_util.c \
spin.c \
tsc_util.c
CPPFLAGS+= -I${HERE}/../../
CPPFLAGS+= -I${NETBSDSRCDIR} -I${NETBSDSRCDIR}/kernel/arch/${MACHINE_ARCH}/

View File

@ -1,42 +0,0 @@
# Makefile for the lwIP TCP/IP socket driver service (LWIP)
.include <bsd.own.mk>
PROG= lwip
SRCS= lwip.c mempool.c pchain.c addr.c addrpol.c tcpisn.c mcast.c ipsock.c \
pktsock.c tcpsock.c udpsock.c rawsock.c ifdev.c ifaddr.c loopif.c \
ethif.c ndev.c rttree.c route.c rtsock.c lnksock.c lldata.c mibtree.c \
ifconf.c bpfdev.c bpf_filter.c util.c
FILES=${PROG}.conf
FILESNAME=${PROG}
FILESDIR= /etc/system.conf.d
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/lib/liblwip/dist/src/include
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/lib/liblwip/lib
# Disabling USE_INET6 only superficially hides IPv6 support in the service.
.if (${USE_INET6} != "no")
CPPFLAGS+= -DINET6
.endif
# Some warnings are the result of usage of lwIP macros. We must not generate
# errors for those, but even producing the warnings is not helpful, so we
# disable them altogether.
CPPFLAGS+= -Wno-address
DPADD+= ${LIBLWIP} ${LIBSOCKEVENT} ${LIBSOCKDRIVER} ${LIBCHARDRIVER} \
${LIBSYS} ${LIBTIMERS}
LDADD+= -llwip -lsockevent -lsockdriver -lchardriver -lsys -ltimers
WARNS?= 5
.if defined(__MINIX)
.if !empty(DBG:M-Og) || !empty(CFLAGS:M-Og) || \
!empty(DBG:M-g) || !empty(CFLAGS:M-g)
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Og
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
.endif
.endif # defined(__MINIX)
.include <minix.service.mk>

View File

@ -1,699 +0,0 @@
/* LWIP service - addr.c - socket address verification and conversion */
#include "lwip.h"
/*
* Return TRUE if the given socket address is of type AF_UNSPEC, or FALSE
* otherwise.
*/
int
addr_is_unspec(const struct sockaddr * addr, socklen_t addr_len)
{
return (addr_len >= offsetof(struct sockaddr, sa_data) &&
addr->sa_family == AF_UNSPEC);
}
/*
* Check whether the given multicast address is generally valid. This check
* should not be moved into addr_get_inet(), as we do not want to forbid
* creating routes for such addresses, for example. We do however apply the
* restrictions here to all provided source and destination addresses. Return
* TRUE if the address is an acceptable multicast address, or FALSE otherwise.
*/
int
addr_is_valid_multicast(const ip_addr_t * ipaddr)
{
uint8_t scope;
assert(ip_addr_ismulticast(ipaddr));
/* We apply restrictions to IPv6 multicast addresses only. */
if (IP_IS_V6(ipaddr)) {
scope = ip6_addr_multicast_scope(ip_2_ip6(ipaddr));
if (scope == IP6_MULTICAST_SCOPE_RESERVED0 ||
scope == IP6_MULTICAST_SCOPE_RESERVEDF)
return FALSE;
/*
* We do not impose restrictions on the three defined embedded
* flags, even though we put no effort into supporting them,
* especially in terms of automatically creating routes for
* all cases. We do force the fourth flag to be zero.
* Unfortunately there is no lwIP macro to check for this flag.
*/
if (ip_2_ip6(ipaddr)->addr[0] & PP_HTONL(0x00800000UL))
return FALSE;
/* Prevent KAME-embedded zone IDs from entering the system. */
if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN) &&
(ip_2_ip6(ipaddr)->addr[0] & PP_HTONL(0x0000ffffUL)))
return FALSE;
}
return TRUE;
}
/*
* Load a sockaddr structure, as copied from userland, as a lwIP-style IP
* address and (optionally) a port number. The expected type of IP address is
* given as 'type', which must be one of IPADDR_TYPE_{V4,ANY,V6}. If it is
* IPADDR_TYPE_V4, 'addr' is expected to point to a sockaddr_in structure. If
* it is IPADDR_TYPE_{ANY,V6}, 'addr' is expected to point to a sockaddr_in6
* structure. For the _ANY case, the result will be an _ANY address only if it
* is the unspecified (all-zeroes) address and a _V6 address in all other
* cases. For the _V6 case, the result will always be a _V6 address. The
* length of the structure pointed to by 'addr' is given as 'addr_len'. If the
* boolean 'kame' flag is set, addresses will be interpreted to be KAME style,
* meaning that for scoped IPv6 addresses, the zone is embedded in the address
* rather than given in sin6_scope_id. On success, store the resulting IP
* address in 'ipaddr'. If 'port' is not NULL, store the port number in it;
* otherwise, ignore the port number. On any parsing failure, return an
* appropriate negative error code.
*/
int
addr_get_inet(const struct sockaddr * addr, socklen_t addr_len, uint8_t type,
ip_addr_t * ipaddr, int kame, uint16_t * port)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
ip6_addr_t *ip6addr;
uint32_t ifindex;
switch (type) {
case IPADDR_TYPE_V4:
if (addr_len != sizeof(sin))
return EINVAL;
/*
* Getting around strict aliasing problems. Oh, the irony of
* doing an extra memcpy so that the compiler can do a better
* job at optimizing..
*/
memcpy(&sin, addr, sizeof(sin));
if (sin.sin_family != AF_INET)
return EAFNOSUPPORT;
ip_addr_set_ip4_u32(ipaddr, sin.sin_addr.s_addr);
if (port != NULL)
*port = ntohs(sin.sin_port);
return OK;
case IPADDR_TYPE_ANY:
case IPADDR_TYPE_V6:
if (addr_len != sizeof(sin6))
return EINVAL;
/* Again, strict aliasing.. */
memcpy(&sin6, addr, sizeof(sin6));
if (sin6.sin6_family != AF_INET6)
return EAFNOSUPPORT;
memset(ipaddr, 0, sizeof(*ipaddr));
/*
* This is a bit ugly, but NetBSD does not expose s6_addr32 and
* s6_addr is a series of bytes, which is a mismatch for lwIP.
* The alternative would be another memcpy..
*/
ip6addr = ip_2_ip6(ipaddr);
assert(sizeof(ip6addr->addr) == sizeof(sin6.sin6_addr));
memcpy(ip6addr->addr, &sin6.sin6_addr, sizeof(ip6addr->addr));
/*
* If the address may have a scope, extract the zone ID.
* Where the zone ID is depends on the 'kame' parameter: KAME-
* style addresses have it embedded within the address, whereas
* non-KAME addresses use the (misnamed) sin6_scope_id field.
*/
if (ip6_addr_has_scope(ip6addr, IP6_UNKNOWN)) {
if (kame) {
ifindex =
ntohl(ip6addr->addr[0]) & 0x0000ffffUL;
ip6addr->addr[0] &= PP_HTONL(0xffff0000UL);
} else {
/*
* Reject KAME-style addresses for normal
* socket calls, to save ourselves the trouble
* of mixed address styles elsewhere.
*/
if (ip6addr->addr[0] & PP_HTONL(0x0000ffffUL))
return EINVAL;
ifindex = sin6.sin6_scope_id;
}
/*
* Reject invalid zone IDs. This also enforces that
* no zone IDs wider than eight bits enter the system.
* As a side effect, it is not possible to add routes
* for invalid zones, but that should be no problem.
*/
if (ifindex != 0 &&
ifdev_get_by_index(ifindex) == NULL)
return ENXIO;
ip6_addr_set_zone(ip6addr, ifindex);
} else
ip6_addr_clear_zone(ip6addr);
/*
* Set the type to ANY if it was ANY and the address itself is
* ANY as well. Otherwise, we are binding to a specific IPv6
* address, so IPV6_V6ONLY stops being relevant and we should
* leave the address set to V6. Destination addresses for ANY
* are set to V6 elsewhere.
*/
if (type == IPADDR_TYPE_ANY && ip6_addr_isany(ip6addr))
IP_SET_TYPE(ipaddr, type);
else
IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6);
if (port != NULL)
*port = ntohs(sin6.sin6_port);
return OK;
default:
return EAFNOSUPPORT;
}
}
/*
* Store an lwIP-style IP address and port number as a sockaddr structure
* (sockaddr_in or sockaddr_in6, depending on the given IP address) to be
* copied to userland. The result is stored in the buffer pointed to by
* 'addr'. Before the call, 'addr_len' must be set to the size of this buffer.
* This is an internal check to prevent buffer overflows, and must not be used
* to validate input, since a mismatch will trigger a panic. After the call,
* 'addr_len' will be set to the size of the resulting structure. The lwIP-
* style address is given as 'ipaddr'. If the boolean 'kame' flag is set, the
* address will be stored KAME-style, meaning that for scoped IPv6 addresses,
* the address zone will be stored embedded in the address rather than in
* sin6_scope_id. If relevant, 'port' contains the port number in host-byte
* order; otherwise it should be set to zone.
*/
void
addr_put_inet(struct sockaddr * addr, socklen_t * addr_len,
const ip_addr_t * ipaddr, int kame, uint16_t port)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
const ip6_addr_t *ip6addr;
uint32_t zone;
switch (IP_GET_TYPE(ipaddr)) {
case IPADDR_TYPE_V4:
if (*addr_len < sizeof(sin))
panic("provided address buffer too small");
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = ip_addr_get_ip4_u32(ipaddr);
memcpy(addr, &sin, sizeof(sin));
*addr_len = sizeof(sin);
break;
case IPADDR_TYPE_ANY:
case IPADDR_TYPE_V6:
if (*addr_len < sizeof(sin6))
panic("provided address buffer too small");
ip6addr = ip_2_ip6(ipaddr);
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port);
memcpy(&sin6.sin6_addr, ip6addr->addr, sizeof(sin6.sin6_addr));
/*
* If the IPv6 address has a zone set, it must be scoped, and
* we put the zone in the result. It may occur that a scoped
* IPv6 address does not have a zone here though, for example
* if packet routing fails for sendto() with a zoneless address
* on an unbound socket, resulting in an RTM_MISS message. In
* such cases, simply leave the zone index blank in the result.
*/
if (ip6_addr_has_zone(ip6addr)) {
assert(ip6_addr_has_scope(ip6addr, IP6_UNKNOWN));
zone = ip6_addr_zone(ip6addr);
assert(zone <= UINT8_MAX);
if (kame)
sin6.sin6_addr.s6_addr[3] = zone;
else
sin6.sin6_scope_id = zone;
}
memcpy(addr, &sin6, sizeof(sin6));
*addr_len = sizeof(sin6);
break;
default:
panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr));
}
}
/*
* Load a link-layer sockaddr structure (sockaddr_dl), as copied from userland,
* and return the contained name and/or hardware address. The address is
* provided as 'addr', with length 'addr_len'. On success, return OK. If
* 'name' is not NULL, it must be of size 'name_max', and will be used to store
* the (null-terminated) interface name in the given structure if present, or
* the empty string if not. If 'hwaddr' is not NULL, it will be used to store
* the hardware address in the given structure, which must in that case be
* present and exactly 'hwaddr_len' bytes long. On any parsing failure, return
* an appropriate negative error code.
*/
int
addr_get_link(const struct sockaddr * addr, socklen_t addr_len, char * name,
size_t name_max, uint8_t * hwaddr, size_t hwaddr_len)
{
struct sockaddr_dlx sdlx;
size_t nlen, alen;
if (addr_len < offsetof(struct sockaddr_dlx, sdlx_data))
return EINVAL;
/*
* We cannot prevent callers from passing in massively oversized
* sockaddr_dl structure. However, we insist that all the actual data
* be contained within the size of our sockaddr_dlx version.
*/
if (addr_len > sizeof(sdlx))
addr_len = sizeof(sdlx);
memcpy(&sdlx, addr, addr_len);
if (sdlx.sdlx_family != AF_LINK)
return EAFNOSUPPORT;
/* Address selectors are not currently supported. */
if (sdlx.sdlx_slen != 0)
return EINVAL;
nlen = (size_t)sdlx.sdlx_nlen;
alen = (size_t)sdlx.sdlx_alen;
/* The nlen and alen fields are 8-bit, so no risks of overflow here. */
if (addr_len < offsetof(struct sockaddr_dlx, sdlx_data) + nlen + alen)
return EINVAL;
/*
* Copy out the name, truncating it if needed. The name in the
* sockaddr is not null terminated, so we have to do that. If the
* sockaddr has no name, copy out an empty name.
*/
if (name != NULL) {
assert(name_max > 0);
if (name_max > nlen + 1)
name_max = nlen + 1;
memcpy(name, sdlx.sdlx_data, name_max - 1);
name[name_max - 1] = '\0';
}
/*
* Copy over the hardware address. For simplicity, we require that the
* caller specify the exact hardware address length.
*/
if (hwaddr != NULL) {
if (alen != hwaddr_len)
return EINVAL;
memcpy(hwaddr, sdlx.sdlx_data + nlen, hwaddr_len);
}
return OK;
}
/*
* Store a link-layer sockaddr structure (sockaddr_dl), to be copied to
* userland. The result is stored in the buffer pointed to by 'addr'. Before
* the call, 'addr_len' must be set to the size of this buffer. This is an
* internal check to prevent buffer overflows, and must not be used to validate
* input, since a mismatch will trigger a panic. After the call, 'addr_len'
* will be set to the size of the resulting structure. The given interface
* index 'ifindex' and (IFT_) interface type 'type' will always be stored in
* the resulting structure. If 'name' is not NULL, it must be a null-
* terminated interface name string which will be included in the structure.
* If 'hwaddr' is not NULL, it must be a hardware address of length
* 'hwaddr_len', which will also be included in the structure.
*/
void
addr_put_link(struct sockaddr * addr, socklen_t * addr_len, uint32_t ifindex,
uint32_t type, const char * name, const uint8_t * hwaddr,
size_t hwaddr_len)
{
struct sockaddr_dlx sdlx;
size_t name_len;
socklen_t len;
name_len = (name != NULL) ? strlen(name) : 0;
if (hwaddr == NULL)
hwaddr_len = 0;
assert(name_len < IFNAMSIZ);
assert(hwaddr_len <= NETIF_MAX_HWADDR_LEN);
len = offsetof(struct sockaddr_dlx, sdlx_data) + name_len + hwaddr_len;
if (*addr_len < len)
panic("provided address buffer too small");
memset(&sdlx, 0, sizeof(sdlx));
sdlx.sdlx_len = len;
sdlx.sdlx_family = AF_LINK;
sdlx.sdlx_index = ifindex;
sdlx.sdlx_type = type;
sdlx.sdlx_nlen = name_len;
sdlx.sdlx_alen = hwaddr_len;
if (name_len > 0)
memcpy(sdlx.sdlx_data, name, name_len);
if (hwaddr_len > 0)
memcpy(sdlx.sdlx_data + name_len, hwaddr, hwaddr_len);
memcpy(addr, &sdlx, len);
*addr_len = len;
}
/*
* Convert an IPv4 or IPv6 netmask, given as sockaddr structure 'addr', to a
* prefix length. The length of the sockaddr structure is given as 'addr_len'.
* For consistency with addr_get_inet(), the expected address type is given as
* 'type', and must be either IPADDR_TYPE_V4 or IPADDR_TYPE_V6. On success,
* return OK with the number of set prefix bits returned in 'prefix', and
* optionally with a lwIP representation of the netmask stored in 'ipaddr' (if
* not NULL). On failure, return an appropriate negative error code. Note
* that this function does not support compressed IPv4 network masks; such
* addresses must be expanded before a call to this function.
*/
int
addr_get_netmask(const struct sockaddr * addr, socklen_t addr_len,
uint8_t type, unsigned int * prefix, ip_addr_t * ipaddr)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
unsigned int byte, bit;
uint32_t val;
switch (type) {
case IPADDR_TYPE_V4:
if (addr_len != sizeof(sin))
return EINVAL;
memcpy(&sin, addr, sizeof(sin));
if (sin.sin_family != AF_INET)
return EAFNOSUPPORT;
val = ntohl(sin.sin_addr.s_addr);
/* Find the first zero bit. */
for (bit = 0; bit < IP4_BITS; bit++)
if (!(val & (1 << (IP4_BITS - bit - 1))))
break;
*prefix = bit;
/* All bits after the first zero bit must also be zero. */
if (bit < IP4_BITS &&
(val & ((1 << (IP4_BITS - bit - 1)) - 1)))
return EINVAL;
if (ipaddr != NULL)
ip_addr_set_ip4_u32(ipaddr, sin.sin_addr.s_addr);
return OK;
case IPADDR_TYPE_V6:
if (addr_len != sizeof(sin6))
return EINVAL;
memcpy(&sin6, addr, sizeof(sin6));
if (sin6.sin6_family != AF_INET6)
return EAFNOSUPPORT;
/* Find the first zero bit. */
for (byte = 0; byte < __arraycount(sin6.sin6_addr.s6_addr);
byte++)
if (sin6.sin6_addr.s6_addr[byte] != 0xff)
break;
/* If all bits are set, there is nothing more to do. */
if (byte == __arraycount(sin6.sin6_addr.s6_addr)) {
*prefix = __arraycount(sin6.sin6_addr.s6_addr) * NBBY;
return OK;
}
for (bit = 0; bit < NBBY; bit++)
if (!(sin6.sin6_addr.s6_addr[byte] &
(1 << (NBBY - bit - 1))))
break;
*prefix = byte * NBBY + bit;
/* All bits after the first zero bit must also be zero. */
if (bit < NBBY && (sin6.sin6_addr.s6_addr[byte] &
((1 << (NBBY - bit - 1)) - 1)))
return EINVAL;
for (byte++; byte < __arraycount(sin6.sin6_addr.s6_addr);
byte++)
if (sin6.sin6_addr.s6_addr[byte] != 0)
return EINVAL;
if (ipaddr != NULL) {
ip_addr_set_zero_ip6(ipaddr);
memcpy(ip_2_ip6(ipaddr)->addr, &sin6.sin6_addr,
sizeof(ip_2_ip6(ipaddr)->addr));
}
return OK;
default:
panic("unknown IP address type: %u", type);
}
}
/*
* Generate a raw network mask based on the given prefix length.
*/
void
addr_make_netmask(uint8_t * addr, socklen_t addr_len, unsigned int prefix)
{
unsigned int byte, bit;
byte = prefix / NBBY;
bit = prefix % NBBY;
assert(byte + !!bit <= addr_len);
if (byte > 0)
memset(addr, 0xff, byte);
if (bit != 0)
addr[byte++] = (uint8_t)(0xff << (NBBY - bit));
if (byte < addr_len)
memset(&addr[byte], 0, addr_len - byte);
}
/*
* Store a network mask as a sockaddr structure, in 'addr'. Before the call,
* 'addr_len' must be set to the memory size of 'addr'. The address type is
* given as 'type', and must be either IPADDR_TYPE_V4 or IPADDR_TYPE_V6. The
* prefix length from which to generate the network mask is given as 'prefix'.
* Upon return, 'addr_len' is set to the size of the resulting sockaddr
* structure.
*/
void
addr_put_netmask(struct sockaddr * addr, socklen_t * addr_len, uint8_t type,
unsigned int prefix)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
switch (type) {
case IPADDR_TYPE_V4:
if (*addr_len < sizeof(sin))
panic("provided address buffer too small");
assert(prefix <= IP4_BITS);
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
addr_make_netmask((uint8_t *)&sin.sin_addr.s_addr,
sizeof(sin.sin_addr.s_addr), prefix);
memcpy(addr, &sin, sizeof(sin));
*addr_len = sizeof(sin);
break;
case IPADDR_TYPE_V6:
if (*addr_len < sizeof(sin6))
panic("provided address buffer too small");
assert(prefix <= IP6_BITS);
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
addr_make_netmask(sin6.sin6_addr.s6_addr,
sizeof(sin6.sin6_addr.s6_addr), prefix);
memcpy(addr, &sin6, sizeof(sin6));
*addr_len = sizeof(sin6);
break;
default:
panic("unknown IP address type: %u", type);
}
}
/*
* Normalize the given address in 'src' to the given number of prefix bits,
* setting all other bits to zero. Return the result in 'dst'.
*/
void
addr_normalize(ip_addr_t * dst, const ip_addr_t * src, unsigned int prefix)
{
#if !defined(NDEBUG)
unsigned int addr_len;
#endif /* !defined(NDEBUG) */
unsigned int byte, bit;
const uint8_t *srcaddr;
uint8_t type, *dstaddr;
type = IP_GET_TYPE(src);
memset(dst, 0, sizeof(*dst));
IP_SET_TYPE(dst, type);
switch (type) {
case IPADDR_TYPE_V4:
srcaddr = (const uint8_t *)&ip_2_ip4(src)->addr;
dstaddr = (uint8_t *)&ip_2_ip4(dst)->addr;
#if !defined(NDEBUG)
addr_len = sizeof(ip_2_ip4(src)->addr);
#endif /* !defined(NDEBUG) */
break;
case IPADDR_TYPE_V6:
ip6_addr_set_zone(ip_2_ip6(dst), ip6_addr_zone(ip_2_ip6(src)));
srcaddr = (const uint8_t *)&ip_2_ip6(src)->addr;
dstaddr = (uint8_t *)&ip_2_ip6(dst)->addr;
#if !defined(NDEBUG)
addr_len = sizeof(ip_2_ip6(src)->addr);
#endif /* !defined(NDEBUG) */
break;
default:
panic("unknown IP address type: %u", type);
}
byte = prefix / NBBY;
bit = prefix % NBBY;
assert(byte + !!bit <= addr_len);
if (byte > 0)
memcpy(dstaddr, srcaddr, byte);
if (bit != 0) {
dstaddr[byte] =
srcaddr[byte] & (uint8_t)(0xff << (NBBY - bit));
byte++;
}
}
/*
* Return the number of common bits between the given two addresses, up to the
* given maximum. Thus, return a value between 0 and 'max' inclusive.
*/
unsigned int
addr_get_common_bits(const ip_addr_t * ipaddr1, const ip_addr_t * ipaddr2,
unsigned int max)
{
unsigned int addr_len, prefix, bit;
const uint8_t *addr1, *addr2;
uint8_t byte;
switch (IP_GET_TYPE(ipaddr1)) {
case IPADDR_TYPE_V4:
assert(IP_IS_V4(ipaddr2));
addr1 = (const uint8_t *)&ip_2_ip4(ipaddr1)->addr;
addr2 = (const uint8_t *)&ip_2_ip4(ipaddr2)->addr;
addr_len = sizeof(ip_2_ip4(ipaddr1)->addr);
break;
case IPADDR_TYPE_V6:
assert(IP_IS_V6(ipaddr2));
addr1 = (const uint8_t *)&ip_2_ip6(ipaddr1)->addr;
addr2 = (const uint8_t *)&ip_2_ip6(ipaddr2)->addr;
addr_len = sizeof(ip_2_ip6(ipaddr1)->addr);
break;
default:
panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr1));
}
if (addr_len > max * NBBY)
addr_len = max * NBBY;
prefix = 0;
for (prefix = 0; addr_len > 0; addr1++, addr2++, prefix += NBBY) {
if ((byte = (*addr1 ^ *addr2)) != 0) {
/* TODO: see if we want a lookup table for this. */
for (bit = 0; bit < NBBY; bit++, prefix++)
if (byte & (1 << (NBBY - bit - 1)))
break;
break;
}
}
if (prefix > max)
prefix = max;
return prefix;
}
/*
* Convert the given IPv4 address to an IPv4-mapped IPv6 address.
*/
void
addr_make_v4mapped_v6(ip_addr_t * dst, const ip4_addr_t * src)
{
IP_ADDR6(dst, 0, 0, PP_HTONL(0x0000ffffUL), ip4_addr_get_u32(src));
}

View File

@ -1,143 +0,0 @@
/* LWIP service - addrpol.c - address policy table and values */
/*
* The main purpose of this module is to implement the address policy table
* described in RFC 6724. In general, the policy table is used for two
* purposes: source address selection, which is part of this service, and
* destination address selection, which is implemented in libc. NetBSD 7, the
* version that MINIX 3 is synced against at this moment, does not actually
* implement the libc part yet, though. That will change with NetBSD 8, where
* libc uses sysctl(7) to obtain the kernel's policy table, which itself can be
* changed with the new ip6addrctl(8) utility. Once we resync to NetBSD 8, we
* will also have to support this new functionality, and this module is where
* it would be implemented. Since NetBSD 7 is even lacking the necessary
* definitions, we cannot do that ahead of time, though. Thus, until then,
* this module is rather simple, as it only implements a static policy table
* used for source address selection. No changes beyond this module should be
* necessary, e.g. we are purposely not caching labels for local addresses.
*/
#include "lwip.h"
/*
* Address policy table. Currently hardcoded to the default of RFC 6724.
* Sorted by prefix length, so that the first match is always also the longest.
*/
static const struct {
ip_addr_t ipaddr;
unsigned int prefix;
int precedence;
int label;
} addrpol_table[] = {
{ IPADDR6_INIT_HOST(0, 0, 0, 1), 128, 50, 0 },
{ IPADDR6_INIT_HOST(0, 0, 0x0000ffffUL, 0), 96, 35, 4 },
{ IPADDR6_INIT_HOST(0, 0, 0, 0), 96, 1, 3 },
{ IPADDR6_INIT_HOST(0x20010000UL, 0, 0, 0), 32, 5, 5 },
{ IPADDR6_INIT_HOST(0x20020000UL, 0, 0, 0), 16, 30, 2 },
{ IPADDR6_INIT_HOST(0x3ffe0000UL, 0, 0, 0), 16, 1, 12 },
{ IPADDR6_INIT_HOST(0xfec00000UL, 0, 0, 0), 10, 1, 11 },
{ IPADDR6_INIT_HOST(0xfc000000UL, 0, 0, 0), 7, 3, 13 },
{ IPADDR6_INIT_HOST(0, 0, 0, 0), 0, 40, 1 }
};
/*
* Obtain the label value for the given IP address from the address policy
* table. Currently only IPv6 addresses may be given. This function is linear
* in number of address policy table entries, requiring a relatively expensive
* normalization operation for each entry, so it should not be called lightly.
* Its results should not be cached beyond local contexts either, because the
* policy table itself may be changed from userland (in the future).
*
* TODO: convert IPv4 addresses to IPv4-mapped IPv6 addresses.
* TODO: embed the interface index in link-local addresses.
*/
int
addrpol_get_label(const ip_addr_t * iporig)
{
ip_addr_t ipaddr;
unsigned int i;
assert(IP_IS_V6(iporig));
/*
* The policy table is sorted by prefix length such that the first
* match is also the one with the longest prefix, and as such the best.
*/
for (i = 0; i < __arraycount(addrpol_table); i++) {
addr_normalize(&ipaddr, iporig, addrpol_table[i].prefix);
if (ip_addr_cmp(&addrpol_table[i].ipaddr, &ipaddr))
return addrpol_table[i].label;
}
/*
* We cannot possibly get here with the default policy table, because
* the last entry will always match. It is not clear what we should
* return if there is no matching entry, though. For now, we return
* the default label value for the default (::/0) entry, which is 1.
*/
return 1;
}
/*
* Return an opaque positive value (possibly zero) that represents the scope of
* the given IP address. A larger value indicates a wider scope. The 'is_src'
* flag indicates whether the address is a source or a destination address,
* which affects the value returned for unknown addresses. A scope is a direct
* function of only the given address, so the result may be cached on a per-
* address basis without risking invalidation at any point in time.
*/
int
addrpol_get_scope(const ip_addr_t * ipaddr, int is_src)
{
const ip6_addr_t *ip6addr;
/*
* For now, all IPv4 addresses are considered global. This function is
* currently called only for IPv6 addresses anyway.
*/
if (IP_IS_V4(ipaddr))
return IP6_MULTICAST_SCOPE_GLOBAL;
assert(IP_IS_V6(ipaddr));
ip6addr = ip_2_ip6(ipaddr);
/*
* These are ordered not by ascending scope, but (roughly) by expected
* likeliness to match, for performance reasons.
*/
if (ip6_addr_isglobal(ip6addr))
return IP6_MULTICAST_SCOPE_GLOBAL;
if (ip6_addr_islinklocal(ip6addr) || ip6_addr_isloopback(ip6addr))
return IP6_MULTICAST_SCOPE_LINK_LOCAL;
/*
* We deliberately deviate from RFC 6724 Sec. 3.1 by considering
* Unique-Local Addresses (ULAs) to be of smaller scope than global
* addresses, to avoid that during source address selection, a
* preferred ULA is picked over a deprecated global address when given
* a global address as destination, as that would likely result in
* broken two-way communication.
*/
if (ip6_addr_isuniquelocal(ip6addr))
return IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL;
if (ip6_addr_ismulticast(ip6addr))
return ip6_addr_multicast_scope(ip6addr);
/* Site-local addresses are deprecated. */
if (ip6_addr_issitelocal(ip6addr))
return IP6_MULTICAST_SCOPE_SITE_LOCAL;
/*
* If the address is a source address, give it a scope beyond global to
* make sure that a "real" global address is picked first. If the
* address is a destination address, give it a global scope so as to
* pick "real" global addresses over unknown-scope source addresses.
*/
if (is_src)
return IP6_MULTICAST_SCOPE_RESERVEDF; /* greater than GLOBAL */
else
return IP6_MULTICAST_SCOPE_GLOBAL;
}

View File

@ -1,561 +0,0 @@
/* LWIP service - bpf_filter.c - Berkeley Packet Filter core implementation */
/*
* This is basically a drop-in replacement of NetBSD's bpf_filter.c, which
* itself can be compiled for either the NetBSD kernel or for userland. On
* MINIX 3, we would like to perform certain checks that NetBSD implements only
* for its kernel (e.g., memory store access validation) while replacing the
* NetBSD kernel specifics with our own (pbuf instead of mbuf, no BPF contexts
* for now, etc.). As a result, it is easier to reimplement the whole thing,
* because there is not all that much to it.
*
* Support for the standard BSD API allows us to run standard tests against
* this module from userland, where _MINIX_SYSTEM is not defined. MINIX 3
* specific extensions are enabled only if _MINIX_SYSTEM is defined.
*/
#include <string.h>
#include <limits.h>
#include <net/bpf.h>
#include <minix/bitmap.h>
#ifdef _MINIX_SYSTEM
#include "lwip.h"
/*
* Obtain an unsigned 32-bit value in network byte order from the pbuf chain
* 'pbuf' at offset 'k'. The given offset is guaranteed to be within bounds.
*/
static uint32_t
bpf_get32_ext(const struct pbuf * pbuf, uint32_t k)
{
uint32_t val;
unsigned int i;
/*
* Find the pbuf that contains the first byte. We expect that most
* filters will operate only on the headers of packets, so that we
* mostly avoid going through this O(n) loop. Since only the superuser
* can open BPF devices at all, we need not be worried about abuse in
* this regard. However, it turns out that this loop is particularly
* CPU-intensive after all, we can probably improve it by caching the
* last visited pbuf, as read locality is likely high.
*/
while (k >= pbuf->len) {
k -= pbuf->len;
pbuf = pbuf->next;
assert(pbuf != NULL);
}
/*
* We assume that every pbuf has some data, but we make no assumptions
* about any minimum amount of data per pbuf. Therefore, we may have
* to take the bytes from anywhere between one and four pbufs.
* Hopefully the compiler will unroll this loop for us.
*/
val = (uint32_t)(((u_char *)pbuf->payload)[k]) << 24;
for (i = 0; i < 3; i++) {
if (k >= (uint32_t)pbuf->len - 1) {
k = 0;
pbuf = pbuf->next;
assert(pbuf != NULL);
} else
k++;
val = (val << 8) | (uint32_t)(((u_char *)pbuf->payload)[k]);
}
return val;
}
/*
* Obtain an unsigned 16-bit value in network byte order from the pbuf chain
* 'pbuf' at offset 'k'. The given offset is guaranteed to be within bounds.
*/
static uint32_t
bpf_get16_ext(const struct pbuf * pbuf, uint32_t k)
{
/* As above. */
while (k >= pbuf->len) {
k -= pbuf->len;
pbuf = pbuf->next;
assert(pbuf != NULL);
}
/*
* There are only two possible cases to cover here: either the two
* bytes are in the same pbuf, or they are in subsequent ones.
*/
if (k < (uint32_t)pbuf->len - 1) {
return ((uint32_t)(((u_char *)pbuf->payload)[k]) << 8) |
(uint32_t)(((u_char *)pbuf->next->payload)[k + 1]);
} else {
assert(pbuf->next != NULL);
return ((uint32_t)(((u_char *)pbuf->payload)[k]) << 8) |
(uint32_t)(((u_char *)pbuf->next->payload)[0]);
}
}
/*
* Obtain an unsigned 8-bit value from the pbuf chain 'pbuf' at offset 'k'.
* The given offset is guaranteed to be within bounds.
*/
static uint32_t
bpf_get8_ext(const struct pbuf * pbuf, uint32_t k)
{
/* As above. */
while (k >= pbuf->len) {
k -= pbuf->len;
pbuf = pbuf->next;
assert(pbuf != NULL);
}
return (uint32_t)(((u_char *)pbuf->payload)[k]);
}
#endif /* _MINIX_SYSTEM */
/*
* Execute a BPF filter program on (the first part of) a packet, and return the
* maximum size of the packet that should be delivered to the filter owner.
*
* The 'pc' parameter points to an array of BPF instructions that together form
* the filter program to be executed. If 'pc' is NULL, the packet is fully
* accepted. Otherwise, the given program MUST have passed a previous call to
* bpf_validate(). Not doing so will allow for arbitrary memory access.
*
* The 'packet' array contains up to the whole packet. The value of 'total'
* denotes the total length of the packet; 'len' contains the size of the array
* 'packet'. Chunked storage of the packet is not supported at this time.
*
* If executing the program succeeds, the return value is the maximum number of
* bytes from the packet to be delivered. The return value may exceed the full
* packet size. If the number of bytes returned is zero, the packet is to be
* ignored. If the program fails to execute properly and return a value, a
* value of zero is returned as well, thus also indicating that the packet
* should be ignored. This is intentional: it saves filter programs from
* having to perform explicit checks on the packet they are filtering.
*/
u_int
bpf_filter(const struct bpf_insn * pc, const u_char * packet, u_int total,
u_int len)
#ifdef _MINIX_SYSTEM
{
return bpf_filter_ext(pc, NULL /*pbuf*/, packet, total, len);
}
u_int
bpf_filter_ext(const struct bpf_insn * pc, const struct pbuf * pbuf,
const u_char * packet, u_int total, u_int len)
#endif /* _MINIX_SYSTEM */
{
uint32_t k, a, x, mem[BPF_MEMWORDS];
/* An empty program accepts all packets. */
if (pc == NULL)
return UINT_MAX;
/*
* We need not clear 'mem': the checker guarantees that each memory
* store word is always written before it is read.
*/
a = 0;
x = 0;
/* Execute the program. */
for (;; pc++) {
k = pc->k;
switch (pc->code) {
case BPF_LD+BPF_W+BPF_IND: /* A <- P[X+k:4] */
if (k + x < k)
return 0;
k += x;
/* FALLTHROUGH */
case BPF_LD+BPF_W+BPF_ABS: /* A <- P[k:4] */
/*
* 'k' may have any value, so check bounds in such a
* way that 'k' cannot possibly overflow and wrap.
*/
if (len >= 3 && k < len - 3)
a = ((uint32_t)packet[k] << 24) |
((uint32_t)packet[k + 1] << 16) |
((uint32_t)packet[k + 2] << 8) |
(uint32_t)packet[k + 3];
#ifdef _MINIX_SYSTEM
else if (total >= 3 && k < total - 3)
a = bpf_get32_ext(pbuf, k);
#endif /* _MINIX_SYSTEM */
else
return 0;
break;
case BPF_LD+BPF_H+BPF_IND: /* A <- P[X+k:2] */
if (k + x < k)
return 0;
k += x;
/* FALLTHROUGH */
case BPF_LD+BPF_H+BPF_ABS: /* A <- P[k:2] */
/* As above. */
if (len >= 1 && k < len - 1)
a = ((uint32_t)packet[k] << 8) |
(uint32_t)packet[k + 1];
#ifdef _MINIX_SYSTEM
else if (total >= 1 && k < total - 1)
a = bpf_get16_ext(pbuf, k);
#endif /* _MINIX_SYSTEM */
else
return 0;
break;
case BPF_LD+BPF_B+BPF_IND: /* A <- P[X+k:1] */
if (k + x < k)
return 0;
k += x;
/* FALLTHROUGH */
case BPF_LD+BPF_B+BPF_ABS: /* A <- P[k:1] */
if (k < len)
a = (uint32_t)packet[k];
#ifdef _MINIX_SYSTEM
else if (k < total)
a = bpf_get8_ext(pbuf, k);
#endif /* _MINIX_SYSTEM */
else
return 0;
break;
case BPF_LD+BPF_W+BPF_LEN: /* A <- len */
a = total;
break;
case BPF_LD+BPF_IMM: /* A <- k */
a = k;
break;
case BPF_LD+BPF_MEM: /* A <- M[k] */
a = mem[k];
break;
case BPF_LDX+BPF_IMM: /* X <- k */
x = k;
break;
case BPF_LDX+BPF_MEM: /* X <- M[k] */
x = mem[k];
break;
case BPF_LDX+BPF_LEN: /* X <- len */
x = total;
break;
case BPF_LDX+BPF_B+BPF_MSH: /* X <- 4*(P[k:1]&0xf) */
if (k < len)
x = ((uint32_t)packet[k] & 0xf) << 2;
#ifdef _MINIX_SYSTEM
else if (k < total)
x = (bpf_get8_ext(pbuf, k) & 0xf) << 2;
#endif /* _MINIX_SYSTEM */
else
return 0;
break;
case BPF_ST: /* M[k] <- A */
mem[k] = a;
break;
case BPF_STX: /* M[k] <- X */
mem[k] = x;
break;
case BPF_ALU+BPF_ADD+BPF_K: /* A <- A + k */
a += k;
break;
case BPF_ALU+BPF_SUB+BPF_K: /* A <- A - k */
a -= k;
break;
case BPF_ALU+BPF_MUL+BPF_K: /* A <- A * k */
a *= k;
break;
case BPF_ALU+BPF_DIV+BPF_K: /* A <- A / k */
a /= k;
break;
case BPF_ALU+BPF_MOD+BPF_K: /* A <- A % k */
a %= k;
break;
case BPF_ALU+BPF_AND+BPF_K: /* A <- A & k */
a &= k;
break;
case BPF_ALU+BPF_OR+BPF_K: /* A <- A | k */
a |= k;
break;
case BPF_ALU+BPF_XOR+BPF_K: /* A <- A ^ k */
a ^= k;
break;
case BPF_ALU+BPF_LSH+BPF_K: /* A <- A << k */
a <<= k;
break;
case BPF_ALU+BPF_RSH+BPF_K: /* A <- A >> k */
a >>= k;
break;
case BPF_ALU+BPF_ADD+BPF_X: /* A <- A + X */
a += x;
break;
case BPF_ALU+BPF_SUB+BPF_X: /* A <- A - X */
a -= x;
break;
case BPF_ALU+BPF_MUL+BPF_X: /* A <- A * X */
a *= x;
break;
case BPF_ALU+BPF_DIV+BPF_X: /* A <- A / X */
if (x == 0)
return 0;
a /= x;
break;
case BPF_ALU+BPF_MOD+BPF_X: /* A <- A % X */
if (x == 0)
return 0;
a %= x;
break;
case BPF_ALU+BPF_AND+BPF_X: /* A <- A & X */
a &= x;
break;
case BPF_ALU+BPF_OR+BPF_X: /* A <- A | X */
a |= x;
break;
case BPF_ALU+BPF_XOR+BPF_X: /* A <- A ^ X */
a ^= x;
break;
case BPF_ALU+BPF_LSH+BPF_X: /* A <- A << X */
if (x >= 32)
return 0;
a <<= x;
break;
case BPF_ALU+BPF_RSH+BPF_X: /* A <- A >> X */
if (x >= 32)
return 0;
a >>= x;
break;
case BPF_ALU+BPF_NEG: /* A <- -A */
a = -a;
break;
case BPF_JMP+BPF_JA: /* pc += k */
pc += k;
break;
case BPF_JMP+BPF_JGT+BPF_K: /* pc += (A > k) ? jt : jf */
pc += (a > k) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JGE+BPF_K: /* pc += (A >= k) ? jt : jf */
pc += (a >= k) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JEQ+BPF_K: /* pc += (A == k) ? jt : jf */
pc += (a == k) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JSET+BPF_K: /* pc += (A & k) ? jt : jf */
pc += (a & k) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JGT+BPF_X: /* pc += (A > X) ? jt : jf */
pc += (a > x) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JGE+BPF_X: /* pc += (A >= X) ? jt : jf */
pc += (a >= x) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JEQ+BPF_X: /* pc += (A == X) ? jt : jf */
pc += (a == x) ? pc->jt : pc->jf;
break;
case BPF_JMP+BPF_JSET+BPF_X: /* pc += (A & X) ? jt : jf */
pc += (a & x) ? pc->jt : pc->jf;
break;
case BPF_RET+BPF_A: /* accept A bytes */
return a;
case BPF_RET+BPF_K: /* accept K bytes */
return k;
case BPF_MISC+BPF_TAX: /* X <- A */
x = a;
break;
case BPF_MISC+BPF_TXA: /* A <- X */
a = x;
break;
default: /* unknown instruction */
return 0;
}
}
/* NOTREACHED */
}
/*
* In order to avoid having to perform explicit memory allocation, we store
* some validation state on the stack, using data types that are as small as
* possible for the current definitions. The data types, and in fact the whole
* assumption that we can store the state on the stack, may need to be revised
* if certain constants are increased in the future. As of writing, the
* validation routine uses a little over 1KB of stack memory.
*/
#if BPF_MEMWORDS <= 16 /* value as of writing: 16 */
typedef uint16_t meminv_t;
#else
#error "increased BPF_MEMWORDS may require code revision"
#endif
#if BPF_MAXINSNS > 2048 /* value as of writing: 512 */
#error "increased BPF_MAXINSNS may require code revision"
#endif
/*
* Verify that the given filter program is safe to execute, by performing as
* many static validity checks as possible. The program is given as 'insns',
* which must be an array of 'ninsns' BPF instructions. Unlike bpf_filter(),
* this function does not accept empty filter programs. The function returns 1
* if the program was successfully validated, or 0 if the program should not be
* accepted.
*/
int
bpf_validate(const struct bpf_insn * insns, int ninsns)
{
bitchunk_t reachable[BITMAP_CHUNKS(BPF_MAXINSNS)];
meminv_t invalid, meminv[BPF_MAXINSNS];
const struct bpf_insn *insn;
u_int pc, count, target;
int advance;
if (insns == NULL || ninsns <= 0 || ninsns > BPF_MAXINSNS)
return 0;
count = (u_int)ninsns;
memset(reachable, 0, sizeof(reachable[0]) * BITMAP_CHUNKS(count));
memset(meminv, 0, sizeof(meminv[0]) * count);
SET_BIT(reachable, 0);
meminv[0] = (meminv_t)~0;
for (pc = 0; pc < count; pc++) {
/* We completely ignore instructions that are not reachable. */
if (!GET_BIT(reachable, pc))
continue;
invalid = meminv[pc];
advance = 1;
insn = &insns[pc];
switch (insn->code) {
case BPF_LD+BPF_W+BPF_ABS:
case BPF_LD+BPF_H+BPF_ABS:
case BPF_LD+BPF_B+BPF_ABS:
case BPF_LD+BPF_W+BPF_IND:
case BPF_LD+BPF_H+BPF_IND:
case BPF_LD+BPF_B+BPF_IND:
case BPF_LD+BPF_LEN:
case BPF_LD+BPF_IMM:
case BPF_LDX+BPF_IMM:
case BPF_LDX+BPF_LEN:
case BPF_LDX+BPF_B+BPF_MSH:
case BPF_ALU+BPF_ADD+BPF_K:
case BPF_ALU+BPF_SUB+BPF_K:
case BPF_ALU+BPF_MUL+BPF_K:
case BPF_ALU+BPF_AND+BPF_K:
case BPF_ALU+BPF_OR+BPF_K:
case BPF_ALU+BPF_XOR+BPF_K:
case BPF_ALU+BPF_ADD+BPF_X:
case BPF_ALU+BPF_SUB+BPF_X:
case BPF_ALU+BPF_MUL+BPF_X:
case BPF_ALU+BPF_DIV+BPF_X:
case BPF_ALU+BPF_MOD+BPF_X:
case BPF_ALU+BPF_AND+BPF_X:
case BPF_ALU+BPF_OR+BPF_X:
case BPF_ALU+BPF_XOR+BPF_X:
case BPF_ALU+BPF_LSH+BPF_X:
case BPF_ALU+BPF_RSH+BPF_X:
case BPF_ALU+BPF_NEG:
case BPF_MISC+BPF_TAX:
case BPF_MISC+BPF_TXA:
/* Nothing we can check for these. */
break;
case BPF_ALU+BPF_DIV+BPF_K:
case BPF_ALU+BPF_MOD+BPF_K:
/* No division by zero. */
if (insn->k == 0)
return 0;
break;
case BPF_ALU+BPF_LSH+BPF_K:
case BPF_ALU+BPF_RSH+BPF_K:
/* Do not invoke undefined behavior. */
if (insn->k >= 32)
return 0;
break;
case BPF_LD+BPF_MEM:
case BPF_LDX+BPF_MEM:
/*
* Only allow loading words that have been stored in
* all execution paths leading up to this instruction.
*/
if (insn->k >= BPF_MEMWORDS ||
(invalid & (1 << insn->k)))
return 0;
break;
case BPF_ST:
case BPF_STX:
if (insn->k >= BPF_MEMWORDS)
return 0;
invalid &= ~(1 << insn->k);
break;
case BPF_JMP+BPF_JA:
/*
* Make sure that the target instruction of the jump is
* still part of the program, and mark it as reachable.
*/
if (insn->k >= count - pc - 1)
return 0;
target = pc + insn->k + 1;
SET_BIT(reachable, target);
meminv[target] |= invalid;
advance = 0;
break;
case BPF_JMP+BPF_JGT+BPF_K:
case BPF_JMP+BPF_JGE+BPF_K:
case BPF_JMP+BPF_JEQ+BPF_K:
case BPF_JMP+BPF_JSET+BPF_K:
case BPF_JMP+BPF_JGT+BPF_X:
case BPF_JMP+BPF_JGE+BPF_X:
case BPF_JMP+BPF_JEQ+BPF_X:
case BPF_JMP+BPF_JSET+BPF_X:
/*
* Make sure that both target instructions are still
* part of the program, and mark both as reachable.
* There is no chance that the additions will overflow.
*/
target = pc + insn->jt + 1;
if (target >= count)
return 0;
SET_BIT(reachable, target);
meminv[target] |= invalid;
target = pc + insn->jf + 1;
if (target >= count)
return 0;
SET_BIT(reachable, target);
meminv[target] |= invalid;
advance = 0;
break;
case BPF_RET+BPF_A:
case BPF_RET+BPF_K:
advance = 0;
break;
default:
return 0;
}
/*
* After most instructions, we simply advance to the next. For
* one thing, this means that there must be a next instruction
* at all.
*/
if (advance) {
if (pc + 1 == count)
return 0;
SET_BIT(reachable, pc + 1);
meminv[pc + 1] |= invalid;
}
}
/* The program has passed all our basic tests. */
return 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,930 +0,0 @@
/* LWIP service - ifconf.c - interface configuration */
#include "lwip.h"
#include "ifaddr.h"
#include "lldata.h"
#include <net/if_media.h>
#include <minix/if.h>
#define LOOPBACK_IFNAME "lo0" /* name of the loopback interface */
/*
* Initialize the first loopback device, which is present by default.
*/
void
ifconf_init(void)
{
const struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr = { htonl(INADDR_LOOPBACK) }
};
struct sockaddr_in6 ll_addr6 = {
.sin6_family = AF_INET6,
};
const struct sockaddr_in6 lo_addr6 = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LOOPBACK_INIT
};
const struct in6_addrlifetime lifetime = {
.ia6t_vltime = ND6_INFINITE_LIFETIME,
.ia6t_pltime = ND6_INFINITE_LIFETIME
};
struct sockaddr_in6 mask6;
struct ifdev *ifdev;
socklen_t addr_len;
int r;
if ((r = ifdev_create(LOOPBACK_IFNAME)) != OK)
panic("unable to create loopback interface: %d", r);
if ((ifdev = ifdev_find_by_name(LOOPBACK_IFNAME)) == NULL)
panic("unable to find loopback interface");
if ((r = ifaddr_v4_add(ifdev, &addr, NULL, NULL, NULL, 0)) != OK)
panic("unable to set IPv4 address on loopback interface: %d",
r);
addr_len = sizeof(mask6);
addr_put_netmask((struct sockaddr *)&mask6, &addr_len, IPADDR_TYPE_V6,
64 /*prefix*/);
ll_addr6.sin6_addr.s6_addr[0] = 0xfe;
ll_addr6.sin6_addr.s6_addr[1] = 0x80;
ll_addr6.sin6_addr.s6_addr[15] = ifdev_get_index(ifdev);
if ((r = ifaddr_v6_add(ifdev, &ll_addr6, &mask6, NULL, 0,
&lifetime)) != OK)
panic("unable to set IPv6 address on loopback interface: %d",
r);
addr_len = sizeof(mask6);
addr_put_netmask((struct sockaddr *)&mask6, &addr_len, IPADDR_TYPE_V6,
128 /*prefix*/);
if ((r = ifaddr_v6_add(ifdev, &lo_addr6, &mask6, NULL, 0,
&lifetime)) != OK)
panic("unable to set IPv6 address on loopback interface: %d",
r);
if ((r = ifdev_set_ifflags(ifdev, IFF_UP)) != OK)
panic("unable to bring up loopback interface");
}
/*
* Process an address family independent IOCTL request with an "ifreq"
* structure.
*/
static int
ifconf_ioctl_ifreq(unsigned long request, const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct ifreq ifr;
int r;
if ((r = sockdriver_copyin(data, 0, &ifr, sizeof(ifr))) != OK)
return r;
if (request != SIOCIFCREATE) {
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifr.ifr_name)) == NULL)
return ENXIO;
} else
ifdev = NULL;
switch (request) {
case SIOCGIFFLAGS:
ifr.ifr_flags = ifdev_get_ifflags(ifdev);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCSIFFLAGS:
/*
* Unfortunately, ifr_flags is a signed integer and the sign
* bit is in fact used as a flag, so without explicit casting
* we end up setting all upper bits of the (full) integer. If
* NetBSD ever extends the field, this assert should trigger..
*/
assert(sizeof(ifr.ifr_flags) == sizeof(short));
return ifdev_set_ifflags(ifdev, (unsigned short)ifr.ifr_flags);
case SIOCGIFMETRIC:
ifr.ifr_metric = ifdev_get_metric(ifdev);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCSIFMETRIC:
/* The metric is not used within the operating system. */
ifdev_set_metric(ifdev, ifr.ifr_metric);
return OK;
case SIOCSIFMEDIA:
return ifdev_set_ifmedia(ifdev, ifr.ifr_media);
case SIOCGIFMTU:
ifr.ifr_mtu = ifdev_get_mtu(ifdev);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCSIFMTU:
return ifdev_set_mtu(ifdev, ifr.ifr_mtu);
case SIOCIFCREATE:
if (memchr(ifr.ifr_name, '\0', sizeof(ifr.ifr_name)) == NULL)
return EINVAL;
return ifdev_create(ifr.ifr_name);
case SIOCIFDESTROY:
return ifdev_destroy(ifdev);
case SIOCGIFDLT:
ifr.ifr_dlt = ifdev_get_dlt(ifdev);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCGIFINDEX:
ifr.ifr_index = ifdev_get_index(ifdev);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
default:
return ENOTTY;
}
}
/*
* Process an address family independent IOCTL request with an "ifcapreq"
* structure.
*/
static int
ifconf_ioctl_ifcap(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct ifcapreq ifcr;
int r;
if ((r = sockdriver_copyin(data, 0, &ifcr, sizeof(ifcr))) != OK)
return r;
ifcr.ifcr_name[sizeof(ifcr.ifcr_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifcr.ifcr_name)) == NULL)
return ENXIO;
switch (request) {
case SIOCSIFCAP:
return ifdev_set_ifcap(ifdev, ifcr.ifcr_capenable);
case SIOCGIFCAP:
ifdev_get_ifcap(ifdev, &ifcr.ifcr_capabilities,
&ifcr.ifcr_capenable);
return sockdriver_copyout(data, 0, &ifcr, sizeof(ifcr));
default:
return ENOTTY;
}
}
/*
* Process an address family independent IOCTL request with an "ifmediareq"
* structure.
*/
static int
ifconf_ioctl_ifmedia(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct ifmediareq ifm;
int r;
if ((r = sockdriver_copyin(data, 0, &ifm, sizeof(ifm))) != OK)
return r;
ifm.ifm_name[sizeof(ifm.ifm_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifm.ifm_name)) == NULL)
return ENXIO;
switch (request) {
case MINIX_SIOCGIFMEDIA:
if ((r = ifdev_get_ifmedia(ifdev, &ifm.ifm_current,
&ifm.ifm_active)) != OK)
return r;
ifm.ifm_mask = 0;
switch (ifdev_get_link(ifdev)) {
case LINK_STATE_UP:
ifm.ifm_status = IFM_AVALID | IFM_ACTIVE;
break;
case LINK_STATE_DOWN:
ifm.ifm_status = IFM_AVALID;
break;
default:
ifm.ifm_status = 0;
break;
}
/*
* TODO: support for the list of supported media types. This
* one is not easy, because we cannot simply suspend the IOCTL
* and query the driver. For now, return only entry (which is
* the minimum for ifconfig(8) not to complain), namely the
* currently selected one.
*/
if (ifm.ifm_ulist != NULL) {
if (ifm.ifm_count < 1)
return ENOMEM;
/*
* Copy out the 'list', which consists of one entry.
* If we were to produce multiple entries, we would
* have to check against the MINIX_IF_MAXMEDIA limit.
*/
if ((r = sockdriver_copyout(data,
offsetof(struct minix_ifmediareq, mifm_list),
&ifm.ifm_current, sizeof(ifm.ifm_current))) != OK)
return r;
}
ifm.ifm_count = 1;
return sockdriver_copyout(data, 0, &ifm, sizeof(ifm));
default:
return ENOTTY;
}
}
/*
* Process an address family independent IOCTL request with an "if_clonereq"
* structure.
*/
static int
ifconf_ioctl_ifclone(unsigned long request,
const struct sockdriver_data * data)
{
struct if_clonereq ifcr;
const char *ptr;
char name[IFNAMSIZ];
size_t off;
unsigned int num;
int r;
if ((r = sockdriver_copyin(data, 0, &ifcr, sizeof(ifcr))) != OK)
return r;
if (ifcr.ifcr_count < 0)
return EINVAL;
off = offsetof(struct minix_if_clonereq, mifcr_buffer);
for (num = 0; (ptr = ifdev_enum_vtypes(num)) != NULL; num++) {
/* Prevent overflow in case we ever have over 128 vtypes.. */
if (num == MINIX_IF_MAXCLONERS)
break;
if (ifcr.ifcr_buffer == NULL ||
num >= (unsigned int)ifcr.ifcr_count)
continue;
memset(name, 0, sizeof(name));
strlcpy(name, ptr, sizeof(name));
if ((r = sockdriver_copyout(data, off, name,
sizeof(name))) != OK)
return r;
off += sizeof(name);
}
ifcr.ifcr_total = num;
return sockdriver_copyout(data, 0, &ifcr, sizeof(ifcr));
}
/*
* Process an address family independent IOCTL request with an "if_addrprefreq"
* structure.
*/
static int
ifconf_ioctl_ifaddrpref(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct if_addrprefreq ifap;
int r;
if ((r = sockdriver_copyin(data, 0, &ifap, sizeof(ifap))) != OK)
return r;
ifap.ifap_name[sizeof(ifap.ifap_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifap.ifap_name)) == NULL)
return ENXIO;
/*
* For now, we simply support only a preference of 0. We do not try to
* look up the given address, nor do we return the looked up address.
*/
switch (request) {
case SIOCSIFADDRPREF:
if (ifap.ifap_preference != 0)
return EINVAL;
return OK;
case SIOCGIFADDRPREF:
ifap.ifap_preference = 0;
return sockdriver_copyout(data, 0, &ifap, sizeof(ifap));
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET with an "ifreq" structure.
*/
static int
ifconf_ioctl_v4_ifreq(unsigned long request,
const struct sockdriver_data * data)
{
struct sockaddr_in addr, mask, bcast, dest, *sin = NULL /*gcc*/;
struct ifdev *ifdev;
struct ifreq ifr;
ifaddr_v4_num_t num;
int r, flags;
if ((r = sockdriver_copyin(data, 0, &ifr, sizeof(ifr))) != OK)
return r;
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifr.ifr_name)) == NULL)
return ENXIO;
switch (request) {
case SIOCGIFADDR:
case SIOCGIFNETMASK:
case SIOCGIFBRDADDR:
case SIOCGIFDSTADDR:
/* Retrieve all addresses, then copy out the desired one. */
switch (request) {
case SIOCGIFADDR: sin = &addr; break;
case SIOCGIFNETMASK: sin = &mask; break;
case SIOCGIFBRDADDR: sin = &bcast; break;
case SIOCGIFDSTADDR: sin = &dest; break;
}
sin->sin_len = 0;
if ((r = ifaddr_v4_get(ifdev, (ifaddr_v4_num_t)0, &addr, &mask,
&bcast, &dest)) != OK)
return r;
if (sin->sin_len == 0) /* not filled in */
return EADDRNOTAVAIL;
memcpy(&ifr.ifr_addr, sin, sizeof(*sin));
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCGIFAFLAG_IN:
if ((r = ifaddr_v4_find(ifdev,
(struct sockaddr_in *)&ifr.ifr_addr, &num)) != OK)
return r;
ifr.ifr_addrflags = ifaddr_v4_get_flags(ifdev, num);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCSIFADDR:
/*
* This one is slightly different from the rest, in that we
* either set or update the primary address: if we set it, we
* must let _add() generate a matching netmask automatically,
* while if we update it, _add() would fail unless we first
* delete the old entry.
*/
sin = (struct sockaddr_in *)&ifr.ifr_addr;
if ((r = ifaddr_v4_get(ifdev, (ifaddr_v4_num_t)0, &addr, &mask,
&bcast, &dest)) == OK) {
flags = ifaddr_v4_get_flags(ifdev, (ifaddr_v4_num_t)0);
ifaddr_v4_del(ifdev, (ifaddr_v4_num_t)0);
/*
* If setting the new address fails, reinstating the
* old address should always work. This is really ugly
* as it generates routing socket noise, but this call
* is deprecated anyway.
*/
if ((r = ifaddr_v4_add(ifdev, sin, &mask, &bcast,
&dest, 0 /*flags*/)) != OK)
(void)ifaddr_v4_add(ifdev, &addr, &mask,
&bcast, &dest, flags);
return r;
} else
return ifaddr_v4_add(ifdev, sin, NULL /*mask*/,
NULL /*bcast*/, NULL /*dest*/, 0 /*flags*/);
case SIOCSIFNETMASK:
case SIOCSIFBRDADDR:
case SIOCSIFDSTADDR:
/* These calls only update the existing primary address. */
if ((r = ifaddr_v4_get(ifdev, (ifaddr_v4_num_t)0, &addr, &mask,
&bcast, &dest)) != OK)
return r;
sin = (struct sockaddr_in *)&ifr.ifr_addr;
switch (request) {
case SIOCSIFNETMASK: memcpy(&mask, sin, sizeof(mask)); break;
case SIOCSIFBRDADDR: memcpy(&bcast, sin, sizeof(bcast)); break;
case SIOCSIFDSTADDR: memcpy(&dest, sin, sizeof(dest)); break;
}
return ifaddr_v4_add(ifdev, &addr, &mask, &bcast, &dest,
ifaddr_v4_get_flags(ifdev, (ifaddr_v4_num_t)0));
case SIOCDIFADDR:
if ((r = ifaddr_v4_find(ifdev,
(struct sockaddr_in *)&ifr.ifr_addr, &num)) != OK)
return r;
ifaddr_v4_del(ifdev, num);
return OK;
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET with an "ifaliasreq" structure.
*/
static int
ifconf_ioctl_v4_ifalias(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct ifaliasreq ifra;
struct sockaddr_in dest;
ifaddr_v4_num_t num;
int r;
if ((r = sockdriver_copyin(data, 0, &ifra, sizeof(ifra))) != OK)
return r;
ifra.ifra_name[sizeof(ifra.ifra_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifra.ifra_name)) == NULL)
return ENXIO;
switch (request) {
case SIOCAIFADDR:
return ifaddr_v4_add(ifdev,
(struct sockaddr_in *)&ifra.ifra_addr,
(struct sockaddr_in *)&ifra.ifra_mask,
(struct sockaddr_in *)&ifra.ifra_broadaddr,
(struct sockaddr_in *)&ifra.ifra_dstaddr, 0 /*flags*/);
case SIOCGIFALIAS:
if ((r = ifaddr_v4_find(ifdev,
(struct sockaddr_in *)&ifra.ifra_addr, &num)) != OK)
return r;
/*
* The broadcast and destination address are stored in the same
* ifaliasreq field. We cannot pass a pointer to the same
* field to ifaddr_v4_get(). So, use a temporary variable.
*/
(void)ifaddr_v4_get(ifdev, num,
(struct sockaddr_in *)&ifra.ifra_addr,
(struct sockaddr_in *)&ifra.ifra_mask,
(struct sockaddr_in *)&ifra.ifra_broadaddr, &dest);
if (ifra.ifra_broadaddr.sa_len == 0)
memcpy(&ifra.ifra_dstaddr, &dest, sizeof(dest));
return sockdriver_copyout(data, 0, &ifra, sizeof(ifra));
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET.
*/
static int
ifconf_ioctl_v4(unsigned long request, const struct sockdriver_data * data,
endpoint_t user_endpt)
{
switch (request) {
case SIOCSIFADDR:
case SIOCSIFDSTADDR:
case SIOCSIFBRDADDR:
case SIOCSIFNETMASK:
case SIOCDIFADDR:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFADDR:
case SIOCGIFDSTADDR:
case SIOCGIFBRDADDR:
case SIOCGIFNETMASK:
case SIOCGIFAFLAG_IN:
return ifconf_ioctl_v4_ifreq(request, data);
case SIOCAIFADDR:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFALIAS:
return ifconf_ioctl_v4_ifalias(request, data);
default:
return ENOTTY;
}
}
#ifdef INET6
/*
* Process an IOCTL request for AF_INET6 with an "in6_ifreq" structure.
*/
static int
ifconf_ioctl_v6_ifreq(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct in6_ifreq ifr;
ifaddr_v6_num_t num;
int r;
if ((r = sockdriver_copyin(data, 0, &ifr, sizeof(ifr))) != OK)
return r;
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifr.ifr_name)) == NULL)
return ENXIO;
if ((r = ifaddr_v6_find(ifdev, &ifr.ifr_addr, &num)) != OK)
return r;
switch (request) {
case SIOCGIFADDR_IN6:
/* This IOCTL basically checks if the given address exists. */
ifaddr_v6_get(ifdev, num, &ifr.ifr_addr, NULL, NULL);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCDIFADDR_IN6:
ifaddr_v6_del(ifdev, num);
return OK;
case SIOCGIFNETMASK_IN6:
ifaddr_v6_get(ifdev, num, NULL, &ifr.ifr_addr, NULL);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCGIFAFLAG_IN6:
ifr.ifr_ifru.ifru_flags6 = ifaddr_v6_get_flags(ifdev, num);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
case SIOCGIFALIFETIME_IN6:
ifaddr_v6_get_lifetime(ifdev, num,
&ifr.ifr_ifru.ifru_lifetime);
return sockdriver_copyout(data, 0, &ifr, sizeof(ifr));
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET6 with an "in6_aliasreq" structure.
*/
static int
ifconf_ioctl_v6_ifalias(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct in6_aliasreq ifra;
int r;
if ((r = sockdriver_copyin(data, 0, &ifra, sizeof(ifra))) != OK)
return r;
ifra.ifra_name[sizeof(ifra.ifra_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ifra.ifra_name)) == NULL)
return ENXIO;
switch (request) {
case SIOCAIFADDR_IN6:
return ifaddr_v6_add(ifdev, &ifra.ifra_addr,
&ifra.ifra_prefixmask, &ifra.ifra_dstaddr,
ifra.ifra_flags, &ifra.ifra_lifetime);
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET6 with an "in6_ndireq" structure.
*/
static int
ifconf_ioctl_v6_ndireq(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct in6_ndireq ndi;
int r;
if ((r = sockdriver_copyin(data, 0, &ndi, sizeof(ndi))) != OK)
return r;
ndi.ifname[sizeof(ndi.ifname) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(ndi.ifname)) == NULL)
return ENXIO;
switch (request) {
case SIOCGIFINFO_IN6:
memset(&ndi.ndi, 0, sizeof(ndi.ndi));
ndi.ndi.linkmtu = ifdev_get_mtu(ifdev);
ndi.ndi.flags = ifdev_get_nd6flags(ifdev);
ndi.ndi.initialized = 1;
/* TODO: all the other fields.. */
return sockdriver_copyout(data, 0, &ndi, sizeof(ndi));
case SIOCSIFINFO_IN6:
/* TODO: all the other fields.. */
/* FALLTHROUGH */
case SIOCSIFINFO_FLAGS:
return ifdev_set_nd6flags(ifdev, ndi.ndi.flags);
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET6 with an "in6_nbrinfo" structure.
*/
static int
ifconf_ioctl_v6_nbrinfo(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct sockaddr_in6 addr;
struct in6_nbrinfo nbri;
lldata_ndp_num_t num;
int r;
if ((r = sockdriver_copyin(data, 0, &nbri, sizeof(nbri))) != OK)
return r;
nbri.ifname[sizeof(nbri.ifname) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(nbri.ifname)) == NULL)
return ENXIO;
switch (request) {
case SIOCGNBRINFO_IN6:
/*
* Convert the given in6_addr to a full sockaddr_in6, mainly
* for internal consistency. It would have been nice if the
* KAME management API had had any sort of consistency itself.
*/
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
memcpy(&addr.sin6_addr.s6_addr, &nbri.addr,
sizeof(addr.sin6_addr.s6_addr));
if ((r = lldata_ndp_find(ifdev, &addr, &num)) != OK)
return r;
lldata_ndp_get_info(num, &nbri.asked, &nbri.isrouter,
&nbri.state, &nbri.expire);
return sockdriver_copyout(data, 0, &nbri, sizeof(nbri));
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_INET6.
*/
static int
ifconf_ioctl_v6(unsigned long request, const struct sockdriver_data * data,
endpoint_t user_endpt)
{
switch (request) {
case SIOCDIFADDR_IN6:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFADDR_IN6:
case SIOCGIFNETMASK_IN6:
case SIOCGIFAFLAG_IN6:
case SIOCGIFALIFETIME_IN6:
return ifconf_ioctl_v6_ifreq(request, data);
case SIOCAIFADDR_IN6:
if (!util_is_root(user_endpt))
return EPERM;
return ifconf_ioctl_v6_ifalias(request, data);
case SIOCSIFINFO_IN6:
case SIOCSIFINFO_FLAGS:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFINFO_IN6:
return ifconf_ioctl_v6_ndireq(request, data);
case SIOCGNBRINFO_IN6:
return ifconf_ioctl_v6_nbrinfo(request, data);
default:
return ENOTTY;
}
}
#endif /* INET6 */
/*
* Process an IOCTL request for AF_LINK with an "if_laddrreq" structure.
*/
static int
ifconf_ioctl_dl_lifaddr(unsigned long request,
const struct sockdriver_data * data)
{
struct ifdev *ifdev;
struct if_laddrreq iflr;
ifaddr_dl_num_t num;
int r;
if ((r = sockdriver_copyin(data, 0, &iflr, sizeof(iflr))) != OK)
return r;
iflr.iflr_name[sizeof(iflr.iflr_name) - 1] = '\0';
if ((ifdev = ifdev_find_by_name(iflr.iflr_name)) == NULL)
return ENXIO;
switch (request) {
case SIOCGLIFADDR:
if (iflr.flags & IFLR_PREFIX) {
/* We ignore the prefix length, like NetBSD does. */
if ((r = ifaddr_dl_find(ifdev,
(struct sockaddr_dlx *)&iflr.addr,
sizeof(iflr.addr), &num)) != OK)
return r;
} else
num = (ifaddr_dl_num_t)0; /* this always works */
ifaddr_dl_get(ifdev, num, (struct sockaddr_dlx *)&iflr.addr);
iflr.flags = ifaddr_dl_get_flags(ifdev, num);
memset(&iflr.dstaddr, 0, sizeof(iflr.dstaddr));
return sockdriver_copyout(data, 0, &iflr, sizeof(iflr));
case SIOCALIFADDR:
return ifaddr_dl_add(ifdev, (struct sockaddr_dlx *)&iflr.addr,
sizeof(iflr.addr), iflr.flags);
case SIOCDLIFADDR:
if ((r = ifaddr_dl_find(ifdev,
(struct sockaddr_dlx *)&iflr.addr, sizeof(iflr.addr),
&num)) != OK)
return r;
return ifaddr_dl_del(ifdev, num);
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request for AF_LINK.
*/
static int
ifconf_ioctl_dl(unsigned long request, const struct sockdriver_data * data,
endpoint_t user_endpt)
{
switch (request) {
case SIOCALIFADDR:
case SIOCDLIFADDR:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGLIFADDR:
return ifconf_ioctl_dl_lifaddr(request, data);
default:
return ENOTTY;
}
}
/*
* Process an IOCTL request. This routine is shared between TCP, UDP, RAW, and
* link sockets. The given socket may be used to obtain the target domain:
* AF_INET, AF_INET6, or AF_LINK.
*/
int
ifconf_ioctl(struct sock * sock, unsigned long request,
const struct sockdriver_data * data, endpoint_t user_endpt)
{
int domain;
domain = sockevent_get_domain(sock);
switch (request) {
case SIOCSIFFLAGS:
case SIOCSIFMETRIC:
case SIOCSIFMEDIA:
case SIOCSIFMTU:
case SIOCIFCREATE:
case SIOCIFDESTROY:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFFLAGS:
case SIOCGIFMETRIC:
case SIOCGIFMTU:
case SIOCGIFDLT:
case SIOCGIFINDEX:
return ifconf_ioctl_ifreq(request, data);
case SIOCSIFCAP:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFCAP:
return ifconf_ioctl_ifcap(request, data);
case MINIX_SIOCGIFMEDIA:
return ifconf_ioctl_ifmedia(request, data);
case MINIX_SIOCIFGCLONERS:
return ifconf_ioctl_ifclone(request, data);
case SIOCSIFADDRPREF:
if (!util_is_root(user_endpt))
return EPERM;
/* FALLTHROUGH */
case SIOCGIFADDRPREF:
return ifconf_ioctl_ifaddrpref(request, data);
default:
switch (domain) {
case AF_INET:
return ifconf_ioctl_v4(request, data, user_endpt);
#ifdef INET6
case AF_INET6:
return ifconf_ioctl_v6(request, data, user_endpt);
#endif /* INET6 */
case AF_LINK:
return ifconf_ioctl_dl(request, data, user_endpt);
default:
return ENOTTY;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,155 +0,0 @@
#ifndef MINIX_NET_LWIP_IFDEV_H
#define MINIX_NET_LWIP_IFDEV_H
#include <net/if.h>
#include <net/if_types.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
/*
* NetBSD makes setting a hardware address through ifconfig(8) a whole lot
* harder than it needs to be, namely by keeping a list of possible hardware
* addresses and marking one of them as active. For us, that level of extra
* flexibility is completely useless. In order to shield individual interface
* modules from having to deal with the rather extended interface for the list
* management, we maintain the list in ifdev and simply use a iop_set_hwaddr()
* call to the modules when the active address changes. This setting is the
* maximum number of hardware addresses in the list maintained by ifdev. It
* should be at least 2, or changing hardware addresses will not be possible.
*/
#define IFDEV_NUM_HWADDRS 3
struct ifdev;
struct bpfdev_link;
struct sockaddr_dlx;
/* Interface operations table. */
struct ifdev_ops {
err_t (* iop_init)(struct ifdev * ifdev, struct netif * netif);
err_t (* iop_input)(struct pbuf * pbuf, struct netif * netif);
err_t (* iop_output)(struct ifdev * ifdev, struct pbuf * pbuf,
struct netif * netif);
err_t (* iop_output_v4)(struct netif * netif, struct pbuf * pbuf,
const ip4_addr_t * ipaddr);
err_t (* iop_output_v6)(struct netif * netif, struct pbuf * pbuf,
const ip6_addr_t * ipaddr);
void (* iop_hdrcmplt)(struct ifdev * ifdev, struct pbuf * pbuf);
void (* iop_poll)(struct ifdev * ifdev);
int (* iop_set_ifflags)(struct ifdev * ifdev, unsigned int ifflags);
void (* iop_get_ifcap)(struct ifdev * ifdev, uint64_t * ifcap,
uint64_t * ifena);
int (* iop_set_ifcap)(struct ifdev * ifdev, uint64_t ifcap);
void (* iop_get_ifmedia)(struct ifdev * ifdev, int * ifcurrent,
int * ifactive);
int (* iop_set_ifmedia)(struct ifdev * ifdev, int ifmedia);
void (* iop_set_promisc)(struct ifdev * ifdev, int promisc);
int (* iop_set_hwaddr)(struct ifdev * ifdev, const uint8_t * hwaddr);
int (* iop_set_mtu)(struct ifdev * ifdev, unsigned int mtu);
int (* iop_destroy)(struct ifdev * ifdev);
};
/* Hardware address list entry. The first entry, if any, is the active one. */
struct ifdev_hwaddr {
uint8_t ifhwa_addr[NETIF_MAX_HWADDR_LEN];
uint8_t ifhwa_flags;
};
#define IFHWAF_VALID 0x01 /* entry contains an address */
#define IFHWAF_FACTORY 0x02 /* factory (device-given) address */
/* Interface structure. */
struct ifdev {
TAILQ_ENTRY(ifdev) ifdev_next; /* list of active interfaces */
char ifdev_name[IFNAMSIZ]; /* interface name, null terminated */
unsigned int ifdev_ifflags; /* NetBSD-style interface flags */
unsigned int ifdev_dlt; /* data link type (DLT_) */
unsigned int ifdev_promisc; /* number of promiscuity requestors */
struct netif ifdev_netif; /* lwIP interface structure */
struct if_data ifdev_data; /* NetBSD-style interface data */
char ifdev_v4set; /* interface has an IPv4 address? */
uint8_t ifdev_v6prefix[LWIP_IPV6_NUM_ADDRESSES]; /* IPv6 prefixes */
uint8_t ifdev_v6flags[LWIP_IPV6_NUM_ADDRESSES]; /* v6 address flags */
uint8_t ifdev_v6state[LWIP_IPV6_NUM_ADDRESSES]; /* v6 shadow states */
uint8_t ifdev_v6scope[LWIP_IPV6_NUM_ADDRESSES]; /* cached v6 scopes */
struct ifdev_hwaddr ifdev_hwlist[IFDEV_NUM_HWADDRS]; /* HW addr's */
uint32_t ifdev_nd6flags; /* ND6-related flags (ND6_IFF_) */
const struct ifdev_ops *ifdev_ops; /* interface operations table */
TAILQ_HEAD(, bpfdev_link) ifdev_bpf; /* list of attached BPF devices */
};
#define ifdev_get_name(ifdev) ((ifdev)->ifdev_name)
#define ifdev_get_ifflags(ifdev) ((ifdev)->ifdev_ifflags)
#define ifdev_get_dlt(ifdev) ((ifdev)->ifdev_dlt)
#define ifdev_is_promisc(ifdev) ((ifdev)->ifdev_promisc != 0)
#define ifdev_get_netif(ifdev) (&(ifdev)->ifdev_netif)
#define ifdev_get_nd6flags(ifdev) ((ifdev)->ifdev_nd6flags)
#define ifdev_get_iftype(ifdev) ((ifdev)->ifdev_data.ifi_type)
#define ifdev_get_hwlen(ifdev) ((ifdev)->ifdev_data.ifi_addrlen)
#define ifdev_get_hdrlen(ifdev) ((ifdev)->ifdev_data.ifi_hdrlen)
#define ifdev_get_link(ifdev) ((ifdev)->ifdev_data.ifi_link_state)
#define ifdev_get_mtu(ifdev) ((ifdev)->ifdev_data.ifi_mtu)
#define ifdev_get_metric(ifdev) ((ifdev)->ifdev_data.ifi_metric)
#define ifdev_get_ifdata(ifdev) (&(ifdev)->ifdev_data)
#define ifdev_is_loopback(ifdev) ((ifdev)->ifdev_ifflags & IFF_LOOPBACK)
#define ifdev_is_up(ifdev) ((ifdev)->ifdev_ifflags & IFF_UP)
#define ifdev_is_link_up(ifdev) (netif_is_link_up(&(ifdev)->ifdev_netif))
#define ifdev_set_metric(ifdev, metric) \
((void)((ifdev)->ifdev_data.ifi_metric = (metric)))
#define ifdev_get_index(ifdev) \
((uint32_t)(netif_get_index(ifdev_get_netif(ifdev))))
#define ifdev_output_drop(ifdev) ((ifdev)->ifdev_data.ifi_oerrors++)
#define netif_get_ifdev(netif) ((struct ifdev *)(netif)->state)
void ifdev_init(void);
void ifdev_poll(void);
void ifdev_register(const char * name, int (* create)(const char *));
void ifdev_input(struct ifdev * ifdev, struct pbuf * pbuf,
struct netif * netif, int to_bpf);
err_t ifdev_output(struct ifdev * ifdev, struct pbuf * pbuf,
struct netif * netif, int to_bpf, int hdrcmplt);
void ifdev_attach_bpf(struct ifdev * ifdev, struct bpfdev_link * bpfl);
void ifdev_detach_bpf(struct ifdev * ifdev, struct bpfdev_link * bpfl);
struct ifdev *ifdev_get_by_index(uint32_t ifindex);
struct ifdev *ifdev_find_by_name(const char * name);
struct ifdev *ifdev_enum(struct ifdev * last);
int ifdev_check_name(const char * name, unsigned int * vtype_slot);
int ifdev_set_promisc(struct ifdev * ifdev);
void ifdev_clear_promisc(struct ifdev * ifdev);
int ifdev_set_ifflags(struct ifdev * ifdev, unsigned int ifflags);
void ifdev_update_ifflags(struct ifdev * ifdev, unsigned int ifflags);
void ifdev_get_ifcap(struct ifdev * ifdev, uint64_t * ifcap,
uint64_t * ifena);
int ifdev_set_ifcap(struct ifdev * ifdev, uint64_t ifena);
int ifdev_get_ifmedia(struct ifdev * ifdev, int * ifcurrent, int * ifactive);
int ifdev_set_ifmedia(struct ifdev * ifdev, int ifmedia);
int ifdev_set_mtu(struct ifdev * ifdev, unsigned int mtu);
int ifdev_set_nd6flags(struct ifdev * ifdev, uint32_t nd6flags);
void ifdev_add(struct ifdev * ifdev, const char * name, unsigned int ifflags,
unsigned int iftype, size_t hdrlen, size_t addrlen, unsigned int dlt,
unsigned int mtu, uint32_t nd6flags, const struct ifdev_ops * iop);
int ifdev_remove(struct ifdev * ifdev);
struct ifdev *ifdev_get_loopback(void);
void ifdev_update_link(struct ifdev * ifdev, int link);
void ifdev_update_hwaddr(struct ifdev * ifdev, const uint8_t * hwaddr,
int is_factory);
int ifdev_create(const char * name);
int ifdev_destroy(struct ifdev * ifdev);
const char *ifdev_enum_vtypes(unsigned int num);
#endif /* !MINIX_NET_LWIP_IFDEV_H */

View File

@ -1,584 +0,0 @@
/* LWIP service - lldata.c - link-layer (ARP, NDP) data related routines */
/*
* This module is largely isolated from the regular routing code. There are
* two reasons for that. First, mixing link-layer routes with regular routes
* would not work well due to the fact that lwIP keeps these data structures
* entirely separate. Second, as of version 8, NetBSD keeps the IP-layer and
* link-layer routing separate as well.
*
* Unfortunately, lwIP does not provide much in the way of implementing the
* functionality that would be expected for this module. As such, the current
* implementation is very restricted and simple.
*
* For ARP table entries, lwIP only allows for adding and deleting static
* entries. Non-static entries cannot be deleted. Incomplete (pending)
* entries cannot even be enumerated, nor can (e.g.) expiry information be
* obtained. The lwIP ARP datastructures are completely hidden, so there is no
* way to overcome these limitations without changing lwIP itself. As a
* result, not all functionality of the arp(8) userland utility is supported.
*
* For NDP table entries, lwIP offers no API at all. However, since the data
* structures are exposed directly, we can use those to implement full support
* for exposing information in a read-only way. However, manipulating data
* structures directly from here is too risky, nor does lwIP currently support
* the concept of static NDP table entries. Therefore, adding, changing, and
* deleting NDP entries is currently not supported, and will also first require
* changes to lwIP itself.
*
* The ndp(8) userland utility is also able to show and manipulate various
* other neighbor discovery related tables and settings. We support only a
* small subset of them. The main reason for this is that the other tables,
* in particular the prefix and default router lists, are not relevant: on
* MINIX 3, these are always managed fully in userland (usually dhcpcd(8)), and
* we even hardcode lwIP not to parse Router Advertisement messages at all, so
* even though those tables are still part of lwIP, they are always empty.
* Other ndp(8) functionality are unsupported for similar reasons.
*/
#include "lwip.h"
#include "lldata.h"
#include "route.h"
#include "rtsock.h"
#include "lwip/etharp.h"
#include "lwip/nd6.h"
#include "lwip/priv/nd6_priv.h" /* for neighbor_cache */
/*
* Process a routing command specifically for an ARP table entry. Return OK if
* the routing command has been processed successfully and a routing socket
* reply message has already been generated. Return a negative error code on
* failure, in which case the caller will generate a reply message instead.
*/
static int
lldata_arp_process(unsigned int type, const ip_addr_t * dst_addr,
const struct eth_addr * gw_addr, struct ifdev * ifdev,
unsigned int flags, const struct rtsock_request * rtr)
{
const ip4_addr_t *ip4addr;
struct eth_addr ethaddr, *ethptr;
struct netif *netif;
lldata_arp_num_t num;
err_t err;
netif = (ifdev != NULL) ? ifdev_get_netif(ifdev) : NULL;
num = etharp_find_addr(netif, ip_2_ip4(dst_addr), &ethptr, &ip4addr);
if (type != RTM_ADD && num < 0)
return ESRCH;
else if (type == RTM_ADD && num >= 0)
return EEXIST;
switch (type) {
case RTM_CHANGE:
/*
* This request is not used by arp(8), so keep things simple.
* For RTM_ADD we support only static entries; we support only
* those too here, and thus we can use delete-and-readd. If
* the ethernet address is not being changed, try readding the
* entry with the previous ethernet address.
*/
if (gw_addr == NULL)
gw_addr = ethptr;
if (etharp_remove_static_entry(ip_2_ip4(dst_addr)) != ERR_OK)
return EPERM;
/* FALLTHROUGH */
case RTM_ADD:
assert(gw_addr != NULL);
memcpy(&ethaddr, gw_addr, sizeof(ethaddr));
/*
* Adding static, permanent, unpublished, non-proxy entries is
* all that lwIP supports right now. We also do not get to
* specify the interface, and the way lwIP picks the interface
* may in fact result in a different one.
*/
if ((err = etharp_add_static_entry(ip_2_ip4(dst_addr),
&ethaddr)) != ERR_OK)
return util_convert_err(err);
if ((num = etharp_find_addr(NULL /*netif*/, ip_2_ip4(dst_addr),
&ethptr, &ip4addr)) < 0)
panic("unable to find just-added static ARP entry");
/* FALLTHROUGH */
case RTM_LOCK:
case RTM_GET:
rtsock_msg_arp(num, type, rtr);
return OK;
case RTM_DELETE:
memcpy(&ethaddr, ethptr, sizeof(ethaddr));
if (etharp_remove_static_entry(ip_2_ip4(dst_addr)) != ERR_OK)
return EPERM;
/*
* FIXME: the following block is a hack, because we cannot
* predict whether the above removal will succeed, while at the
* same time we need the entry to be present in order to report
* the deleted address to the routing socket. We temporarily
* readd and then remove the entry just for the purpose of
* generating the routing socket reply. There are other ways
* to resolve this, but only a better lwIP etharp API would
* allow us to resolve this problem cleanly.
*/
(void)etharp_add_static_entry(ip_2_ip4(dst_addr), &ethaddr);
num = etharp_find_addr(NULL /*netif*/, ip_2_ip4(dst_addr),
&ethptr, &ip4addr);
assert(num >= 0);
rtsock_msg_arp(num, type, rtr);
(void)etharp_remove_static_entry(ip_2_ip4(dst_addr));
return OK;
default:
return EINVAL;
}
}
/*
* Enumerate ARP table entries. Return TRUE if there is at least one more ARP
* table entry, of which the number is stored in 'num'. The caller should set
* 'num' to 0 initially, and increase it by one between a successful call and
* the next call. Return FALSE if there are no more ARP table entries.
*/
int
lldata_arp_enum(lldata_arp_num_t * num)
{
ip4_addr_t *ip4addr;
struct netif *netif;
struct eth_addr *ethaddr;
for (; *num < ARP_TABLE_SIZE; ++*num) {
if (etharp_get_entry(*num, &ip4addr, &netif, &ethaddr))
return TRUE;
}
return FALSE;
}
/*
* Obtain information about the ARP table entry identified by 'num'. The IPv4
* address of the entry is stored in 'addr'. Its ethernet address is stored in
* 'gateway'. The associated interface is stored in 'ifdevp', and the entry's
* routing flags (RTF_) are stored in 'flagsp'.
*/
void
lldata_arp_get(lldata_arp_num_t num, struct sockaddr_in * addr,
struct sockaddr_dlx * gateway, struct ifdev ** ifdevp,
unsigned int * flagsp)
{
ip_addr_t ipaddr;
ip4_addr_t *ip4addr;
struct netif *netif;
struct ifdev *ifdev;
struct eth_addr *ethaddr;
socklen_t addr_len;
if (!etharp_get_entry(num, &ip4addr, &netif, &ethaddr))
panic("request for invalid ARP entry");
ip_addr_copy_from_ip4(ipaddr, *ip4addr);
assert(netif != NULL);
ifdev = netif_get_ifdev(netif);
addr_len = sizeof(*addr);
addr_put_inet((struct sockaddr *)addr, &addr_len, &ipaddr,
TRUE /*kame*/, 0 /*port*/);
addr_len = sizeof(*gateway);
addr_put_link((struct sockaddr *)gateway, &addr_len,
ifdev_get_index(ifdev), ifdev_get_iftype(ifdev), NULL /*name*/,
ethaddr->addr, sizeof(ethaddr->addr));
*ifdevp = ifdev;
/*
* TODO: this is not necessarily accurate, but lwIP does not provide us
* with information as to whether this is a static entry or not..
*/
*flagsp = RTF_HOST | RTF_LLINFO | RTF_LLDATA | RTF_STATIC | RTF_CLONED;
}
/*
* Obtain information about the ND6 neighbor cache entry 'i', which must be a
* number between 0 (inclusive) and LWIP_ND6_NUM_NEIGHBORS (exclusive). If an
* entry with this number exists, return a pointer to its IPv6 address, and
* additional information in each of the given pointers if not NULL. The
* associated interface is stored in 'netif'. If the entry has an associated
* link-layer address, a pointer to it is stored in 'lladdr'. The entry's
* state (ND6_{INCOMPLETE,REACHABLE,STALE,DELAY,PROBE}) is stored in 'state'.
* The 'isrouter' parameter is filled with a boolean value indicating whether
* the entry is for a router. For ND6_INCOMPLETE and ND6_PROBE, the number of
* probes sent so far is stored in 'probes_sent'; for other states, the value
* is set to zero. For ND6_REACHABLE and ND6_DELAY, the time until expiration
* in ND6_TMR_INTERVAL-millisecond units is stored in 'expire_time'; for other
* states, the value is set to zero. If an entry with number 'i' does not
* exist, NULL is returned.
*
* TODO: upstream this function to lwIP.
*/
static const ip6_addr_t *
nd6_get_neighbor_cache_entry(int8_t i, struct netif ** netif,
const uint8_t ** lladdr, uint8_t * state, uint8_t * isrouter,
uint32_t * probes_sent, uint32_t * expire_time)
{
if (i < 0 || i >= LWIP_ND6_NUM_NEIGHBORS ||
neighbor_cache[i].state == ND6_NO_ENTRY)
return NULL;
if (netif != NULL)
*netif = neighbor_cache[i].netif;
if (lladdr != NULL) {
if (neighbor_cache[i].state != ND6_INCOMPLETE)
*lladdr = neighbor_cache[i].lladdr;
else
*lladdr = NULL;
}
if (state != NULL)
*state = neighbor_cache[i].state;
if (isrouter != NULL)
*isrouter = neighbor_cache[i].isrouter;
if (probes_sent != NULL) {
if (neighbor_cache[i].state == ND6_INCOMPLETE ||
neighbor_cache[i].state == ND6_PROBE)
*probes_sent = neighbor_cache[i].counter.probes_sent;
else
*probes_sent = 0;
}
if (expire_time != NULL) {
switch (neighbor_cache[i].state) {
case ND6_REACHABLE:
*expire_time =
neighbor_cache[i].counter.reachable_time /
ND6_TMR_INTERVAL;
break;
case ND6_DELAY:
*expire_time = neighbor_cache[i].counter.delay_time;
break;
case ND6_INCOMPLETE:
case ND6_PROBE:
/* Probes are sent once per timer tick. */
*expire_time = (LWIP_ND6_MAX_MULTICAST_SOLICIT + 1 -
neighbor_cache[i].counter.probes_sent) *
(ND6_TMR_INTERVAL / 1000);
break;
default:
/* Stale entries do not expire; they get replaced. */
*expire_time = 0;
break;
}
}
return &neighbor_cache[i].next_hop_address;
}
/*
* Find a neighbor cache entry by IPv6 address. Return its index number if
* found, or -1 if not. This is a reimplementation of the exact same function
* internal to lwIP.
*
* TODO: make this function public in lwIP.
*/
static int8_t
nd6_find_neighbor_cache_entry(const ip6_addr_t * addr)
{
int8_t i;
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
if (ip6_addr_cmp(addr, &neighbor_cache[i].next_hop_address))
return i;
}
return -1;
}
/*
* Find an NDP table entry based on the given interface and IPv6 address. On
* success, return OK, with the entry's index number stored in 'nump'. On
* failure, return an appropriate error code.
*/
int
lldata_ndp_find(struct ifdev * ifdev, const struct sockaddr_in6 * addr,
lldata_ndp_num_t * nump)
{
ip_addr_t ipaddr;
int8_t i;
int r;
if ((r = addr_get_inet((const struct sockaddr *)addr, sizeof(*addr),
IPADDR_TYPE_V6, &ipaddr, TRUE /*kame*/, NULL /*port*/)) != OK)
return r;
/*
* For given link-local addresses, no zone may be provided in the
* address at all. In such cases, add the zone ourselves, using the
* given interface.
*/
if (ip6_addr_lacks_zone(ip_2_ip6(&ipaddr), IP6_UNKNOWN))
ip6_addr_assign_zone(ip_2_ip6(&ipaddr), IP6_UNKNOWN,
ifdev_get_netif(ifdev));
i = nd6_find_neighbor_cache_entry(ip_2_ip6(&ipaddr));
if (i < 0)
return ESRCH;
/*
* We should compare the neighbor cache entry's associated netif to
* the given ifdev, but since the lwIP neighbor cache is currently not
* keyed by netif anyway (i.e. the internal lookups are purely by IPv6
* address as well), doing so makes little sense in practice.
*/
*nump = (lldata_ndp_num_t)i;
return OK;
}
/*
* Process a routing command specifically for an NDP table entry. Return OK if
* the routing command has been processed successfully and a routing socket
* reply message has already been generated. Return a negative error code on
* failure, in which case the caller will generate a reply message instead.
*/
static int
lldata_ndp_process(unsigned int type, const ip_addr_t * dst_addr,
const struct eth_addr * gw_addr,
struct ifdev * ifdev, unsigned int flags,
const struct rtsock_request * rtr)
{
lldata_ndp_num_t num;
num = (lldata_ndp_num_t)
nd6_find_neighbor_cache_entry(ip_2_ip6(dst_addr));
if (type != RTM_ADD && num < 0)
return ESRCH;
else if (type == RTM_ADD && num >= 0)
return EEXIST;
switch (type) {
case RTM_LOCK:
case RTM_GET:
rtsock_msg_arp(num, type, rtr);
return OK;
case RTM_ADD:
case RTM_CHANGE:
case RTM_DELETE:
/* TODO: add lwIP support to implement these commands. */
return ENOSYS;
default:
return EINVAL;
}
}
/*
* Enumerate NDP table entries. Return TRUE if there is at least one more NDP
* table entry, of which the number is stored in 'num'. The caller should set
* 'num' to 0 initially, and increase it by one between a successful call and
* the next call. Return FALSE if there are no more NDP table entries.
*/
int
lldata_ndp_enum(lldata_ndp_num_t * num)
{
for (; *num < LWIP_ND6_NUM_NEIGHBORS; ++*num) {
if (nd6_get_neighbor_cache_entry(*num, NULL /*netif*/,
NULL /*lladdr*/, NULL /*state*/, NULL /*isrouter*/,
NULL /*probes_sent*/, NULL /*expire_time*/) != NULL)
return TRUE;
}
return FALSE;
}
/*
* Obtain information about the NDP table entry identified by 'num'. The IPv6
* address of the entry is stored in 'addr'. Its ethernet address is stored in
* 'gateway'. The associated interface is stored in 'ifdevp', and the entry's
* routing flags (RTF_) are stored in 'flagsp'.
*/
void
lldata_ndp_get(lldata_ndp_num_t num, struct sockaddr_in6 * addr,
struct sockaddr_dlx * gateway, struct ifdev ** ifdevp,
unsigned int * flagsp)
{
const ip6_addr_t *ip6addr;
ip_addr_t ipaddr;
struct netif *netif = NULL /*gcc*/;
struct ifdev *ifdev;
const uint8_t *lladdr = NULL /*gcc*/;
socklen_t addr_len;
ip6addr = nd6_get_neighbor_cache_entry(num, &netif, &lladdr,
NULL /*state*/, NULL /*isrouter*/, NULL /*probes_sent*/,
NULL /*expire_time*/);
assert(ip6addr != NULL);
ip_addr_copy_from_ip6(ipaddr, *ip6addr);
ifdev = netif_get_ifdev(netif);
assert(ifdev != NULL);
addr_len = sizeof(*addr);
addr_put_inet((struct sockaddr *)addr, &addr_len, &ipaddr,
TRUE /*kame*/, 0 /*port*/);
addr_len = sizeof(*gateway);
addr_put_link((struct sockaddr *)gateway, &addr_len,
ifdev_get_index(ifdev), ifdev_get_iftype(ifdev), NULL /*name*/,
lladdr, ifdev_get_hwlen(ifdev));
*ifdevp = ifdev;
*flagsp = RTF_HOST | RTF_LLINFO | RTF_LLDATA | RTF_CLONED;
}
/*
* Obtain information about the NDP table entry with the number 'num', which
* must be obtained through a previous call to lldata_ndp_find(). On return,
* 'asked' is filled with the number of probes sent so far (0 if inapplicable),
* 'isrouter' is set to 1 or 0 depending on whether the entry is for a router,
* 'state' is set to the entry's state (ND6_LLINFO_), and 'expire' is set to
* either the UNIX timestamp of expiry for the entry; 0 for permanent entries.
* None of the given pointers must be NULL. This function always succeeds.
*/
void
lldata_ndp_get_info(lldata_ndp_num_t num, long * asked, int * isrouter,
int * state, int * expire)
{
uint32_t nd6_probes_sent = 0 /*gcc*/, nd6_expire_time = 0 /*gcc*/;
uint8_t nd6_state = 0 /*gcc*/, nd6_isrouter = 0 /*gcc*/;
(void)nd6_get_neighbor_cache_entry(num, NULL /*netif*/,
NULL /*lladdr*/, &nd6_state, &nd6_isrouter, &nd6_probes_sent,
&nd6_expire_time);
*asked = (long)nd6_probes_sent;
*isrouter = !!nd6_isrouter;
switch (nd6_state) {
case ND6_INCOMPLETE: *state = ND6_LLINFO_INCOMPLETE; break;
case ND6_REACHABLE: *state = ND6_LLINFO_REACHABLE; break;
case ND6_STALE: *state = ND6_LLINFO_STALE; break;
case ND6_DELAY: *state = ND6_LLINFO_DELAY; break;
case ND6_PROBE: *state = ND6_LLINFO_PROBE; break;
default: panic("unknown ND6 state %u", nd6_state);
}
if (nd6_expire_time != 0)
*expire = clock_time(NULL) +
(int)nd6_expire_time * (ND6_TMR_INTERVAL / 1000);
else
*expire = 0;
}
/*
* Process a routing command specifically for a link-layer route, as one of the
* specific continuations of processing started by route_process(). The RTM_
* routing command is given as 'type'. The route destination is given as
* 'dst_addr'; its address type determines whether the operation is for ARP or
* NDP. The sockaddr structure for 'gateway' is passed on as is and may have
* to be parsed here if not NULL. 'ifdev' is the interface to be associated
* with the route; it is non-NULL only if an interface name (IFP) or address
* (IFA) was given. The RTF_ flags field has been checked against the globally
* supported flags, but may have to be checked for flags that do not apply to
* ARP/NDP routes. Return OK or a negative error code, following the same
* semantics as route_process().
*/
int
lldata_process(unsigned int type, const ip_addr_t * dst_addr,
const struct sockaddr * gateway, struct ifdev * ifdev,
unsigned int flags, const struct rtsock_request * rtr)
{
const struct route_entry *route;
struct eth_addr ethaddr, *gw_addr;
int r;
assert(flags & RTF_LLDATA);
/*
* It seems that RTF_UP does not apply to link-layer routing entries.
* We basically accept any flags that we can return, but we do not
* actually check most of them anywhere.
*/
if ((flags & ~(RTF_HOST | RTF_LLINFO | RTF_LLDATA | RTF_STATIC |
RTF_CLONED | RTF_ANNOUNCE)) != 0)
return EINVAL;
gw_addr = NULL;
if (type == RTM_ADD || type == RTM_CHANGE) {
/*
* Link-layer entries are always host entries. Not all
* requests pass in this flag though, so check only when the
* flags are supposed to be set.
*/
if ((type == RTM_ADD || type == RTM_CHANGE) &&
!(flags & RTF_HOST))
return EINVAL;
/* lwIP does not support publishing custom entries. */
if (flags & RTF_ANNOUNCE)
return ENOSYS;
/* RTF_GATEWAY is always cleared for link-layer entries. */
if (gateway != NULL) {
if ((r = addr_get_link(gateway, gateway->sa_len,
NULL /*name*/, 0 /*name_max*/, ethaddr.addr,
sizeof(ethaddr.addr))) != OK)
return r;
gw_addr = &ethaddr;
}
if (type == RTM_ADD) {
if (gateway == NULL)
return EINVAL;
/*
* If no interface has been specified, see if the
* destination address is on a locally connected
* network. If so, use that network's interface.
* Otherwise reject the request altogether: we must
* have an interface to which to associate the entry.
*/
if (ifdev == NULL) {
if ((route = route_lookup(dst_addr)) != NULL &&
!(route_get_flags(route) & RTF_GATEWAY))
ifdev = route_get_ifdev(route);
else
return ENETUNREACH;
}
}
}
if (IP_IS_V4(dst_addr))
return lldata_arp_process(type, dst_addr, gw_addr, ifdev,
flags, rtr);
else
return lldata_ndp_process(type, dst_addr, gw_addr, ifdev,
flags, rtr);
}

View File

@ -1,420 +0,0 @@
/* LWIP service - loopif.c - loopback interfaces */
/*
* There is always at least one loopback device. This device is used also to
* loop back packets sent on other interfaces to the local interface address.
* Therefore, not all packets on the loopback device have a source or
* destination address corresponding to the loopback device.
*/
#include "lwip.h"
/*
* As a safety measure, if lwIP somehow gets stuck in a loop replying to its
* own packets on a loopback interface, stop with immediately feeding packets
* back into lwIP after this many packets. The remaining packets will still be
* delivered, but not before the main message loop has had a chance to run.
*/
#define LOOPIF_LIMIT 65536
/*
* The MTU is restricted to 65531 bytes, because we need space for a 4-byte
* header to identify the original interface of the packet.
*/
#define LOOPIF_MAX_MTU (UINT16_MAX - sizeof(uint32_t)) /* maximum MTU */
#define LOOPIF_DEF_MTU LOOPIF_MAX_MTU /* default MTU */
#define NR_LOOPIF 2 /* number of loopback devices */
struct loopif {
struct ifdev loopif_ifdev; /* interface device, MUST be first */
struct pbuf *loopif_head; /* head of pending loopback packets */
struct pbuf **loopif_tailp; /* tail ptr-ptr of pending packets */
TAILQ_ENTRY(loopif) loopif_next; /* next in free list */
} loopif_array[NR_LOOPIF];
static TAILQ_HEAD(, loopif) loopif_freelist; /* free loop interfaces list */
static TAILQ_HEAD(, loopif) loopif_activelist; /* active loop interfaces */
#define loopif_get_netif(loopif) (ifdev_get_netif(&(loopif)->loopif_ifdev))
static unsigned int loopif_cksum_flags;
static int loopif_create(const char *name);
static const struct ifdev_ops loopif_ops;
/*
* Initialize the loopback interface module.
*/
void
loopif_init(void)
{
unsigned int slot;
/* Initialize the lists of loopback interfaces. */
TAILQ_INIT(&loopif_freelist);
TAILQ_INIT(&loopif_activelist);
for (slot = 0; slot < __arraycount(loopif_array); slot++)
TAILQ_INSERT_TAIL(&loopif_freelist, &loopif_array[slot],
loopif_next);
/*
* The default is to perform no checksumming on loopback interfaces,
* except for ICMP messages because otherwise we would need additional
* changes in the code receiving those. In fact, for future
* compatibility, disable only those flags that we manage ourselves.
*/
loopif_cksum_flags = NETIF_CHECKSUM_ENABLE_ALL &
~(NETIF_CHECKSUM_GEN_IP | NETIF_CHECKSUM_CHECK_IP |
NETIF_CHECKSUM_GEN_UDP | NETIF_CHECKSUM_CHECK_UDP |
NETIF_CHECKSUM_GEN_TCP | NETIF_CHECKSUM_CHECK_TCP);
/* Tell the ifdev module that users may create more loopif devices. */
ifdev_register("lo", loopif_create);
}
/*
* Polling function, invoked after each message loop iteration. Forward any
* packets received on the output side of the loopback device during this
* loop iteration, to the input side of the device.
*/
static void
loopif_poll(struct ifdev * ifdev)
{
struct loopif *loopif = (struct loopif *)ifdev;
struct pbuf *pbuf, **pnext;
struct ifdev *oifdev;
struct netif *netif;
uint32_t oifindex;
unsigned int count;
static int warned = FALSE;
count = 0;
while ((pbuf = loopif->loopif_head) != NULL) {
/*
* Prevent endless loops. Keep in mind that packets may be
* added to the queue as part of processing packets from the
* queue here, so the queue itself will never reach this
* length. As such the limit can (and must) be fairly high.
*
* In any case, if this warning is shown, that basically means
* that a bug in lwIP has been triggered. There should be no
* such bugs, so if there are, they should be fixed in lwIP.
*/
if (count++ == LOOPIF_LIMIT) {
if (!warned) {
printf("LWIP: excess loopback traffic, "
"throttling output\n");
warned = TRUE;
}
break;
}
pnext = pchain_end(pbuf);
if ((loopif->loopif_head = *pnext) == NULL)
loopif->loopif_tailp = &loopif->loopif_head;
*pnext = NULL;
/*
* Get the original interface for the packet, which if non-zero
* must also be used to pass the packet back to. The interface
* should still exist in all cases, but better safe than sorry.
*/
memcpy(&oifindex, pbuf->payload, sizeof(oifindex));
util_pbuf_header(pbuf, -(int)sizeof(oifindex));
if (oifindex != 0 &&
(oifdev = ifdev_get_by_index(oifindex)) != NULL)
netif = ifdev_get_netif(oifdev);
else
netif = NULL;
/*
* Loopback devices hand packets to BPF on output only. Doing
* so on input as well would duplicate all captured packets.
*/
ifdev_input(ifdev, pbuf, netif, FALSE /*to_bpf*/);
}
}
/*
* Process a packet as output on a loopback interface. Packets cannot be
* passed back into lwIP right away, nor can the original packets be passed
* back into lwIP. Therefore, make a copy of the packet, and pass it back to
* lwIP at the end of the current message loop iteration.
*/
static err_t
loopif_output(struct ifdev * ifdev, struct pbuf * pbuf, struct netif * netif)
{
struct loopif *loopif = (struct loopif *)ifdev;
struct ifdev *oifdev;
struct pbuf *pcopy;
uint32_t oifindex;
/* Reject oversized packets immediately. This should not happen. */
if (pbuf->tot_len > UINT16_MAX - sizeof(oifindex)) {
printf("LWIP: attempt to send oversized loopback packet\n");
return ERR_MEM;
}
/*
* If the service is low on memory, this is a likely place where
* allocation failures will occur. Thus, do not print anything here.
* The user can diagnose such problems with interface statistics.
*/
pcopy = pchain_alloc(PBUF_RAW, sizeof(oifindex) + pbuf->tot_len);
if (pcopy == NULL) {
ifdev_output_drop(ifdev);
return ERR_MEM;
}
/*
* If the packet was purposely diverted from a non-loopback interface
* to this interface, we have to remember the original interface, so
* that we can pass back the packet to that interface as well. If we
* don't, packets to link-local addresses assigned to non-loopback
* interfaces will not be processed correctly.
*/
if (netif != NULL) {
oifdev = netif_get_ifdev(netif);
oifindex = ifdev_get_index(oifdev);
} else
oifindex = 0;
assert(pcopy->len >= sizeof(oifindex));
memcpy(pcopy->payload, &oifindex, sizeof(oifindex));
util_pbuf_header(pcopy, -(int)sizeof(oifindex));
if (pbuf_copy(pcopy, pbuf) != ERR_OK)
panic("unexpected pbuf copy failure");
pcopy->flags |= pbuf->flags & (PBUF_FLAG_LLMCAST | PBUF_FLAG_LLBCAST);
util_pbuf_header(pcopy, sizeof(oifindex));
*loopif->loopif_tailp = pcopy;
loopif->loopif_tailp = pchain_end(pcopy);
return ERR_OK;
}
/*
* Initialization function for a loopback-type netif interface, called from
* lwIP at interface creation time.
*/
static err_t
loopif_init_netif(struct ifdev * ifdev, struct netif * netif)
{
netif->name[0] = 'l';
netif->name[1] = 'o';
/*
* FIXME: unfortunately, lwIP does not allow one to enable multicast on
* an interface without also enabling multicast management traffic
* (that is, IGMP and MLD). Thus, for now, joining multicast groups
* and assigning local IPv6 addresses will incur such traffic even on
* loopback interfaces. For now this is preferable over not supporting
* multicast on loopback interfaces at all.
*/
netif->flags |= NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
NETIF_SET_CHECKSUM_CTRL(netif, loopif_cksum_flags);
return ERR_OK;
}
/*
* Create a new loopback device.
*/
static int
loopif_create(const char * name)
{
struct loopif *loopif;
/* Find a free loopback interface slot, if available. */
if (TAILQ_EMPTY(&loopif_freelist))
return ENOBUFS;
loopif = TAILQ_FIRST(&loopif_freelist);
TAILQ_REMOVE(&loopif_freelist, loopif, loopif_next);
/* Initialize the loopif structure. */
TAILQ_INSERT_HEAD(&loopif_activelist, loopif, loopif_next);
loopif->loopif_head = NULL;
loopif->loopif_tailp = &loopif->loopif_head;
/*
* For simplicity and efficiency, we do not prepend the address family
* (IPv4/IPv6) to the packet for BPF, which means our loopback devices
* are of type DLT_RAW rather than (NetBSD's) DLT_NULL.
*/
ifdev_add(&loopif->loopif_ifdev, name, IFF_LOOPBACK | IFF_MULTICAST,
IFT_LOOP, 0 /*hdrlen*/, 0 /*addrlen*/, DLT_RAW, LOOPIF_MAX_MTU,
0 /*nd6flags*/, &loopif_ops);
ifdev_update_link(&loopif->loopif_ifdev, LINK_STATE_UP);
return OK;
}
/*
* Destroy an existing loopback device.
*/
static int
loopif_destroy(struct ifdev * ifdev)
{
struct loopif *loopif = (struct loopif *)ifdev;
struct pbuf *pbuf, **pnext;
int r;
/*
* The ifdev module may refuse to remove this interface if it is the
* loopback interface used to loop back packets for other interfaces.
*/
if ((r = ifdev_remove(&loopif->loopif_ifdev)) != OK)
return r;
/*
* Clean up. The loopback queue can be non-empty only if we have been
* throttling in case of a feedback loop.
*/
while ((pbuf = loopif->loopif_head) != NULL) {
pnext = pchain_end(pbuf);
if ((loopif->loopif_head = *pnext) == NULL)
loopif->loopif_tailp = &loopif->loopif_head;
*pnext = NULL;
pbuf_free(pbuf);
}
TAILQ_REMOVE(&loopif_activelist, loopif, loopif_next);
TAILQ_INSERT_HEAD(&loopif_freelist, loopif, loopif_next);
return OK;
}
/*
* Set NetBSD-style interface flags (IFF_) for a loopback interface.
*/
static int
loopif_set_ifflags(struct ifdev * ifdev, unsigned int ifflags)
{
struct loopif *loopif = (struct loopif *)ifdev;
/*
* Only the IFF_UP flag may be set and cleared. We adjust the
* IFF_RUNNING flag immediately based on this flag. This is a bit
* dangerous, but the caller takes this possibility into account.
*/
if ((ifflags & ~IFF_UP) != 0)
return EINVAL;
if (ifflags & IFF_UP)
ifdev_update_ifflags(&loopif->loopif_ifdev,
ifdev_get_ifflags(&loopif->loopif_ifdev) | IFF_RUNNING);
else
ifdev_update_ifflags(&loopif->loopif_ifdev,
ifdev_get_ifflags(&loopif->loopif_ifdev) & ~IFF_RUNNING);
return OK;
}
/*
* Set the Maximum Transmission Unit for this interface. Return TRUE if the
* new value is acceptable, in which case the caller will do the rest. Return
* FALSE otherwise.
*/
static int
loopif_set_mtu(struct ifdev * ifdev __unused, unsigned int mtu)
{
return (mtu <= LOOPIF_MAX_MTU);
}
static const struct ifdev_ops loopif_ops = {
.iop_init = loopif_init_netif,
.iop_input = ip_input,
.iop_output = loopif_output,
.iop_poll = loopif_poll,
.iop_set_ifflags = loopif_set_ifflags,
.iop_set_mtu = loopif_set_mtu,
.iop_destroy = loopif_destroy,
};
/*
* Set and/or retrieve a per-protocol loopback checksumming option through
* sysctl(7).
*/
ssize_t
loopif_cksum(struct rmib_call * call, struct rmib_node * node __unused,
struct rmib_oldp * oldp, struct rmib_newp * newp)
{
struct loopif *loopif;
unsigned int flags;
int r, val;
/*
* The third name field is the protocol. We ignore the domain (the
* second field), thus sharing settings between PF_INET and PF_INET6.
* This is necessary because lwIP does not support TCP/UDP checksumming
* flags on a per-domain basis.
*/
switch (call->call_oname[2]) {
case IPPROTO_IP:
flags = NETIF_CHECKSUM_GEN_IP | NETIF_CHECKSUM_CHECK_IP;
break;
case IPPROTO_UDP:
flags = NETIF_CHECKSUM_GEN_UDP | NETIF_CHECKSUM_CHECK_UDP;
break;
case IPPROTO_TCP:
flags = NETIF_CHECKSUM_GEN_TCP | NETIF_CHECKSUM_CHECK_TCP;
break;
default:
return EINVAL;
}
/* Copy out the old (current) checksumming option. */
if (oldp != NULL) {
val = !!(loopif_cksum_flags & flags);
if ((r = rmib_copyout(oldp, 0, &val, sizeof(val))) < 0)
return r;
}
if (newp != NULL) {
if ((r = rmib_copyin(newp, &val, sizeof(val))) != OK)
return r;
if (val)
loopif_cksum_flags |= flags;
else
loopif_cksum_flags &= ~flags;
/*
* Apply the new checksum flags to all loopback interfaces.
* Technically, this may result in dropped packets when
* enabling checksumming on a throttled loopif, but that is a
* case so rare and unimportant that we ignore it.
*/
TAILQ_FOREACH(loopif, &loopif_activelist, loopif_next) {
NETIF_SET_CHECKSUM_CTRL(loopif_get_netif(loopif),
loopif_cksum_flags);
}
}
/* Return the length of the node. */
return sizeof(val);
}

View File

@ -1,130 +0,0 @@
#ifndef MINIX_NET_LWIP_LWIP_H
#define MINIX_NET_LWIP_LWIP_H
#include <minix/drivers.h>
#include <minix/sockevent.h>
#include <minix/rmib.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include "lwip/ip.h"
#include "lwiphooks.h"
#include "addr.h"
#include "ipsock.h"
#include "ifdev.h"
#include "util.h"
/*
* The standard sockaddr_dl is an absolute pain, because the actual structure
* is dynamically sized, while the standard definition is neither the minimum
* nor the maximum size. We use our own version, which uses the maximum size
* that we will ever produce and accept. This greatly simplifies dealing with
* this structure while also limiting stack usage a bit.
*/
struct sockaddr_dlx {
uint8_t sdlx_len; /* actual length of this structure */
sa_family_t sdlx_family; /* address family, always AF_LINK */
uint16_t sdlx_index; /* interface index */
uint8_t sdlx_type; /* interface type (IFT_) */
uint8_t sdlx_nlen; /* interface name length, w/o nul */
uint8_t sdlx_alen; /* link-layer address length */
uint8_t sdlx_slen; /* selector length, always 0 */
uint8_t sdlx_data[IFNAMSIZ + NETIF_MAX_HWADDR_LEN];
};
STATIC_SOCKADDR_MAX_ASSERT(sockaddr_in);
STATIC_SOCKADDR_MAX_ASSERT(sockaddr_in6);
STATIC_SOCKADDR_MAX_ASSERT(sockaddr_dlx);
/* This is our own, much smaller internal version of sockaddr_storage. */
union sockaddr_any {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_dlx sdlx;
};
/* Number of bits in each of the types of IP addresses. */
#define IP4_BITS 32 /* number of bits in an IPv4 address */
#define IP6_BITS 128 /* number of bits in an IPv6 address */
/*
* Each socket module maintains its own set of sockets, but all sockets must be
* given globally unique identifiers. Therefore, we use these modifier masks,
* which are bitwise OR'ed with the per-module socket identifiers.
*/
#define SOCKID_TCP 0x00000000
#define SOCKID_UDP 0x00100000
#define SOCKID_RAW 0x00200000
#define SOCKID_RT 0x00400000
#define SOCKID_LNK 0x00800000
/*
* Static remote MIB node identifiers for nodes that are dynamically numbered
* on NetBSD, because they do not have a corresponding protocol family number.
*/
#define NET_INTERFACES (PF_MAX) /* net.interfaces (TODO) */
#define NET_BPF (PF_MAX + 1) /* net.bpf */
#define ROOT_EUID 0 /* effective user ID of superuser */
/*
* Function declarations. Modules with more extended interfaces have their own
* header files.
*/
/* mempool.c */
void mempool_init(void);
unsigned int mempool_cur_buffers(void);
unsigned int mempool_max_buffers(void);
/* pchain.c */
struct pbuf **pchain_end(struct pbuf * pbuf);
size_t pchain_size(struct pbuf * pbuf);
/* addrpol.c */
int addrpol_get_label(const ip_addr_t * ipaddr);
int addrpol_get_scope(const ip_addr_t * ipaddr, int is_src);
/* tcpsock.c */
void tcpsock_init(void);
sockid_t tcpsock_socket(int domain, int protocol, struct sock ** sock,
const struct sockevent_ops ** ops);
/* udpsock.c */
void udpsock_init(void);
sockid_t udpsock_socket(int domain, int protocol, struct sock ** sock,
const struct sockevent_ops ** ops);
/* rawsock.c */
void rawsock_init(void);
sockid_t rawsock_socket(int domain, int protocol, struct sock ** sock,
const struct sockevent_ops ** ops);
/* loopif.c */
void loopif_init(void);
ssize_t loopif_cksum(struct rmib_call * call, struct rmib_node * node,
struct rmib_oldp * oldp, struct rmib_newp * newp);
/* lnksock.c */
void lnksock_init(void);
sockid_t lnksock_socket(int type, int protocol, struct sock ** sock,
const struct sockevent_ops ** ops);
/* mibtree.c */
void mibtree_init(void);
void mibtree_register_inet(int domain, int protocol, struct rmib_node * node);
void mibtree_register_lwip(struct rmib_node * node);
/* ifconf.c */
void ifconf_init(void);
int ifconf_ioctl(struct sock * sock, unsigned long request,
const struct sockdriver_data * data, endpoint_t user_endpt);
/* bpf_filter.c */
u_int bpf_filter_ext(const struct bpf_insn * pc, const struct pbuf * pbuf,
const u_char * packet, u_int total, u_int len);
#endif /* !MINIX_NET_LWIP_LWIP_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,997 +0,0 @@
/* LWIP service - udpsock.c - UDP sockets */
#include "lwip.h"
#include "ifaddr.h"
#include "pktsock.h"
#include "lwip/udp.h"
#include <netinet/udp.h>
#include <netinet/ip_var.h>
#include <netinet/udp_var.h>
/* The number of UDP sockets. Inherited from the lwIP configuration. */
#define NR_UDPSOCK MEMP_NUM_UDP_PCB
/*
* Outgoing packets are not getting buffered, so the send buffer size simply
* determines the maximum size for sent packets. The send buffer maximum is
* therefore limited to the maximum size of a single packet (64K-1 bytes),
* which is already enforced by lwIP's 16-bit length parameter to pbuf_alloc().
*
* The actual transmission may enforce a lower limit, though. The full packet
* size must not exceed the same 64K-1 limit, and that includes any headers
* that still have to be prepended to the given packet. The size of those
* headers depends on the socket type (IPv4/IPv6) and the IP_HDRINCL setting.
*/
#define UDP_MAX_PAYLOAD (UINT16_MAX)
#define UDP_SNDBUF_MIN 1 /* minimum UDP send buffer size */
#define UDP_SNDBUF_DEF 8192 /* default UDP send buffer size */
#define UDP_SNDBUF_MAX UDP_MAX_PAYLOAD /* maximum UDP send buffer size */
#define UDP_RCVBUF_MIN MEMPOOL_BUFSIZE /* minimum UDP receive buffer size */
#define UDP_RCVBUF_DEF 32768 /* default UDP receive buffer size */
#define UDP_RCVBUF_MAX 65536 /* maximum UDP receive buffer size */
static struct udpsock {
struct pktsock udp_pktsock; /* pkt socket, MUST be first */
struct udp_pcb *udp_pcb; /* lwIP UDP control block */
SIMPLEQ_ENTRY(udpsock) udp_next; /* next in free list */
} udp_array[NR_UDPSOCK];
static SIMPLEQ_HEAD(, udpsock) udp_freelist; /* list of free UDP sockets */
static const struct sockevent_ops udpsock_ops;
#define udpsock_get_sock(udp) (ipsock_get_sock(udpsock_get_ipsock(udp)))
#define udpsock_get_ipsock(udp) (pktsock_get_ipsock(&(udp)->udp_pktsock))
#define udpsock_is_ipv6(udp) (ipsock_is_ipv6(udpsock_get_ipsock(udp)))
#define udpsock_is_conn(udp) \
(udp_flags((udp)->udp_pcb) & UDP_FLAGS_CONNECTED)
static ssize_t udpsock_pcblist(struct rmib_call *, struct rmib_node *,
struct rmib_oldp *, struct rmib_newp *);
/* The CTL_NET {PF_INET,PF_INET6} IPPROTO_UDP subtree. */
/* TODO: add many more and make some of them writable.. */
static struct rmib_node net_inet_udp_table[] = {
/* 1*/ [UDPCTL_CHECKSUM] = RMIB_INT(RMIB_RO, 1, "checksum",
"Compute UDP checksums"),
/* 2*/ [UDPCTL_SENDSPACE] = RMIB_INT(RMIB_RO, UDP_SNDBUF_DEF,
"sendspace",
"Default UDP send buffer size"),
/* 3*/ [UDPCTL_RECVSPACE] = RMIB_INT(RMIB_RO, UDP_RCVBUF_DEF,
"recvspace",
"Default UDP receive buffer size"),
/* 4*/ [UDPCTL_LOOPBACKCKSUM] = RMIB_FUNC(RMIB_RW | CTLTYPE_INT, sizeof(int),
loopif_cksum, "do_loopback_cksum",
"Perform UDP checksum on loopback"),
/*+0*/ [UDPCTL_MAXID] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0,
udpsock_pcblist, "pcblist",
"UDP protocol control block list"),
};
static struct rmib_node net_inet_udp_node =
RMIB_NODE(RMIB_RO, net_inet_udp_table, "udp", "UDPv4 related settings");
static struct rmib_node net_inet6_udp6_node =
RMIB_NODE(RMIB_RO, net_inet_udp_table, "udp6", "UDPv6 related settings");
/*
* Initialize the UDP sockets module.
*/
void
udpsock_init(void)
{
unsigned int slot;
/* Initialize the list of free UDP sockets. */
SIMPLEQ_INIT(&udp_freelist);
for (slot = 0; slot < __arraycount(udp_array); slot++)
SIMPLEQ_INSERT_TAIL(&udp_freelist, &udp_array[slot], udp_next);
/* Register the net.inet.udp and net.inet6.udp6 RMIB subtrees. */
mibtree_register_inet(PF_INET, IPPROTO_UDP, &net_inet_udp_node);
mibtree_register_inet(PF_INET6, IPPROTO_UDP, &net_inet6_udp6_node);
}
/*
* A packet has arrived on a UDP socket. We own the given packet buffer, and
* so we must free it if we do not want to keep it.
*/
static void
udpsock_input(void * arg, struct udp_pcb * pcb __unused, struct pbuf * pbuf,
const ip_addr_t * ipaddr, uint16_t port)
{
struct udpsock *udp = (struct udpsock *)arg;
/* All UDP input processing is handled by pktsock. */
pktsock_input(&udp->udp_pktsock, pbuf, ipaddr, port);
}
/*
* Create a UDP socket.
*/
sockid_t
udpsock_socket(int domain, int protocol, struct sock ** sockp,
const struct sockevent_ops ** ops)
{
struct udpsock *udp;
unsigned int flags;
uint8_t ip_type;
switch (protocol) {
case 0:
case IPPROTO_UDP:
break;
/* NetBSD does not support IPPROTO_UDPLITE, even though lwIP does. */
default:
return EPROTONOSUPPORT;
}
if (SIMPLEQ_EMPTY(&udp_freelist))
return ENOBUFS;
udp = SIMPLEQ_FIRST(&udp_freelist);
ip_type = pktsock_socket(&udp->udp_pktsock, domain, UDP_SNDBUF_DEF,
UDP_RCVBUF_DEF, sockp);
/* We should have enough PCBs so this call should not fail.. */
if ((udp->udp_pcb = udp_new_ip_type(ip_type)) == NULL)
return ENOBUFS;
udp_recv(udp->udp_pcb, udpsock_input, (void *)udp);
/* By default, the multicast TTL is 1 and looping is enabled. */
udp_set_multicast_ttl(udp->udp_pcb, 1);
flags = udp_flags(udp->udp_pcb);
udp_setflags(udp->udp_pcb, flags | UDP_FLAGS_MULTICAST_LOOP);
SIMPLEQ_REMOVE_HEAD(&udp_freelist, udp_next);
*ops = &udpsock_ops;
return SOCKID_UDP | (sockid_t)(udp - udp_array);
}
/*
* Bind a UDP socket to a local address.
*/
static int
udpsock_bind(struct sock * sock, const struct sockaddr * addr,
socklen_t addr_len, endpoint_t user_endpt)
{
struct udpsock *udp = (struct udpsock *)sock;
ip_addr_t ipaddr;
uint16_t port;
err_t err;
int r;
if ((r = ipsock_get_src_addr(udpsock_get_ipsock(udp), addr, addr_len,
user_endpt, &udp->udp_pcb->local_ip, udp->udp_pcb->local_port,
TRUE /*allow_mcast*/, &ipaddr, &port)) != OK)
return r;
err = udp_bind(udp->udp_pcb, &ipaddr, port);
return util_convert_err(err);
}
/*
* Connect a UDP socket to a remote address.
*/
static int
udpsock_connect(struct sock * sock, const struct sockaddr * addr,
socklen_t addr_len, endpoint_t user_endpt __unused)
{
struct udpsock *udp = (struct udpsock *)sock;
struct ifdev *ifdev;
const ip_addr_t *src_addr;
ip_addr_t dst_addr;
uint16_t dst_port;
uint32_t ifindex, ifindex2;
err_t err;
int r;
/*
* One may "unconnect" socket by providing an address with family
* AF_UNSPEC. Providing an <any>:0 address does not achieve the same.
*/
if (addr_is_unspec(addr, addr_len)) {
udp_disconnect(udp->udp_pcb);
return OK;
}
if ((r = ipsock_get_dst_addr(udpsock_get_ipsock(udp), addr,
addr_len, &udp->udp_pcb->local_ip, &dst_addr, &dst_port)) != OK)
return r;
/*
* Bind explicitly to a source address if the PCB is not bound to one
* yet. This is expected in the BSD socket API, but lwIP does not do
* it for us.
*/
if (ip_addr_isany(&udp->udp_pcb->local_ip)) {
/* Help the multicast case a bit, if possible. */
ifdev = NULL;
if (ip_addr_ismulticast(&dst_addr)) {
ifindex = pktsock_get_ifindex(&udp->udp_pktsock);
ifindex2 = udp_get_multicast_netif_index(udp->udp_pcb);
if (ifindex == 0)
ifindex = ifindex2;
if (ifindex != 0) {
ifdev = ifdev_get_by_index(ifindex);
if (ifdev == NULL)
return ENXIO;
}
}
src_addr = ifaddr_select(&dst_addr, ifdev, NULL /*ifdevp*/);
if (src_addr == NULL)
return EHOSTUNREACH;
err = udp_bind(udp->udp_pcb, src_addr,
udp->udp_pcb->local_port);
if (err != ERR_OK)
return util_convert_err(err);
}
/*
* Connecting a UDP socket serves two main purposes: 1) the socket uses
* the address as destination when sending, and 2) the socket receives
* packets from only the connected address.
*/
err = udp_connect(udp->udp_pcb, &dst_addr, dst_port);
if (err != ERR_OK)
return util_convert_err(err);
return OK;
}
/*
* Perform preliminary checks on a send request.
*/
static int
udpsock_pre_send(struct sock * sock, size_t len, socklen_t ctl_len __unused,
const struct sockaddr * addr, socklen_t addr_len __unused,
endpoint_t user_endpt __unused, int flags)
{
struct udpsock *udp = (struct udpsock *)sock;
if ((flags & ~MSG_DONTROUTE) != 0)
return EOPNOTSUPP;
if (!udpsock_is_conn(udp) && addr == NULL)
return EDESTADDRREQ;
/*
* This is only one part of the length check. The rest is done from
* udpsock_send(), once we have more information.
*/
if (len > ipsock_get_sndbuf(udpsock_get_ipsock(udp)))
return EMSGSIZE;
return OK;
}
/*
* Swap IP-level options between the UDP PCB and the packet options structure,
* for all options that have their flag set in the packet options structure.
* This function is called twice when sending a packet. The result is that the
* flagged options are overridden for only the packet being sent.
*/
static void
udpsock_swap_opt(struct udpsock * udp, struct pktopt * pkto)
{
uint8_t tos, ttl, mcast_ttl;
if (pkto->pkto_flags & PKTOF_TOS) {
tos = udp->udp_pcb->tos;
udp->udp_pcb->tos = pkto->pkto_tos;
pkto->pkto_tos = tos;
}
if (pkto->pkto_flags & PKTOF_TTL) {
ttl = udp->udp_pcb->ttl;
mcast_ttl = udp_get_multicast_ttl(udp->udp_pcb);
udp->udp_pcb->ttl = pkto->pkto_ttl;
udp_set_multicast_ttl(udp->udp_pcb, pkto->pkto_mcast_ttl);
pkto->pkto_ttl = ttl;
pkto->pkto_mcast_ttl = mcast_ttl;
}
}
/*
* Send a packet on a UDP socket.
*/
static int
udpsock_send(struct sock * sock, const struct sockdriver_data * data,
size_t len, size_t * off, const struct sockdriver_data * ctl,
socklen_t ctl_len, socklen_t * ctl_off __unused,
const struct sockaddr * addr, socklen_t addr_len,
endpoint_t user_endpt __unused, int flags, size_t min __unused)
{
struct udpsock *udp = (struct udpsock *)sock;
struct pktopt pktopt;
struct pbuf *pbuf;
struct ifdev *ifdev;
struct netif *netif;
const ip_addr_t *src_addrp, *dst_addrp;
ip_addr_t src_addr, dst_addr; /* for storage only; not always used! */
uint16_t dst_port;
uint32_t ifindex;
size_t hdrlen;
err_t err;
int r;
/* Copy in and parse any packet options. */
pktopt.pkto_flags = 0;
if ((r = pktsock_get_ctl(&udp->udp_pktsock, ctl, ctl_len,
&pktopt)) != OK)
return r;
/*
* The code below will both determine an outgoing interface and a
* source address for the packet. Even though lwIP could do this for
* us in some cases, there are other cases where we must do so
* ourselves, with as main reasons 1) the possibility that either or
* both have been provided through IPV6_PKTINFO, and 2) our intent to
* detect and stop zone violations for (combinations of) scoped IPv6
* addresses. As a result, it is easier to simply take over the
* selection tasks lwIP in their entirety.
*
* Much of the same applies to rawsock_send() as well. Functional
* differences (e.g. IP_HDRINCL support) as well as the PCB accesses in
* the code make it hard to merge the two into a single pktsock copy.
* Please do keep the two in sync as much as possible.
*/
/*
* Start by checking whether the source address and/or the outgoing
* interface are overridden using sticky and/or ancillary options. The
* call to pktsock_get_pktinfo(), if successful, will either set
* 'ifdev' to NULL, in which case there is no override, or it will set
* 'ifdev' to the outgoing interface to use, and (only) in that case
* also fill 'src_addr', with an address that may either be a locally
* owned unicast address or the unspecified ('any') address. If it is
* a unicast address, that is the source address to use for the packet.
* Otherwise, fall back to the address to which the socket is bound,
* which may also be the unspecified address or even a multicast
* address. In those case we will pick a source address further below.
*/
if ((r = pktsock_get_pktinfo(&udp->udp_pktsock, &pktopt, &ifdev,
&src_addr)) != OK)
return r;
if (ifdev != NULL && !ip_addr_isany(&src_addr)) {
/* This is guaranteed to be a proper local unicast address. */
src_addrp = &src_addr;
} else {
src_addrp = &udp->udp_pcb->local_ip;
/*
* If the socket is bound to a multicast address, use the
* unspecified ('any') address as source address instead, until
* we select a real source address (further below). This
* substitution keeps the rest of the code a bit simpler.
*/
if (ip_addr_ismulticast(src_addrp))
src_addrp = IP46_ADDR_ANY(IP_GET_TYPE(src_addrp));
}
/*
* Determine the destination address to use. If the socket is
* connected, always ignore any address provided in the send call.
*/
if (!udpsock_is_conn(udp)) {
assert(addr != NULL); /* already checked in pre_send */
if ((r = ipsock_get_dst_addr(udpsock_get_ipsock(udp), addr,
addr_len, src_addrp, &dst_addr, &dst_port)) != OK)
return r;
dst_addrp = &dst_addr;
} else {
dst_addrp = &udp->udp_pcb->remote_ip;
dst_port = udp->udp_pcb->remote_port;
}
/*
* If the destination is a multicast address, select the outgoing
* interface based on the multicast interface index, if one is set.
* This must be done here in order to allow the code further below to
* detect zone violations, because if we leave this selection to lwIP,
* it will not perform zone violation detection at all. Also note that
* this case must *not* override an interface index already specified
* using IPV6_PKTINFO, as per RFC 3542 Sec. 6.7.
*/
if (ifdev == NULL && ip_addr_ismulticast(dst_addrp)) {
ifindex = udp_get_multicast_netif_index(udp->udp_pcb);
if (ifindex != NETIF_NO_INDEX)
ifdev = ifdev_get_by_index(ifindex); /* (may fail) */
}
/*
* If an interface has been determined already now, the send operation
* will bypass routing. In that case, we must perform our own checks
* on address zone violations, because those will not be made anywhere
* else. Subsequent steps below will never introduce violations.
*/
if (ifdev != NULL && IP_IS_V6(dst_addrp)) {
if (ifaddr_is_zone_mismatch(ip_2_ip6(dst_addrp), ifdev))
return EHOSTUNREACH;
if (IP_IS_V6(src_addrp) &&
ifaddr_is_zone_mismatch(ip_2_ip6(src_addrp), ifdev))
return EHOSTUNREACH;
}
/*
* If we do not yet have an interface at this point, perform a route
* lookup to determine the outgoing interface. Unless MSG_DONTROUTE is
* set (which covers SO_DONTROUTE as well), in which case we look for a
* local subnet that matches the destination address.
*/
if (ifdev == NULL) {
if (!(flags & MSG_DONTROUTE)) {
/*
* ip_route() should never be called with an
* IPADDR_TYPE_ANY type address. This is a lwIP-
* internal requirement; while we override both routing
* functions, we do not deviate from it.
*/
if (IP_IS_ANY_TYPE_VAL(*src_addrp))
src_addrp =
IP46_ADDR_ANY(IP_GET_TYPE(dst_addrp));
/* Perform the route lookup. */
if ((netif = ip_route(src_addrp, dst_addrp)) == NULL)
return EHOSTUNREACH;
ifdev = netif_get_ifdev(netif);
} else {
if ((ifdev = ifaddr_map_by_subnet(dst_addrp)) == NULL)
return EHOSTUNREACH;
}
}
/*
* At this point we have an outgoing interface. If we do not have a
* source address yet, pick one now.
*/
assert(ifdev != NULL);
if (ip_addr_isany(src_addrp)) {
src_addrp = ifaddr_select(dst_addrp, ifdev, NULL /*ifdevp*/);
if (src_addrp == NULL)
return EHOSTUNREACH;
}
/*
* Now that we know the full conditions of what we are about to send,
* check whether the packet size leaves enough room for lwIP to prepend
* headers. If so, allocate a chain of pbufs for the packet.
*/
assert(len <= UDP_MAX_PAYLOAD);
if (IP_IS_V6(dst_addrp))
hdrlen = IP6_HLEN + UDP_HLEN;
else
hdrlen = IP_HLEN + UDP_HLEN;
if (hdrlen + len > UDP_MAX_PAYLOAD)
return EMSGSIZE;
if ((pbuf = pchain_alloc(PBUF_TRANSPORT, len)) == NULL)
return ENOBUFS;
/* Copy in the packet data. */
if ((r = pktsock_get_data(&udp->udp_pktsock, data, len, pbuf)) != OK) {
pbuf_free(pbuf);
return r;
}
/*
* Set broadcast/multicast flags for accounting purposes. Only the
* multicast flag is used for output accounting, but for loopback
* traffic, both flags are copied and used for input accounting and
* setting MSG_MCAST/MSG_BCAST.
*/
if (ip_addr_ismulticast(dst_addrp))
pbuf->flags |= PBUF_FLAG_LLMCAST;
else if (ip_addr_isbroadcast(dst_addrp, ifdev_get_netif(ifdev)))
pbuf->flags |= PBUF_FLAG_LLBCAST;
/* Send the packet. */
udpsock_swap_opt(udp, &pktopt);
assert(!ip_addr_isany(src_addrp));
assert(!ip_addr_ismulticast(src_addrp));
err = udp_sendto_if_src(udp->udp_pcb, pbuf, dst_addrp, dst_port,
ifdev_get_netif(ifdev), src_addrp);
udpsock_swap_opt(udp, &pktopt);
/* Free the pbuf, as a copy has been made. */
pbuf_free(pbuf);
/*
* On success, make sure to return the size of the sent packet as well.
* As an aside: ctl_off need not be updated, as it is not returned.
*/
if ((r = util_convert_err(err)) == OK)
*off = len;
return r;
}
/*
* Update the set of flag-type socket options on a UDP socket.
*/
static void
udpsock_setsockmask(struct sock * sock, unsigned int mask)
{
struct udpsock *udp = (struct udpsock *)sock;
if (mask & SO_REUSEADDR)
ip_set_option(udp->udp_pcb, SOF_REUSEADDR);
else
ip_reset_option(udp->udp_pcb, SOF_REUSEADDR);
if (mask & SO_BROADCAST)
ip_set_option(udp->udp_pcb, SOF_BROADCAST);
else
ip_reset_option(udp->udp_pcb, SOF_BROADCAST);
}
/*
* Prepare a helper structure for IP-level option processing.
*/
static void
udpsock_get_ipopts(struct udpsock * udp, struct ipopts * ipopts)
{
ipopts->local_ip = &udp->udp_pcb->local_ip;
ipopts->remote_ip = &udp->udp_pcb->remote_ip;
ipopts->tos = &udp->udp_pcb->tos;
ipopts->ttl = &udp->udp_pcb->ttl;
ipopts->sndmin = UDP_SNDBUF_MIN;
ipopts->sndmax = UDP_SNDBUF_MAX;
ipopts->rcvmin = UDP_RCVBUF_MIN;
ipopts->rcvmax = UDP_RCVBUF_MAX;
}
/*
* Set socket options on a UDP socket.
*/
static int
udpsock_setsockopt(struct sock * sock, int level, int name,
const struct sockdriver_data * data, socklen_t len)
{
struct udpsock *udp = (struct udpsock *)sock;
struct ipopts ipopts;
ip_addr_t ipaddr;
struct in_addr in_addr;
struct ifdev *ifdev;
unsigned int flags;
uint32_t ifindex;
uint8_t byte;
int r, val;
/*
* Unfortunately, we have to duplicate most of the multicast options
* rather than sharing them with rawsock at the pktsock level. The
* reason is that each of the PCBs have their own multicast abstraction
* functions and so we cannot merge the rest. Same for getsockopt.
*/
switch (level) {
case IPPROTO_IP:
if (udpsock_is_ipv6(udp))
break;
switch (name) {
case IP_MULTICAST_IF:
pktsock_set_mcaware(&udp->udp_pktsock);
if ((r = sockdriver_copyin_opt(data, &in_addr,
sizeof(in_addr), len)) != OK)
return r;
ip_addr_set_ip4_u32(&ipaddr, in_addr.s_addr);
if ((ifdev = ifaddr_map_by_addr(&ipaddr)) == NULL)
return EADDRNOTAVAIL;
udp_set_multicast_netif_index(udp->udp_pcb,
ifdev_get_index(ifdev));
return OK;
case IP_MULTICAST_LOOP:
pktsock_set_mcaware(&udp->udp_pktsock);
if ((r = sockdriver_copyin_opt(data, &byte,
sizeof(byte), len)) != OK)
return r;
flags = udp_flags(udp->udp_pcb);
if (byte)
flags |= UDP_FLAGS_MULTICAST_LOOP;
else
flags &= ~UDP_FLAGS_MULTICAST_LOOP;
udp_setflags(udp->udp_pcb, flags);
return OK;
case IP_MULTICAST_TTL:
pktsock_set_mcaware(&udp->udp_pktsock);
if ((r = sockdriver_copyin_opt(data, &byte,
sizeof(byte), len)) != OK)
return r;
udp_set_multicast_ttl(udp->udp_pcb, byte);
return OK;
}
break;
case IPPROTO_IPV6:
if (!udpsock_is_ipv6(udp))
break;
switch (name) {
case IPV6_MULTICAST_IF:
pktsock_set_mcaware(&udp->udp_pktsock);
if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
len)) != OK)
return r;
if (val != 0) {
ifindex = (uint32_t)val;
ifdev = ifdev_get_by_index(ifindex);
if (ifdev == NULL)
return ENXIO;
} else
ifindex = NETIF_NO_INDEX;
udp_set_multicast_netif_index(udp->udp_pcb, ifindex);
return OK;
case IPV6_MULTICAST_LOOP:
pktsock_set_mcaware(&udp->udp_pktsock);
if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
len)) != OK)
return r;
if (val < 0 || val > 1)
return EINVAL;
flags = udp_flags(udp->udp_pcb);
if (val)
flags |= UDP_FLAGS_MULTICAST_LOOP;
else
flags &= ~UDP_FLAGS_MULTICAST_LOOP;
/*
* lwIP's IPv6 functionality does not actually check
* this flag at all yet. We set it in the hope that
* one day this will magically start working.
*/
udp_setflags(udp->udp_pcb, flags);
return OK;
case IPV6_MULTICAST_HOPS:
pktsock_set_mcaware(&udp->udp_pktsock);
if ((r = sockdriver_copyin_opt(data, &val, sizeof(val),
len)) != OK)
return r;
if (val < -1 || val > UINT8_MAX)
return EINVAL;
if (val == -1)
val = 1;
udp_set_multicast_ttl(udp->udp_pcb, val);
return OK;
}
break;
}
/* Handle all other options at the packet or IP level. */
udpsock_get_ipopts(udp, &ipopts);
return pktsock_setsockopt(&udp->udp_pktsock, level, name, data, len,
&ipopts);
}
/*
* Retrieve socket options on a UDP socket.
*/
static int
udpsock_getsockopt(struct sock * sock, int level, int name,
const struct sockdriver_data * data, socklen_t * len)
{
struct udpsock *udp = (struct udpsock *)sock;
struct ipopts ipopts;
const ip4_addr_t *ip4addr;
struct in_addr in_addr;
struct ifdev *ifdev;
unsigned int flags;
uint32_t ifindex;
uint8_t byte;
int val;
switch (level) {
case IPPROTO_IP:
if (udpsock_is_ipv6(udp))
break;
switch (name) {
case IP_MULTICAST_IF:
ifindex = udp_get_multicast_netif_index(udp->udp_pcb);
/*
* Map back from the interface index to the IPv4
* address assigned to the corresponding interface.
* Should this not work out, return the 'any' address.
*/
if (ifindex != NETIF_NO_INDEX &&
(ifdev = ifdev_get_by_index(ifindex)) != NULL) {
ip4addr =
netif_ip4_addr(ifdev_get_netif(ifdev));
in_addr.s_addr = ip4_addr_get_u32(ip4addr);
} else
in_addr.s_addr = PP_HTONL(INADDR_ANY);
return sockdriver_copyout_opt(data, &in_addr,
sizeof(in_addr), len);
case IP_MULTICAST_LOOP:
flags = udp_flags(udp->udp_pcb);
byte = !!(flags & UDP_FLAGS_MULTICAST_LOOP);
return sockdriver_copyout_opt(data, &byte,
sizeof(byte), len);
case IP_MULTICAST_TTL:
byte = udp_get_multicast_ttl(udp->udp_pcb);
return sockdriver_copyout_opt(data, &byte,
sizeof(byte), len);
}
break;
case IPPROTO_IPV6:
if (!udpsock_is_ipv6(udp))
break;
switch (name) {
case IPV6_MULTICAST_IF:
ifindex = udp_get_multicast_netif_index(udp->udp_pcb);
val = (int)ifindex;
return sockdriver_copyout_opt(data, &val, sizeof(val),
len);
case IPV6_MULTICAST_LOOP:
flags = udp_flags(udp->udp_pcb);
val = !!(flags & UDP_FLAGS_MULTICAST_LOOP);
return sockdriver_copyout_opt(data, &val, sizeof(val),
len);
case IPV6_MULTICAST_HOPS:
val = udp_get_multicast_ttl(udp->udp_pcb);
return sockdriver_copyout_opt(data, &val, sizeof(val),
len);
}
break;
}
/* Handle all other options at the packet or IP level. */
udpsock_get_ipopts(udp, &ipopts);
return pktsock_getsockopt(&udp->udp_pktsock, level, name, data, len,
&ipopts);
}
/*
* Retrieve the local socket address of a UDP socket.
*/
static int
udpsock_getsockname(struct sock * sock, struct sockaddr * addr,
socklen_t * addr_len)
{
struct udpsock *udp = (struct udpsock *)sock;
ipsock_put_addr(udpsock_get_ipsock(udp), addr, addr_len,
&udp->udp_pcb->local_ip, udp->udp_pcb->local_port);
return OK;
}
/*
* Retrieve the remote socket address of a UDP socket.
*/
static int
udpsock_getpeername(struct sock * sock, struct sockaddr * addr,
socklen_t * addr_len)
{
struct udpsock *udp = (struct udpsock *)sock;
if (!udpsock_is_conn(udp))
return ENOTCONN;
ipsock_put_addr(udpsock_get_ipsock(udp), addr, addr_len,
&udp->udp_pcb->remote_ip, udp->udp_pcb->remote_port);
return OK;
}
/*
* Shut down a UDP socket for reading and/or writing.
*/
static int
udpsock_shutdown(struct sock * sock, unsigned int mask)
{
struct udpsock *udp = (struct udpsock *)sock;
if (mask & SFL_SHUT_RD)
udp_recv(udp->udp_pcb, NULL, NULL);
pktsock_shutdown(&udp->udp_pktsock, mask);
return OK;
}
/*
* Close a UDP socket.
*/
static int
udpsock_close(struct sock * sock, int force __unused)
{
struct udpsock *udp = (struct udpsock *)sock;
udp_recv(udp->udp_pcb, NULL, NULL);
udp_remove(udp->udp_pcb);
udp->udp_pcb = NULL;
pktsock_close(&udp->udp_pktsock);
return OK;
}
/*
* Free up a closed UDP socket.
*/
static void
udpsock_free(struct sock * sock)
{
struct udpsock *udp = (struct udpsock *)sock;
assert(udp->udp_pcb == NULL);
SIMPLEQ_INSERT_HEAD(&udp_freelist, udp, udp_next);
}
/*
* Fill the given kinfo_pcb sysctl(7) structure with information about the UDP
* PCB identified by the given pointer.
*/
static void
udpsock_get_info(struct kinfo_pcb * ki, const void * ptr)
{
const struct udp_pcb *pcb = (const struct udp_pcb *)ptr;
struct udpsock *udp;
ki->ki_type = SOCK_DGRAM;
/*
* All UDP sockets should be created by this module, but protect
* ourselves from the case that that is not true anyway.
*/
if (pcb->recv_arg != NULL) {
udp = (struct udpsock *)pcb->recv_arg;
assert(udp >= udp_array &&
udp < &udp_array[__arraycount(udp_array)]);
} else
udp = NULL;
ipsock_get_info(ki, &pcb->local_ip, pcb->local_port, &pcb->remote_ip,
pcb->remote_port);
if (udp != NULL) {
/* TODO: change this so that sockstat(1) may work one day. */
ki->ki_sockaddr = (uint64_t)(uintptr_t)udpsock_get_sock(udp);
ki->ki_rcvq = pktsock_get_recvlen(&udp->udp_pktsock);
}
}
/*
* Given either NULL or a previously returned UDP PCB pointer, return the first
* or next UDP PCB pointer, or NULL if there are no more. Skip UDP PCBs that
* are not bound to an address, as there is no use reporting them.
*/
static const void *
udpsock_enum(const void * last)
{
const struct udp_pcb *pcb;
if (last != NULL)
pcb = (const void *)((const struct udp_pcb *)last)->next;
else
pcb = (const void *)udp_pcbs;
while (pcb != NULL && pcb->local_port == 0)
pcb = pcb->next;
return pcb;
}
/*
* Obtain the list of UDP protocol control blocks, for sysctl(7).
*/
static ssize_t
udpsock_pcblist(struct rmib_call * call, struct rmib_node * node __unused,
struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
{
return util_pcblist(call, oldp, udpsock_enum, udpsock_get_info);
}
static const struct sockevent_ops udpsock_ops = {
.sop_bind = udpsock_bind,
.sop_connect = udpsock_connect,
.sop_pre_send = udpsock_pre_send,
.sop_send = udpsock_send,
.sop_pre_recv = pktsock_pre_recv,
.sop_recv = pktsock_recv,
.sop_test_recv = pktsock_test_recv,
.sop_ioctl = ifconf_ioctl,
.sop_setsockmask = udpsock_setsockmask,
.sop_setsockopt = udpsock_setsockopt,
.sop_getsockopt = udpsock_getsockopt,
.sop_getsockname = udpsock_getsockname,
.sop_getpeername = udpsock_getpeername,
.sop_shutdown = udpsock_shutdown,
.sop_close = udpsock_close,
.sop_free = udpsock_free
};

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +0,0 @@
/* UNIX Domain Sockets - stat.c - network status */
#include "uds.h"
#include <sys/socketvar.h>
#include <sys/unpcb.h>
/*
* Fill the given 'ki' structure with information about the socket 'uds'.
*/
static void
uds_get_info(struct kinfo_pcb * ki, const struct udssock * uds)
{
struct udssock *peer;
socklen_t len;
int type;
type = uds_get_type(uds);
peer = uds_get_peer(uds);
ki->ki_pcbaddr = (uint64_t)(uintptr_t)uds;
ki->ki_ppcbaddr = (uint64_t)(uintptr_t)uds;
ki->ki_sockaddr = (uint64_t)(uintptr_t)&uds->uds_sock;
ki->ki_family = AF_UNIX;
ki->ki_type = type;
ki->ki_protocol = UDSPROTO_UDS;
ki->ki_pflags = 0;
if (uds->uds_flags & UDSF_CONNWAIT)
ki->ki_pflags |= UNP_CONNWAIT;
if (uds->uds_flags & UDSF_PASSCRED)
ki->ki_pflags |= UNP_WANTCRED;
if (type != SOCK_DGRAM && uds->uds_cred.unp_pid != -1) {
if (uds_is_listening(uds))
ki->ki_pflags |= UNP_EIDSBIND;
else if (uds_is_connecting(uds) || uds_is_connected(uds))
ki->ki_pflags |= UNP_EIDSVALID;
}
/* Not sure about NetBSD connection states. First attempt here. */
if (uds_is_connecting(uds))
ki->ki_sostate = SS_ISCONNECTING;
else if (uds_is_connected(uds))
ki->ki_sostate = SS_ISCONNECTED;
else if (uds_is_disconnected(uds))
ki->ki_sostate = SS_ISDISCONNECTED;
ki->ki_rcvq = uds->uds_len;
/* We currently mirror the peer's receive queue size when connected. */
if (uds_is_connected(uds))
ki->ki_sndq = peer->uds_len;
/* The source is not set for bound connection-type sockets here. */
if (type == SOCK_DGRAM || uds_is_listening(uds))
uds_make_addr(uds->uds_path, (size_t)uds->uds_pathlen,
&ki->ki_src, &len);
if (peer != NULL)
uds_make_addr(peer->uds_path, (size_t)peer->uds_pathlen,
&ki->ki_dst, &len);
/* TODO: we should set ki_inode and ki_vnode, but to what? */
ki->ki_conn = (uint64_t)(uintptr_t)peer;
if (!TAILQ_EMPTY(&uds->uds_queue))
ki->ki_refs =
(uint64_t)(uintptr_t)TAILQ_FIRST(&uds->uds_queue);
if (uds_has_link(uds))
ki->ki_nextref =
(uint64_t)(uintptr_t)TAILQ_NEXT(uds, uds_next);
}
/*
* Remote MIB implementation of CTL_NET PF_LOCAL {SOCK_STREAM,SOCK_DGRAM,
* SOCK_SEQPACKET} 0. This function handles all queries on the
* "net.local.{stream,dgram,seqpacket}.pcblist" sysctl(7) nodes.
*
* The 0 for "pcblist" is a MINIXism: we use it to keep our arrays small.
* NetBSD numbers these nodes dynamically and so they have numbers above
* CREATE_BASE. That also means that no userland application can possibly
* hardcode their numbers, and must perform lookups by name. In turn, that
* means that we can safely change the 0 to another number if NetBSD ever
* introduces statically numbered nodes in these subtrees.
*/
static ssize_t
net_local_pcblist(struct rmib_call * call, struct rmib_node * node __unused,
struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
{
struct udssock *uds;
struct kinfo_pcb ki;
ssize_t off;
int r, type, size, max;
if (call->call_namelen != 4)
return EINVAL;
/* The first two added name fields are not used. */
size = call->call_name[2];
if (size < 0 || (size_t)size > sizeof(ki))
return EINVAL;
if (size == 0)
size = sizeof(ki);
max = call->call_name[3];
type = call->call_oname[2];
off = 0;
for (uds = uds_enum(NULL, type); uds != NULL;
uds = uds_enum(uds, type)) {
if (rmib_inrange(oldp, off)) {
memset(&ki, 0, sizeof(ki));
uds_get_info(&ki, uds);
if ((r = rmib_copyout(oldp, off, &ki, size)) < 0)
return r;
}
off += size;
if (max > 0 && --max == 0)
break;
}
/*
* Margin to limit the possible effects of the inherent race condition
* between receiving just the data size and receiving the actual data.
*/
if (oldp == NULL)
off += PCB_SLOP * size;
return off;
}
/* The CTL_NET PF_LOCAL SOCK_STREAM subtree. */
static struct rmib_node net_local_stream_table[] = {
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
"pcblist", "SOCK_STREAM protocol control block list"),
};
/* The CTL_NET PF_LOCAL SOCK_DGRAM subtree. */
static struct rmib_node net_local_dgram_table[] = {
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
"pcblist", "SOCK_DGRAM protocol control block list"),
};
/* The CTL_NET PF_LOCAL SOCK_SEQPACKET subtree. */
static struct rmib_node net_local_seqpacket_table[] = {
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
"pcblist", "SOCK_SEQPACKET protocol control block list"),
};
/* The CTL_NET PF_LOCAL subtree. */
static struct rmib_node net_local_table[] = {
/* 1*/ [SOCK_STREAM] = RMIB_NODE(RMIB_RO, net_local_stream_table,
"stream", "SOCK_STREAM settings"),
/* 2*/ [SOCK_DGRAM] = RMIB_NODE(RMIB_RO, net_local_dgram_table,
"dgram", "SOCK_DGRAM settings"),
/* 5*/ [SOCK_SEQPACKET] = RMIB_NODE(RMIB_RO, net_local_seqpacket_table,
"seqpacket", "SOCK_SEQPACKET settings"),
};
static struct rmib_node net_local_node =
RMIB_NODE(RMIB_RO, net_local_table, "local", "PF_LOCAL related settings");
/*
* Initialize the status module.
*/
void
uds_stat_init(void)
{
const int mib[] = { CTL_NET, PF_LOCAL };
int r;
/*
* Register our own "net.local" subtree with the MIB service.
*
* This call only returns local failures. Remote failures (in the MIB
* service) are silently ignored. So, we can safely panic on failure.
*/
if ((r = rmib_register(mib, __arraycount(mib), &net_local_node)) != OK)
panic("UDS: unable to register remote MIB tree: %d", r);
}
/*
* Clean up the status module.
*/
void
uds_stat_cleanup(void)
{
rmib_deregister(&net_local_node);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,136 +0,0 @@
NOGCCERROR:= yes
BINDIR?= /usr/tests/minix-posix
FILESDIR?= /usr/tests/minix-posix
WARNS?= 1
# Tests have no manpages
MKMAN= no
# They are all bin-owned; by default normal executable mode
BINOWN= bin
# Needed by testsh1.sh
FILES= test1.c
CFLAGS+= -fno-builtin
LDADD+= -lm
.include <bsd.own.mk>
SUBDIR+= blocktest
SUBDIR+= ddekit
SUBDIR+= rmibtest
# Some have special flags compiling
CPPFLAGS.test56.c += -D_MINIX_SYSTEM=1
COPTS.test9.c= -O0
COPTS.test37.c= -O0
COPTS.test53.c= -O0
COPTS.test68.c= -O0
# Some have special libraries
LDADD.test59= -lmthread
LDADD.test76= -lutil
LDADD.test77= -lutil
# Some have an extra file
OBJS.test57= test57loop.o
OBJS.test56+= common-socket.o
OBJS.test80+= common-socket.o
OBJS.test81+= common-socket.o
# Cache testing programs
OBJS.test71+= testcache.o
OBJS.test72+= testcache.o
OBJS.test74+= testcache.o
LDADD.test72+= -lminixfs
PROGS += testvm
OBJS.testvm+= testcache.o
LDSTATIC.testvm= -static
LDADD.testvm+= -lsys -ltimers
FILES += testvm.conf
# Network stack testing programs
OBJS.test90+= socklib.o
OBJS.test91+= socklib.o
OBJS.test92+= socklib.o
OBJS.test93+= socklib.o
# Uncomment the following lines to use SOCKLIB_SWEEP_GENERATE=1/2 in socklib.c
#.PATH: ${NETBSDSRCDIR}/minix/usr.bin/trace
#OBJS.test90+= error.o
#OBJS.test91+= error.o
#OBJS.test92+= error.o
#OBJS.test93+= error.o
.if ${USE_INET6} == "no"
# Tests 91-94 will fail without IPv6 support, but they should at least compile.
CPPFLAGS.socklib.c += -DNO_INET6
CPPFLAGS.test94.c += -DNO_INET6
.endif # ${USE_INET6} == "no"
# Tests to compile, For every architecture
MINIX_TESTS= \
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
81 82 83 84 85 86 87 88 89 90 91 92 93 94
FILES += t84_h_nonexec.sh
.if ${MACHINE_ARCH} == "i386"
MINIX_TESTS+= \
47 51 57 \
62
.endif # ${MACHINE_ARCH} == "i386"
.for t in ${MINIX_TESTS}
PROGS+= test${t}
.endfor
PROGS+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t40g t60a t60b \
t67a t67b t68a t68b tvnd t84_h_spawn t84_h_spawnattr
SCRIPTS+= run check-install testinterp.sh testsh1.sh testsh2.sh testmfs.sh \
testisofs.sh testvnd.sh testkyua.sh testrelpol.sh testrmib.sh
# test57loop.S is not linked into the .bcl file.
# This way, we can link it in when linking the final binary
LDADD.test57+= ${${USE_BITCODE:Uno} != "no":? test57loop.o -Wl,-allow-multiple-definition:}
.if ${MKPIC} == "yes"
# Build them as dynamic executables by default if shared libraries
# are available; so that the building and executing of dynamic
# executables is tested
LDSTATIC= -dynamic
LDFLAGS.mod+= -shared # make shared object
# Files which have to be compiled with -fPIC
mod.o: mod.c
${COMPILE.c} -fPIC ${.IMPSRC}
common.o: common.c
${COMPILE.c} -fPIC ${.IMPSRC}
# Add test that must be linked dynamically, and its dynamically loaded
# module
PROGS+= test63 mod
.endif # ${MKPIC} == "yes"
.for o in ${PROGS}
OBJS.${o} += common.o
.endfor
.include "./arch/${MACHINE_ARCH}/Makefile.inc"
# LSC Make sure there is not leftover after a failed testrun
clean: .PHONY .MAKE
@rm -rf DIR*
.include <bsd.prog.mk>
.include <bsd.subdir.mk>

View File

@ -1,16 +0,0 @@
# Makefile for the sys_padconf test.
.include <bsd.own.mk>
PROG= padconftest
SRCS= padconftest.c
DPADD+= ${LIBSYS}
LDADD+= -lsys
MAN=
BINDIR?= /usr/tests/minix-posix
.include "${NETBSDSRCDIR}/drivers/Makefile.inc"
.include <minix.service.mk>

View File

@ -1,310 +0,0 @@
/* test27: stat() fstat() Author: Jan-Mark Wams (jms@cs.vu.nl) */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <stdio.h>
#define MODE_MASK (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID)
int max_error = 4;
#include "common.h"
#define ITERATIONS 2
#define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
#define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
int superuser;
char *MaxName; /* Name of maximum length */
char MaxPath[PATH_MAX];
char *ToLongName; /* Name of maximum +1 length */
char ToLongPath[PATH_MAX + 1];
void test27a(void);
void test27b(void);
void test27c(void);
void makelongnames(void);
int main(int argc, char *argv[])
{
int i, m = 0xFFFF;
start(27);
if (argc == 2) m = atoi(argv[1]);
superuser = (getuid() == 0);
makelongnames();
for (i = 0; i < ITERATIONS; i++) {
if (m & 0001) test27a();
if (m & 0002) test27b();
if (m & 0004) test27c();
}
quit();
return(-1); /* Unreachable */
}
void test27a()
{ /* Test Normal operation. */
struct stat st1, st2;
time_t time1, time2;
int fd, pfd[2];
subtest = 1;
time(&time1); /* get time before */
while (time1 >= time((time_t *)0))
; /* Wait for time to change. */
System("echo 7bytes > foo; chmod 4750 foo");
if (stat("foo", &st1) != 0) e(1); /* get foo's info */
time(&time2);
while (time2 >= time((time_t *)0))
; /* Wait for next second. */
time(&time2); /* get time after */
if ((st1.st_mode & MODE_MASK) != 04750) e(2);
if (st1.st_nlink != 1) e(3); /* check stat */
if (st1.st_uid != geteuid()) e(4);
#if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
if (st1.st_gid != getegid()) e(5);
#endif /* defined(NGROUPS_MAX) && NGROUPS_MAX == 0 */
if (st1.st_size != (size_t) 7) e(6);
if (st1.st_atime <= time1) e(7);
if (st1.st_atime >= time2) e(8);
if (st1.st_ctime <= time1) e(9);
if (st1.st_ctime >= time2) e(10);
if (st1.st_mtime <= time1) e(11);
if (st1.st_mtime >= time2) e(12);
/* Compair stat and fstat. */
System("echo 7bytes > bar");
fd = open("bar", O_RDWR | O_APPEND); /* the bar is open! */
if (fd != 3) e(13); /* should be stderr + 1 */
if (stat("bar", &st1) != 0) e(14); /* get bar's info */
if (fstat(fd, &st2) != 0) e(15); /* get bar's info */
/* St1 en st2 should be the same. */
if (st1.st_dev != st2.st_dev) e(16);
if (st1.st_ino != st2.st_ino) e(17);
if (st1.st_mode != st2.st_mode) e(18);
if (st1.st_nlink != st2.st_nlink) e(19);
if (st1.st_uid != st2.st_uid) e(20);
if (st1.st_gid != st2.st_gid) e(21);
if (st1.st_size != st2.st_size) e(22);
if (st1.st_atime != st2.st_atime) e(23);
if (st1.st_ctime != st2.st_ctime) e(24);
if (st1.st_mtime != st2.st_mtime) e(25);
time(&time1); /* wait a sec. */
while (time1 >= time((time_t *)0))
;
System("chmod 755 bar"); /* chainge mode */
System("rm -f foobar; ln bar foobar"); /* chainge # links */
if (write(fd, "foo", 4) != 4) e(26); /* write a bit (or two) */
if (stat("bar", &st2) != 0) e(27); /* get new info */
if (st2.st_dev != st1.st_dev) e(28);
if (st2.st_ino != st1.st_ino) e(29); /* compair the fealds */
if ((st2.st_mode & MODE_MASK) != 0755) e(30);
if (!S_ISREG(st2.st_mode)) e(31);
if (st2.st_nlink != st1.st_nlink + 1) e(32);
if (st2.st_uid != st1.st_uid) e(33);
if (st2.st_gid != st1.st_gid) e(34);
if (st2.st_size != (size_t) 11) e(35);
if (st2.st_atime != st1.st_atime) e(36);
if (st2.st_ctime <= st1.st_ctime) e(37);
if (st2.st_mtime <= st1.st_mtime) e(38);
if (close(fd) != 0) e(39); /* sorry the bar is closed */
/* Check special file. */
if (stat("/dev/tty", &st1) != 0) e(40);
if (!S_ISCHR(st1.st_mode)) e(41);
#if defined(__minix) && defined(_NETBSD_SOURCE)
if (stat("/dev/ram", &st1) != 0) e(42);
if (!S_ISBLK(st1.st_mode)) e(43);
#endif
/* Check fifos. */
time(&time1);
while (time1 >= time((time_t *)0))
;
if (mkfifo("fifo", 0640) != 0) e(44);
if (stat("fifo", &st1) != 0) e(45); /* get fifo's info */
time(&time2);
while (time2 >= time((time_t *)0))
;
time(&time2);
if (!S_ISFIFO(st1.st_mode)) e(46);
if (st1.st_nlink != 1) e(47); /* check the stat info */
if (st1.st_uid != geteuid()) e(48);
#if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
if (st1.st_gid != getegid()) e(49);
#endif /* defined(NGROUPS_MAX) && NGROUPS_MAX == 0 */
if (st1.st_size != (size_t) 0) e(50);
if (st1.st_atime <= time1) e(51);
if (st1.st_atime >= time2) e(52);
if (st1.st_ctime <= time1) e(53);
if (st1.st_ctime >= time2) e(54);
if (st1.st_mtime <= time1) e(55);
if (st1.st_mtime >= time2) e(56);
/* Note: the st_mode of a fstat on a pipe should contain a isfifo bit. */
/* Check pipes. */
time(&time1);
while (time1 >= time((time_t *)0))
;
if (pipe(pfd) != 0) e(57);
if (fstat(pfd[0], &st1) != 0) e(58); /* get pipe input info */
time(&time2);
while (time2 >= time((time_t *)0))
;
time(&time2);
if (!(S_ISFIFO(st1.st_mode))) e(59); /* check stat struct */
if (st1.st_uid != geteuid()) e(60);
if (st1.st_gid != getegid()) e(61);
if (st1.st_size != (size_t) 0) e(62);
if (st1.st_atime <= time1) e(63);
if (st1.st_atime >= time2) e(64);
if (st1.st_ctime <= time1) e(65);
if (st1.st_ctime >= time2) e(66);
if (st1.st_mtime <= time1) e(67);
if (st1.st_mtime >= time2) e(68);
if (fstat(pfd[1], &st1) != 0) e(69); /* get pipe output info */
if (!(S_ISFIFO(st1.st_mode))) e(70);
if (st1.st_uid != geteuid()) e(71);
if (st1.st_gid != getegid()) e(72);
if (st1.st_size != (size_t) 0) e(73);
if (st1.st_atime < time1) e(74);
if (st1.st_atime > time2) e(75);
if (st1.st_ctime < time1) e(76);
if (st1.st_ctime > time2) e(77);
if (st1.st_mtime < time1) e(78);
if (st1.st_mtime > time2) e(79);
if (close(pfd[0]) != 0) e(80);
if (close(pfd[1]) != 0) e(81);/* close pipe */
/* Check dirs. */
time(&time1);
while (time1 >= time((time_t *)0))
;
System("mkdir dir");
if (stat("dir", &st1) != 0) e(82); /* get dir info */
time(&time2);
while (time2 >= time((time_t *)0))
;
time(&time2);
if (!(S_ISDIR(st1.st_mode))) e(83); /* check stat struct */
if (st1.st_uid != geteuid()) e(84);
#if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
if (st1.st_gid != getegid()) e(85);
#endif /* defined(NGROUPS_MAX) && NGROUPS_MAX == 0 */
if (st1.st_atime < time1) e(86);
if (st1.st_atime > time2) e(87);
if (st1.st_ctime < time1) e(88);
if (st1.st_ctime > time2) e(89);
if (st1.st_mtime < time1) e(90);
if (st1.st_mtime > time2) e(91);
System("rm -rf ../DIR_27/*");
}
void test27b()
{ /* Test maxima. */
struct stat st;
int fd;
subtest = 2;
/* Check stats on maximum length files names. */
if (mkdir(MaxName, 0777) != 0) e(1);
if (stat(MaxName, &st) != 0) e(2);
if ((fd = open(MaxName, O_RDONLY)) != 3) e(3);
if (fstat(fd, &st) != 0) e(4);
if (close(fd) != 0) e(5);
if (rmdir(MaxName) != 0) e(6);
if (stat(MaxPath, &st) != 0) e(7);
if ((fd = open(MaxPath, O_RDONLY)) != 3) e(8);
if (fstat(fd, &st) != 0) e(9);
if (close(fd) != 0) e(10);
System("rm -rf ../DIR_27/*");
}
void test27c()
{ /* Test error response. */
struct stat st;
int fd, i;
subtest = 3;
System("echo Hi > foo"); /* Make a file called foo. */
/* Check if a un searchable dir is handled ok. */
Chdir(".."); /* cd .. */
System("chmod 677 DIR_27"); /* no search permission */
if (stat("DIR_27/nono", &st) != -1) e(1);
if (superuser) {
if (errno != ENOENT) e(2); /* su has access */
}
if (!superuser) {
if (errno != EACCES) e(3); /* we don't ;-) */
}
System("chmod 777 DIR_27");
Chdir("DIR_27"); /* back to test dir */
/* Check on ToLongName etc. */
if (stat(ToLongPath, &st) != -1) e(6); /* path is too long */
if (errno != ENAMETOOLONG) e(7);
/* Test some common errors. */
if (stat("nono", &st) != -1) e(8); /* nono nonexistent */
if (errno != ENOENT) e(9);
if (stat("", &st) != -1) e(10); /* try empty */
if (errno != ENOENT) e(11);
if (stat("foo/bar", &st) != -1) e(12); /* foo is a file */
if (errno != ENOTDIR) e(13);
/* Test fstat on file descriptors that are not open. */
for (i = 3; i < 6; i++) {
if (fstat(i, &st) != -1) e(14);
if (errno != EBADF) e(15);
}
/* Test if a just closed file is `fstat()'-able. */
if ((fd = open("foo", O_RDONLY)) != 3) e(16); /* open foo */
if (fstat(fd, &st) != 0) e(17); /* get stat */
if (close(fd) != 0) e(18); /* close it */
if (fstat(fd, &st) != -1) e(19); /* get stat */
if (errno != EBADF) e(20);
System("rm -rf ../DIR_27/*");
}
void makelongnames()
{
register int i;
int max_name_length;
max_name_length = name_max("."); /* Aka NAME_MAX, but not every FS supports
* the same length, hence runtime check */
MaxName = malloc(max_name_length + 1);
ToLongName = malloc(max_name_length + 1 + 1); /* Name of maximum +1 length */
memset(MaxName, 'a', max_name_length);
MaxName[max_name_length] = '\0';
for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */
MaxPath[i++] = '.';
MaxPath[i] = '/';
}
MaxPath[PATH_MAX - 1] = '\0';
strcpy(ToLongName, MaxName); /* copy them Max to ToLong */
strcpy(ToLongPath, MaxPath);
ToLongName[max_name_length] = 'a';
ToLongName[max_name_length+1] = '\0';/* extend ToLongName by one too many */
ToLongPath[PATH_MAX - 1] = '/';
ToLongPath[PATH_MAX] = '\0'; /* inc ToLongPath by one */
}

View File

@ -1,405 +0,0 @@
/* test28: mkdir() rmdir() Author: Jan-Mark Wams (jms@cs.vu.nl) */
/*
** Not tested readonly file systems (EROFS.)
** Not tested fs full (ENOSPC.)
** Not really tested EBUSY.
** Not tested unlinking busy directories.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <time.h>
#include <stdio.h>
int max_error = 4;
#include "common.h"
#define ITERATIONS 2
#define DIRENT0 ((struct dirent *) NULL)
#define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
#define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
int subtest = 1;
int superuser;
char *MaxName; /* Name of maximum length */
char MaxPath[PATH_MAX];
char *ToLongName; /* Name of maximum +1 length */
char ToLongPath[PATH_MAX + 1];
void test28a(void);
void test28c(void);
void test28b(void);
void makelongnames(void);
int main(int argc, char *argv[])
{
int i, m = 0xFFFF;
sync();
if (argc == 2) m = atoi(argv[1]);
start(28);
superuser = (getuid() == 0);
makelongnames();
umask(0000); /* no umask */
for (i = 0; i < ITERATIONS; i++) {
if (m & 0001) test28a();
if (m & 0002) test28b();
if (m & 0004) test28c();
}
quit();
return(-1); /* Unreachable */
}
void test28a()
{
int mode; /* used in for loop */
struct stat st;
time_t time1, time2;
DIR *dirp;
struct dirent *dep;
int dot = 0, dotdot = 0;
subtest = 1;
System("rm -rf foo /tmp/foo");/* clean up junk */
/* Check relative path names */
if (mkdir("./foo", 0777) != 0) e(1); /* make a dir foo */
if (mkdir("./foo/bar", 0777) != 0) e(2); /* make foo/bar */
if (rmdir("foo/bar") != 0) e(3); /* delete bar */
if (mkdir("foo/../foo/bar", 0777) != 0) e(4); /* make bar again */
if (rmdir("./foo/bar") != 0) e(5); /* and remove again */
/* Foo should be empty (ie. contain only "." and ".." */
if ((dirp = opendir("foo")) == (DIR *) NULL) e(6); /* open foo */
if ((dep = readdir(dirp)) == DIRENT0) e(7); /* get first entry */
if (strcmp(dep->d_name, ".") == 0) dot += 1; /* record what it is */
if (strcmp(dep->d_name, "..") == 0) dotdot += 1;
if ((dep = readdir(dirp)) == DIRENT0) e(8); /* get second entry */
if (strcmp(dep->d_name, ".") == 0) dot += 1; /* record again */
if (strcmp(dep->d_name, "..") == 0) dotdot += 1;
if ((dep = readdir(dirp)) != DIRENT0) e(9); /* no 3d entry */
if (dot == 1 && dotdot != 1) e(10); /* only . and .. */
if (closedir(dirp) != 0) e(11); /* close foo */
if (rmdir("./foo") != 0) e(12); /* remove dir foo */
/* Check absolute path names */
if (mkdir("/tmp/foo", 0777) != 0) e(13);
if (mkdir("/tmp/foo/bar", 0777) != 0) e(14);
if (rmdir("/tmp/foo/bar") != 0) e(15); /* make some dirs */
if (rmdir("/tmp/foo") != 0) e(16);
/* Check the mode arument for mkdir() */
for (mode = 0; mode <= 0777; mode++) {
if (mkdir("foo", mode) != 0) e(17); /* make foo */
if (stat("foo", &st) != 0) e(18);
if ((st.st_mode & 0777) != mode) e(19); /* check it's mode */
if (rmdir("foo") != 0) e(20); /* and remove it */
}
/* Check the stat */
time(&time1);
while (time1 >= time((time_t *)0))
;
if (mkdir("foo", 0765) != 0) e(21); /* make foo */
if (stat("foo", &st) != 0) e(22);
time(&time2);
while (time2 >= time((time_t *)0))
;
time(&time2);
if (st.st_nlink != 2) e(23);
if (st.st_uid != geteuid()) e(24);
if (st.st_gid != getegid()) e(25);
if (st.st_size < 0) e(26);
if ((st.st_mode & 0777) != 0765) e(27);
if (st.st_atime <= time1) e(28);
if (st.st_atime >= time2) e(29);
if (st.st_ctime <= time1) e(30);
if (st.st_ctime >= time2) e(31);
if (st.st_mtime <= time1) e(32);
if (st.st_mtime >= time2) e(33);
/* Check if parent is updated */
if (stat(".", &st) != 0) e(34);
time(&time2);
while (time2 >= time((time_t *)0))
;
time(&time2);
if (st.st_ctime <= time1) e(35);
if (st.st_ctime >= time2) e(36);
if (st.st_mtime <= time1) e(37);
if (st.st_mtime >= time2) e(38);
time(&time1);
while (time1 >= time((time_t *)0))
;
if (rmdir("foo") != 0) e(39);
if (stat(".", &st) != 0) e(40);
time(&time2);
while (time2 >= time((time_t *)0))
;
time(&time2);
if (st.st_ctime <= time1) e(41);
if (st.st_ctime >= time2) e(42);
if (st.st_mtime <= time1) e(43);
if (st.st_mtime >= time2) e(44);
}
void test28b()
{ /* Test critical values. */
struct stat st;
DIR *dirp;
struct dirent *dep;
int fd; /* file descriptor */
int other = 0, dot = 0, dotdot = 0; /* dirent counters */
int r; /* Intermediate result */
int rmdir_result; /* tmp var */
int stat_loc, does_truncate;
subtest = 2;
System("rm -rf ../DIR_28/*");
/* Check funny but valid path names */
if (mkdir("/../../..////.//../tmp/foo/", 0777) != 0) e(1);
if (mkdir("/tmp/foo//////..//foo//../foo/bar/", 0777) != 0) e(2);
if (rmdir("///tmp/..//tmp/foo/bar//../..//foo/bar") != 0) e(3);
if (mkdir("///tmp/foo/foobar//", 0777) != 0) e(4);
if (rmdir("/tmp/foo/foobar//") != 0) e(5);
if (rmdir("/.././/././/tmp/foo///////////////") != 0) e(6);
if (rmdir("/tmp/foo") != -1) e(7); /* try again */
/* Test max path ed. */
if (mkdir(MaxName, 0777) != 0) e(9); /* make dir MaxName */
if (rmdir(MaxName) != 0) e(10); /* and remove it */
MaxPath[strlen(MaxPath) - 2] = '/'; /* convert MaxPath */
MaxPath[strlen(MaxPath) - 1] = 'a'; /* to ././.../a */
if (mkdir(MaxPath, 0777) != 0) e(11); /* it should be */
if (rmdir(MaxPath) != 0) e(12); /* ok */
/* Test too long path ed. */
does_truncate = does_fs_truncate();
r = mkdir(ToLongName, 0777);
if (does_truncate ) {
/* FS truncates names, mkdir should've worked */
if (r != 0) e(13); /* Try ToLongName */
if (rmdir(ToLongName) != 0) e(14); /* and remove it */
} else {
/* Too long, should've failed with ENAMETOOLONG */
if (r == 0) e(15);
if (errno != ENAMETOOLONG) e(16);
}
ToLongPath[strlen(ToLongPath) - 2] = '/'; /* make ToLongPath */
ToLongPath[strlen(ToLongPath) - 1] = 'a'; /* contain ././.../a */
if (mkdir(ToLongPath, 0777) != -1) e(17); /* it should */
if (errno != ENAMETOOLONG) e(18); /* not be ok */
if (rmdir(ToLongPath) != -1) e(19);
if (errno != ENAMETOOLONG) e(20);
if (mkdir("foo", 0777) != 0) e(21);
System("touch foo/xyzzy");
/* Test if rmdir removes only empty dirs */
if (rmdir("foo") != -1) e(29);/* not empty */
if (errno != EEXIST && errno != ENOTEMPTY) e(30);
/* Test if rmdir removes a dir with an empty file (it shouldn't.) */
System("rm -rf foo"); /* cleanup */
if (mkdir("foo", 0777) != 0) e(31);
System("> foo/empty"); /* > empty */
if (rmdir("foo") != -1) e(32);/* not empty */
if (errno != EEXIST && errno != ENOTEMPTY) e(33);
if (unlink("foo/empty") != 0) e(34); /* rm empty */
/* See what happens if foo is linked. */
#if 0
if (superuser) {
if (link("foo", "footoo") != 0) e(35); /* foo still */
if (rmdir("footoo") != 0) e(36); /* exist */
if (chdir("footoo") != -1) e(37); /* footoo */
if (errno != ENOENT) e(38); /* is gone */
}
#endif
#if defined(__minix) && defined(_NETBSD_SOURCE)
/* Some implementations might allow users to link directories. */
if (!superuser) {
if (link("foo", "footoo") != -1) e(39);
if (errno != EPERM) e(40);
if (unlink("foo") != -1) e(41);
if (errno != EPERM) e(42);
}
#endif
/* See if ".." and "." are removed from the dir, and if it is
* unwriteable
* Note, we can not remove any files in the PARENT
* process, because this
* will make readdir unpredicatble. (see
* 1003.1 page 84 line 30.) However
* removal of the directory is
* not specified in the standard.
*/
System("rm -rf /tmp/sema[12].07");
switch (fork()) {
case -1: printf("Can't fork\n"); break;
case 0:
alarm(20);
if ((fd = open("foo", O_RDONLY)) <= 2) e(43); /* open */
if ((dirp = opendir("foo")) == (DIR *) NULL) e(44); /* opendir */
/* UpA downB */
system(">/tmp/sema1.07; while test -f /tmp/sema1.07; do sleep 1;done");
while ((dep = readdir(dirp)) != DIRENT0) {
if (strcmp(dep->d_name, "..") == 0)
dotdot += 1;
else if (strcmp(dep->d_name, ".") == 0)
dot += 1;
else
other += 1;
}
if (dotdot != 0) e(45); /* no entrys */
if (dot != 0) e(46); /* shoul be */
if (other != 0) e(47); /* left or */
/* No new files (entrys) are allowed on foo */
if (creat("foo/nono", 0777) != -1) e(48); /* makeable */
if (closedir(dirp) != 0) e(49); /* close foo */
system("while test ! -f /tmp/sema2.07; do sleep 1; done"); /* downA */
System("rm -f /tmp/sema2.07"); /* clean up */
/* Foo still exist, so we should be able to get a fstat */
if (fstat(fd, &st) != 0) e(50);
if (st.st_nlink != (nlink_t) 0) e(51); /* 0 left */
if (close(fd) != 0) e(52); /* last one */
exit(0);
default:
system("while test ! -f /tmp/sema1.07; do sleep 1; done"); /* downA */
if (rmdir("foo") != 0) e(53); /* cleanerup */
System("rm -f /tmp/sema1.07"); /* upB */
if (chdir("foo") != -1) e(54); /* it should */
if (errno != ENOENT) e(55); /* be gone */
System("> /tmp/sema2.07"); /* upA */
if (wait(&stat_loc) == -1) e(56);
if (stat_loc != 0) e(57);
}
/* See if foo isn't accessible any more */
if (chdir("foo") != -1) e(58);
if (errno != ENOENT) e(59);
/* Let's see if we can get a EBUSSY..... */
if (mkdir("foo", 0777) != 0) e(60); /* mkdir foo */
System("rm -f /tmp/sema.07"); /* unness */
switch (fork()) {
case -1: printf("Can't fork\n"); break;
case 0:
alarm(20);
if (chdir("foo") != 0) e(61); /* child goes */
System("> /tmp/sema.07"); /* upA */
system("while test -f /tmp/sema.07; do sleep 1; done"); /* downB */
sleep(1);
exit(0);
default:
system("while test ! -f /tmp/sema.07; do sleep 1; done"); /* downA */
rmdir_result = rmdir("foo"); /* try remove */
if (rmdir_result == -1) { /* if it failed */
if (errno != EBUSY) e(62); /* foo is busy */
} else {
if (rmdir_result != 0) e(63);
if (rmdir("foo") != -1) e(64); /* not removable */
if (errno != ENOENT) e(65); /* again. */
if (chdir("foo") != -1) e(66); /* we can't go */
if (errno != ENOENT) e(67); /* there any more */
if (mkdir("foo", 0777) != 0) e(68); /* we can remake foo */
}
System("rm -f /tmp/sema.07"); /* upB */
if (wait(&stat_loc) == -1) e(69);
if (stat_loc != 0) e(70);
}
if (rmdir("foo") != 0) e(71); /* clean up */
}
void test28c()
{ /* Test error handeling. */
subtest = 3;
System("rm -rf ../DIR_28/*");
System("rm -rf foo /tmp/foo");/* clean up junk */
/* Test common errors */
if (mkdir("foo", 0777) != 0) e(1); /* mkdir shouldn't fail */
if (mkdir("foo", 0777) != -1) e(2); /* should fail the 2d time */
if (errno != EEXIST) e(3); /* because it exists already */
if (rmdir("foo") != 0) e(4); /* rmdir shouldn't fail */
if (rmdir("foo") != -1) e(5); /* but it should now because */
if (errno != ENOENT) e(6); /* it's gone the 1st time */
/* Test on access etc. */
if (mkdir("foo", 0777) != 0) e(7);
if (mkdir("foo/bar", 0777) != 0) e(8);
if (!superuser) {
System("chmod 677 foo");/* make foo inaccesable */
if (mkdir("foo/foo", 0777) != -1) e(9);
if (errno != EACCES) e(10);
if (rmdir("foo/bar") != -1) e(11);
if (errno != EACCES) e(12);
System("chmod 577 foo");/* make foo unwritable */
if (mkdir("foo/foo", 0777) != -1) e(13);
if (errno != EACCES) e(14);
if (rmdir("foo/bar") != -1) e(15);
if (errno != EACCES) e(16);
System("chmod 777 foo");/* make foo full accessable */
}
if (rmdir("foo/bar") != 0) e(17); /* bar should be removable */
if (mkdir("foo/no/foo", 0777) != -1) e(18); /* Note: "no" doesn't exist */
if (errno != ENOENT) e(19);
if (mkdir("", 0777) != -1) e(20); /* empty string isn't ok */
if (errno != ENOENT) e(21);
if (rmdir("") != -1) e(22); /* empty string isn't ok */
if (errno != ENOENT) e(23);
System("> foo/no"); /* make a file "no" */
if (mkdir("foo/no/foo", 0777) != -1) e(24);
if (errno != ENOTDIR) e(25); /* note: "no" is not a a dir */
if (rmdir("foo/no/foo") != -1) e(26);
if (errno != ENOTDIR) e(27);
System("rm -rf foo"); /* clean up */
}
void makelongnames()
{
register int i;
int max_name_length;
max_name_length = name_max("."); /* Aka NAME_MAX, but not every FS supports
* the same length, hence runtime check */
MaxName = malloc(max_name_length + 1);
ToLongName = malloc(max_name_length + 1 + 1); /* Name of maximum +1 length */
memset(MaxName, 'a', max_name_length);
MaxName[max_name_length] = '\0';
for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */
MaxPath[i++] = '.';
MaxPath[i] = '/';
}
MaxPath[PATH_MAX - 1] = '\0';
strcpy(ToLongName, MaxName); /* copy them Max to ToLong */
strcpy(ToLongPath, MaxPath);
ToLongName[max_name_length] = 'a';
ToLongName[max_name_length+1] = '\0';/* extend ToLongName by one too many */
ToLongPath[PATH_MAX - 1] = '/';
ToLongPath[PATH_MAX] = '\0'; /* inc ToLongPath by one */
}

View File

@ -1,109 +0,0 @@
# Makefile for the kernel image.
.include <bsd.own.mk>
GEN_FILES= *.bak image kernel *.iso *.iso.gz cdfdimage rootimage src
# LSC detect where were built the objects files
PROGROOT:= ..
.if "${MAKEOBJDIR:S,${.CURDIR},,}" != ""
PROGROOT:= ${MAKEOBJDIR:S,releasetools,,}
.endif
# Specify the programs that are part of the system image.
KERNEL= ${PROGROOT}/minix/kernel/kernel
# PROGRAMS are in the order they should be loaded by boot
PROGRAMS+= ${PROGROOT}/minix/servers/ds/ds
PROGRAMS+= ${PROGROOT}/minix/servers/rs/rs
PROGRAMS+= ${PROGROOT}/minix/servers/pm/pm
PROGRAMS+= ${PROGROOT}/minix/servers/sched/sched
PROGRAMS+= ${PROGROOT}/minix/servers/vfs/vfs
PROGRAMS+= ${PROGROOT}/minix/drivers/storage/memory/memory
PROGRAMS+= ${PROGROOT}/minix/drivers/tty/tty/tty
PROGRAMS+= ${PROGROOT}/minix/servers/mib/mib
PROGRAMS+= ${PROGROOT}/minix/servers/vm/vm
PROGRAMS+= ${PROGROOT}/minix/fs/pfs/pfs
PROGRAMS+= ${PROGROOT}/minix/fs/mfs/mfs
PROGRAMS+= ${PROGROOT}/sbin/init/init
all usage help:
@echo " " >&2
@echo "Master Makefile to create new MINIX configuration." >&2
@echo "Root privileges are required." >&2
@echo " " >&2
@echo "Usage:" >&2
@echo " make includes # Install include files" >&2
@echo " make depend # Generate dependency files" >&2
@echo " make services # Compile and install all services" >&2
@echo " make hdboot # Make image, and install to hard disk" >&2
@echo " make clean # Remove all compiler results" >&2
@echo " " >&2
@echo "To create a fresh MINIX configuration, try:" >&2
@echo " make clean install # new boot image" >&2
@echo " " >&2
.gitignore: Makefile
echo ${GEN_FILES} | tr ' ' '\n' >.gitignore
includes:
${MAKE} -C ${NETBSDSRCDIR} includes
depend: includes .gitignore
${MAKE} -C ${NETBSDSRCDIR} depend
libraries: includes
${MAKE} -C ${NETBSDSRCDIR} do-lib
kernel: libraries
${MAKE} -C ${NETBSDSRCDIR}/minix/kernel
servers: libraries
${MAKE} -C ${NETBSDSRCDIR}/minix/fs all install
${MAKE} -C ${NETBSDSRCDIR}/minix/net all install
${MAKE} -C ${NETBSDSRCDIR}/minix/servers all install
sbin: libraries
${MAKE} -C ${NETBSDSRCDIR}/sbin all install
${MAKE} -C ${NETBSDSRCDIR}/minix/sbin all install
drivers: libraries
${MAKE} -C ${NETBSDSRCDIR}/minix/drivers all install
services: kernel servers drivers sbin
do-hdboot:
@rm -rf ${DESTDIR}/boot/minix/.temp/
${INSTALL_DIR} ${DESTDIR}/boot/minix/.temp
# mod_0 is used to make alphabetical order equal to the boot order
@n=0; \
for i in ${PROGRAMS}; \
do \
n=`expr $$n + 1`; \
[ "$$n" -ge 10 ] && prefix="mod" || prefix="mod0"; \
newname="${DESTDIR}/boot/minix/.temp/$${prefix}$${n}_`basename $$i`"; \
${INSTALL_FILE} $$i $$newname; \
echo ${INSTALL_FILE} $$i $$newname; \
done
@${INSTALL_FILE} ${KERNEL} ${DESTDIR}/boot/minix/.temp/
@if [ "${MKINSTALLBOOT:Uno}" != "no" ] ; then \
${STRIP} -s ${DESTDIR}/boot/minix/.temp/* ; \
gzip ${DESTDIR}/boot/minix/.temp/mod* ; \
${HOST_SH} mkboot hdboot ${DESTDIR}; \
${HOST_SH} ../minix/commands/update_bootcfg/update_bootcfg.sh;\
fi
hdboot: services .WAIT do-hdboot
clean:
${MAKE} -C ${NETBSDSRCDIR}/lib $@
${MAKE} -C ${NETBSDSRCDIR}/minix/kernel $@
${MAKE} -C ${NETBSDSRCDIR}/minix/fs $@
${MAKE} -C ${NETBSDSRCDIR}/minix/net $@
${MAKE} -C ${NETBSDSRCDIR}/minix/servers $@
${MAKE} -C ${NETBSDSRCDIR}/minix/drivers $@
${MAKE} -C ${NETBSDSRCDIR}/sbin $@
${MAKE} -C ${NETBSDSRCDIR}/minix/sbin $@
rm -rf ${GEN_FILES}
# LSC: For STRIP and HOST_SH
.include <bsd.sys.mk>

View File

@ -1,209 +0,0 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
#
# Source settings if present
#
: ${SETTINGS_MINIX=.settings}
if [ -f "${SETTINGS_MINIX}" ]
then
echo "Sourcing settings from ${SETTINGS_MINIX}"
# Display the content (so we can check in the build logs
# what the settings contain.
cat ${SETTINGS_MINIX} | sed "s,^,CONTENT ,g"
. ${SETTINGS_MINIX}
fi
: ${ARCH=evbearm-el}
: ${OBJ=../obj.${ARCH}}
: ${TOOLCHAIN_TRIPLET=arm-elf32-minix-}
: ${BUILDSH=build.sh}
: ${SETS="minix-base minix-comp minix-games minix-man minix-tests tests"}
: ${IMG=minix_arm_sd.img}
# ARM definitions:
: ${BUILDVARS=-V MKGCCCMDS=yes -V MKLLVM=no}
# These BUILDVARS are for building with LLVM:
#: ${BUILDVARS=-V MKLIBCXX=no -V MKKYUA=no -V MKATF=no -V MKLLVMCMDS=no}
: ${FAT_SIZE=$(( 10*(2**20) / 512))} # This is in sectors
# Beagleboard-xm
: ${U_BOOT_BIN_DIR=build/omap3_beagle/}
: ${CONSOLE=tty02}
# BeagleBone (and black)
#: ${U_BOOT_BIN_DIR=build/am335x_evm/}
#: ${CONSOLE=tty00}
#
# We host u-boot binaries.
#
: ${MLO=MLO}
: ${UBOOT=u-boot.img}
U_BOOT_GIT_VERSION=cb5178f12787c690cb1c888d88733137e5a47b15
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
if [ -n "$BASE_URL" ]
then
#we no longer download u-boot but do a checkout
#BASE_URL used to be the base url for u-boot
#Downloads
echo "Warning:** Setting BASE_URL (u-boot) is no longer possible use U_BOOT_BIN_DIR"
echo "Look in ${RELEASETOOLSDIR}/arm_sdimage.sh for suggested values"
exit 1
fi
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:${PATH}
# we create a disk image of about 2 gig's
# for alignment reasons, prefer sizes which are multiples of 4096 bytes
: ${IMG_SIZE=$(( 2*(2**30) ))}
: ${ROOT_SIZE=$(( 64*(2**20) ))}
: ${HOME_SIZE=$(( 128*(2**20) ))}
: ${USR_SIZE=$(( 1792*(2**20) ))}
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
# all sizes are written in 512 byte blocks
ROOTSIZEARG="-b $((${ROOT_SIZE} / 512 / 8))"
USRSIZEARG="-b $((${USR_SIZE} / 512 / 8))"
HOMESIZEARG="-b $((${HOME_SIZE} / 512 / 8))"
# where the kernel & boot modules will be
MODDIR=${DESTDIR}/boot/minix/.temp
echo "Building work directory..."
build_workdir "$SETS"
echo "Adding extra files..."
# create a fstab entry in /etc
cat >${ROOT_DIR}/etc/fstab <<END_FSTAB
/dev/c0d0p2 /usr mfs rw 0 2
/dev/c0d0p3 /home mfs rw 0 2
none /sys devman rw,rslabel=devman 0 0
none /dev/pts ptyfs rw,rslabel=ptyfs 0 0
END_FSTAB
add_file_spec "etc/fstab" extra.fstab
echo "Bundling packages..."
bundle_packages "$BUNDLE_PACKAGES"
echo "Creating specification files..."
create_input_spec
create_protos "usr home"
# Download the stage 1 bootloader and u-boot
#
${RELEASETOOLSDIR}/fetch_u-boot.sh -o ${RELEASETOOLSDIR}/u-boot -n $U_BOOT_GIT_VERSION
# Clean image
if [ -f ${IMG} ] # IMG might be a block device
then
rm -f ${IMG}
fi
#
# Create the empty image where we later will put the partitions in.
# Make sure it is at least 2GB, otherwise the SD card will not be detected
# correctly in qemu / HW.
#
dd if=/dev/zero of=${IMG} bs=512 count=1 seek=$((($IMG_SIZE / 512) -1))
#
# Generate /root, /usr and /home partition images.
#
echo "Writing disk image..."
FAT_START=2048 # those are sectors
ROOT_START=$(($FAT_START + $FAT_SIZE))
echo " * ROOT"
_ROOT_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -d ${ROOTSIZEARG} -I $((${ROOT_START}*512)) ${IMG} ${WORK_DIR}/proto.root)
_ROOT_SIZE=$(($_ROOT_SIZE / 512))
USR_START=$((${ROOT_START} + ${_ROOT_SIZE}))
echo " * USR"
_USR_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -d ${USRSIZEARG} -I $((${USR_START}*512)) ${IMG} ${WORK_DIR}/proto.usr)
_USR_SIZE=$(($_USR_SIZE / 512))
HOME_START=$((${USR_START} + ${_USR_SIZE}))
echo " * HOME"
_HOME_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -d ${HOMESIZEARG} -I $((${HOME_START}*512)) ${IMG} ${WORK_DIR}/proto.home)
_HOME_SIZE=$(($_HOME_SIZE / 512))
echo " * BOOT"
rm -rf ${ROOT_DIR}/*
cp ${RELEASETOOLSDIR}/u-boot/${U_BOOT_BIN_DIR}/MLO ${ROOT_DIR}/
cp ${RELEASETOOLSDIR}/u-boot/${U_BOOT_BIN_DIR}/u-boot.img ${ROOT_DIR}/
# Create a uEnv.txt file
# -n default to network boot
# -p add a prefix to the network booted files (e.g. xm/"
# -c set console e.g. tty02 or tty00
# -v set verbosity e.g. 0 to 3
#${RELEASETOOLSDIR}/gen_uEnv.txt.sh -c ${CONSOLE} -n -p bb/ > ${WORK_DIR}/uEnv.txt
${RELEASETOOLSDIR}/gen_uEnv.txt.sh -c ${CONSOLE} > ${ROOT_DIR}/uEnv.txt
# Do some last processing of the kernel and servers and then put them on the FAT
# partition.
${CROSS_PREFIX}objcopy ${OBJ}/minix/kernel/kernel -O binary ${ROOT_DIR}/kernel.bin
for f in servers/vm/vm servers/rs/rs servers/pm/pm servers/sched/sched \
servers/vfs/vfs servers/ds/ds servers/mib/mib fs/pfs/pfs fs/mfs/mfs \
../sbin/init/init drivers/tty/tty/tty drivers/storage/memory/memory
do
fn=`basename $f`.elf
cp ${OBJ}/minix/${f} ${ROOT_DIR}/${fn}
${CROSS_PREFIX}strip -s ${ROOT_DIR}/${fn}
done
cat >${WORK_DIR}/boot.mtree <<EOF
. type=dir
./MLO type=file
./u-boot.img type=file
./uEnv.txt type=file
./kernel.bin type=file
./ds.elf type=file
./rs.elf type=file
./pm.elf type=file
./sched.elf type=file
./vfs.elf type=file
./memory.elf type=file
./tty.elf type=file
./mib.elf type=file
./vm.elf type=file
./pfs.elf type=file
./mfs.elf type=file
./init.elf type=file
EOF
#
# Create the FAT partition, which contains the bootloader files, kernel and modules
#
${CROSS_TOOLS}/nbmakefs -t msdos -s ${FAT_SIZE}b -o F=16,c=1 \
-F ${WORK_DIR}/boot.mtree ${WORK_DIR}/fat.img ${ROOT_DIR}
#
# Write the partition table using the natively compiled
# minix partition utility
#
${CROSS_TOOLS}/nbpartition -f -m ${IMG} ${FAT_START} \
"c:${FAT_SIZE}*" 81:${_ROOT_SIZE} 81:${_USR_SIZE} 81:${_HOME_SIZE}
#
# Merge the partitions into a single image.
#
echo "Merging file systems"
dd if=${WORK_DIR}/fat.img of=${IMG} seek=$FAT_START conv=notrunc
echo "Disk image at `pwd`/${IMG}"
echo "To boot this image on kvm:"
echo "qemu-system-arm -M beaglexm -serial stdio -drive if=sd,cache=writeback,file=`pwd`/${IMG}"

View File

@ -1,52 +0,0 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
: ${ARCH=i386}
: ${OBJ=../obj.${ARCH}}
: ${TOOLCHAIN_TRIPLET=i586-elf32-minix-}
: ${BUILDSH=build.sh}
: ${IMG=minix_pkgsrc.iso}
: ${SETS=}
: ${CREATE_IMAGE_ONLY=1}
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
echo "Building work directory..."
build_workdir "$SETS"
echo "Bundling packages..."
bundle_packages "$BUNDLE_PACKAGES"
echo "Creating specification files..."
cat > ${WORK_DIR}/extra.base <<EOF
. type=dir uid=0 gid=0 mode=0755
./usr type=dir uid=0 gid=0 mode=0755
EOF
create_input_spec
create_protos
# Clean image
if [ -f ${IMG} ] # IMG might be a block device
then
rm -f ${IMG}
fi
echo "Writing ISO..."
${CROSS_TOOLS}/nbmakefs -t cd9660 -F ${WORK_DIR}/input -o "rockridge,label=MINIX_PKGSRC" ${IMG} ${ROOT_DIR}
echo ""
echo "ISO image at `pwd`/${IMG}"

View File

@ -1,91 +0,0 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
: ${ARCH=i386}
: ${OBJ=../obj.${ARCH}}
: ${TOOLCHAIN_TRIPLET=i586-elf32-minix-}
: ${BUILDSH=build.sh}
: ${SETS="minix-base"}
: ${IMG=minix_x86.iso}
: ${BUNDLE_SETS=1}
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
echo "Building work directory..."
build_workdir "$SETS"
echo "Adding extra files..."
workdir_add_cd_files
# add kernel
workdir_add_kernel minix_default
# add boot.cfg
cat >${ROOT_DIR}/boot.cfg <<END_BOOT_CFG
banner=Welcome to the MINIX 3 installation CD
banner================================================================================
banner=
menu=Regular MINIX 3:multiboot /boot/minix_default/kernel bootcd=1 cdproberoot=1
menu=Regular MINIX 3 (with AHCI):multiboot /boot/minix_default/kernel bootcd=1 cdproberoot=1 ahci=yes
menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
clear=1
timeout=10
default=1
load=/boot/minix_default/mod01_ds
load=/boot/minix_default/mod02_rs
load=/boot/minix_default/mod03_pm
load=/boot/minix_default/mod04_sched
load=/boot/minix_default/mod05_vfs
load=/boot/minix_default/mod06_memory
load=/boot/minix_default/mod07_tty
load=/boot/minix_default/mod08_mib
load=/boot/minix_default/mod09_vm
load=/boot/minix_default/mod10_pfs
load=/boot/minix_default/mod11_mfs
load=/boot/minix_default/mod12_init
END_BOOT_CFG
add_file_spec "boot.cfg" extra.cdfiles
# set correct message of the day (log in and install tip)
cp releasetools/release/cd/etc/issue ${ROOT_DIR}/etc/issue
add_file_spec "etc/issue" extra.cdfiles
echo "Bundling packages..."
bundle_packages "$BUNDLE_PACKAGES"
echo "Creating specification files..."
create_input_spec
create_protos
# Clean image
if [ -f ${IMG} ] # IMG might be a block device
then
rm -f ${IMG}
fi
echo "Writing ISO..."
${CROSS_TOOLS}/nbmakefs -t cd9660 -F ${WORK_DIR}/input -o "rockridge,bootimage=i386;${DESTDIR}/usr/mdec/bootxx_cd9660,label=MINIX" ${IMG} ${ROOT_DIR}
echo ""
echo "ISO image at `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm using the bootloader:"
echo "qemu-system-i386 --enable-kvm -cdrom `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm:"
echo "cd ${MODDIR} && qemu-system-i386 --enable-kvm -kernel kernel -append \"bootcd=1 cdproberoot=1\" -initrd \"${mods}\" -cdrom `pwd`/${IMG}"

View File

@ -1,136 +0,0 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
: ${ARCH=i386}
: ${OBJ=../obj.${ARCH}}
: ${TOOLCHAIN_TRIPLET=i586-elf32-minix-}
: ${BUILDSH=build.sh}
: ${SETS="minix-base minix-comp minix-games minix-man minix-tests tests"}
: ${IMG=minix_x86.img}
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
# we create a disk image of about 2 gig's
# for alignment reasons, prefer sizes which are multiples of 4096 bytes
: ${BOOTXX_SECS=32}
: ${ROOT_SIZE=$(( 128*(2**20) - ${BOOTXX_SECS} * 512 ))}
: ${HOME_SIZE=$(( 128*(2**20) ))}
: ${USR_SIZE=$(( 1792*(2**20) ))}
: ${EFI_SIZE=$(( 0 ))}
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
echo "Building work directory..."
build_workdir "$SETS"
echo "Adding extra files..."
workdir_add_hdd_files
# add kernels
add_link_spec "boot/minix_latest" "minix_default" extra.kernel
workdir_add_kernel minix_default
workdir_add_kernel minix/$RELEASE_VERSION
# add boot.cfg
cat >${ROOT_DIR}/boot.cfg <<END_BOOT_CFG
menu=Start MINIX 3:load_mods /boot/minix_default/mod*; multiboot /boot/minix_default/kernel rootdevname=c0d0p0
menu=Start latest MINIX 3:load_mods /boot/minix_latest/mod*; multiboot /boot/minix_latest/kernel rootdevname=c0d0p0
menu=Start latest MINIX 3 in single user mode:load_mods /boot/minix_latest/mod*; multiboot /boot/minix_latest/kernel rootdevname=c0d0p0 bootopts=-s
menu=Start MINIX 3 ALIX:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel rootdevname=c0d0p0 console=tty00 consdev=com0 ata_no_dma=1
menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
clear=1
timeout=5
default=2
menu=Start MINIX 3 ($RELEASE_VERSION):load_mods /boot/minix/$RELEASE_VERSION/mod*; multiboot /boot/minix/$RELEASE_VERSION/kernel rootdevname=c0d0p0
END_BOOT_CFG
add_file_spec "boot.cfg" extra.boot
echo "Bundling packages..."
bundle_packages "$BUNDLE_PACKAGES"
echo "Creating specification files..."
create_input_spec
create_protos "usr home"
# Clean image
if [ -f ${IMG} ] # IMG might be a block device
then
rm -f ${IMG}
fi
#
# Generate /root, /usr and /home partition images.
#
echo "Writing disk image..."
# all sizes are written in 512 byte blocks
ROOTSIZEARG="-b $((${ROOT_SIZE} / 512 / 8))"
USRSIZEARG="-b $((${USR_SIZE} / 512 / 8))"
HOMESIZEARG="-b $((${HOME_SIZE} / 512 / 8))"
if [ ${EFI_SIZE} -ge 512 ]
then
fetch_and_build_grub
: ${EFI_DIR=$OBJ/efi}
rm -rf ${EFI_DIR} && mkdir -p ${EFI_DIR}/boot/minix_default ${EFI_DIR}/boot/efi
create_grub_cfg
cp ${MODDIR}/* ${EFI_DIR}/boot/minix_default/
cp ${RELEASETOOLSDIR}/grub/grub-core/booti386.efi ${EFI_DIR}/boot/efi
cp ${RELEASETOOLSDIR}/grub/grub-core/*.mod ${EFI_DIR}/boot/efi
fi
ROOT_START=${BOOTXX_SECS}
echo " * ROOT"
_ROOT_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -d ${ROOTSIZEARG} -I $((${ROOT_START}*512)) ${IMG} ${WORK_DIR}/proto.root)
_ROOT_SIZE=$(($_ROOT_SIZE / 512))
USR_START=$((${ROOT_START} + ${_ROOT_SIZE}))
echo " * USR"
_USR_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -d ${USRSIZEARG} -I $((${USR_START}*512)) ${IMG} ${WORK_DIR}/proto.usr)
_USR_SIZE=$(($_USR_SIZE / 512))
HOME_START=$((${USR_START} + ${_USR_SIZE}))
echo " * HOME"
_HOME_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -d ${HOMESIZEARG} -I $((${HOME_START}*512)) ${IMG} ${WORK_DIR}/proto.home)
_HOME_SIZE=$(($_HOME_SIZE / 512))
#
# Write the partition table using the natively compiled
# minix partition utility
#
if [ ${EFI_SIZE} -ge 512 ]
then
dd if=/dev/zero bs=${EFI_SIZE} count=1 > ${OBJ}/efi.img
EFI_START=$((${HOME_START} + ${_HOME_SIZE}))
echo " * EFI"
${CROSS_TOOLS}/nbmakefs -t msdos -s ${EFI_SIZE} -o "F=32,c=1" ${OBJ}/efi.img ${EFI_DIR}
dd if=${OBJ}/efi.img >> ${IMG}
${CROSS_TOOLS}/nbpartition -m ${IMG} ${BOOTXX_SECS} 81:${_ROOT_SIZE}* 81:${_USR_SIZE} 81:${_HOME_SIZE} EF:1+
else
${CROSS_TOOLS}/nbpartition -m ${IMG} ${BOOTXX_SECS} 81:${_ROOT_SIZE}* 81:${_USR_SIZE} 81:${_HOME_SIZE}
fi
${CROSS_TOOLS}/nbinstallboot -f -m ${ARCH} ${IMG} ${DESTDIR}/usr/mdec/bootxx_minixfs3
echo ""
echo "Disk image at `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm using the bootloader:"
echo "qemu-system-i386 --enable-kvm -m 256 -hda `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm:"
echo "cd ${MODDIR} && qemu-system-i386 --enable-kvm -m 256M -kernel kernel -append \"rootdevname=c0d0p0\" -initrd \"${mods}\" -hda `pwd`/${IMG}"
echo "To boot this image on kvm with EFI (tianocore OVMF):"
echo "qemu-system-i386 -L . -bios OVMF-i32.fd -m 256M -drive file=minix_x86.img,if=ide,format=raw"

View File

@ -1,57 +0,0 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
: ${ARCH=i386}
: ${OBJ=../obj.${ARCH}}
: ${TOOLCHAIN_TRIPLET=i586-elf32-minix-}
: ${BUILDSH=build.sh}
: ${SETS="minix-base"}
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
#: ${RAMDISK_SIZE=$(( 200*(2**20) ))}
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
# where the kernel & boot modules will be
MODDIR=${DESTDIR}/boot/minix/.temp
echo "Building work directory..."
build_workdir "$SETS"
echo "Adding extra files..."
workdir_add_ramdisk_files
# set correct message of the day (log in and install tip)
cp releasetools/release/ramdisk/etc/issue ${ROOT_DIR}/etc/issue
add_file_spec "etc/issue" extra.cdfiles
echo "Bundling packages..."
bundle_packages "$BUNDLE_PACKAGES"
echo "Creating specification files..."
create_input_spec
create_protos
echo "Writing ramdisk image..."
# add the other modules for boot
cp ${MODDIR}/* ${WORK_DIR}
create_ramdisk_image ${RAMDISK_SIZE}
echo ""
echo "RAM image modules at ${WORK_DIR}"
echo ""
echo "To boot this image on kvm:"
echo "cd ${WORK_DIR} && qemu-system-i386 --enable-kvm -m 1G -kernel kernel -append \"bootramdisk=1\" -initrd \"${mods}\""

View File

@ -1,105 +0,0 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
: ${ARCH=i386}
: ${OBJ=../obj.${ARCH}}
: ${TOOLCHAIN_TRIPLET=i586-elf32-minix-}
: ${BUILDSH=build.sh}
: ${SETS="minix-base"}
: ${IMG=minix_x86_usb.img}
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
#: ${RAMDISK_SIZE=$(( 200*(2**20) ))}
: ${BOOTXX_SECS=32}
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
# where the kernel & boot modules will be
MODDIR=${DESTDIR}/boot/minix/.temp
echo "Building work directory..."
build_workdir "$SETS"
echo "Adding extra files..."
workdir_add_ramdisk_files
# set correct message of the day (log in and install tip)
cp releasetools/release/ramdisk/etc/issue ${ROOT_DIR}/etc/issue
add_file_spec "etc/issue" extra.cdfiles
echo "Bundling packages..."
bundle_packages "$BUNDLE_PACKAGES"
echo "Creating specification files..."
create_input_spec
create_protos
echo "Writing ramdisk image..."
# add the other modules for boot
cp ${MODDIR}/* ${WORK_DIR}
create_ramdisk_image ${RAMDISK_SIZE}
echo "Writing USB image..."
# clear ROOT_DIR
rm -rf ${ROOT_DIR}/*
echo ". type=dir uid=0 gid=0 mode=0755" > ${WORK_DIR}/extra.boot
# move all modules back to ROOT_DIR
mv ${WORK_DIR}/kernel ${WORK_DIR}/mod* ${ROOT_DIR}/
add_file_spec "kernel" extra.boot
for i in ${ROOT_DIR}/mod*; do
add_file_spec $(basename $i) extra.boot
done
# add boot.cfg
cat >${ROOT_DIR}/boot.cfg <<END_BOOT_CFG
menu=Start MINIX 3:load_mods /mod*; multiboot /kernel bootramdisk=1
menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
clear=1
timeout=5
default=1
END_BOOT_CFG
add_file_spec "boot.cfg" extra.boot
# add boot monitor
cp ${DESTDIR}/usr/mdec/boot_monitor ${ROOT_DIR}/boot_monitor
add_file_spec "boot_monitor" extra.boot
# create proto file
cat ${WORK_DIR}/extra.boot | ${CROSS_TOOLS}/nbtoproto -b ${ROOT_DIR} -o ${WORK_DIR}/proto.boot
ROOT_START=${BOOTXX_SECS}
_ROOT_SIZE=$(${CROSS_TOOLS}/nbmkfs.mfs -I $((${ROOT_START} * 512)) ${IMG} ${WORK_DIR}/proto.boot)
_ROOT_SIZE=$(($_ROOT_SIZE / 512))
#
# Write the partition table using the natively compiled
# minix partition utility
#
${CROSS_TOOLS}/nbpartition -m ${IMG} ${BOOTXX_SECS} 81:${_ROOT_SIZE}
${CROSS_TOOLS}/nbinstallboot -f -m ${ARCH} ${IMG} ${DESTDIR}/usr/mdec/bootxx_minixfs3
echo ""
echo "Universally Supported Boot disk image at `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm using the bootloader:"
# This is really, really slow.
# echo "qemu-system-i386 --enable-kvm -m 1G -usbdevice disk:`pwd`/${IMG}"
echo "qemu-system-i386 --enable-kvm -m 1G -hda `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm:"
echo "cd ${ROOT_DIR} && qemu-system-i386 --enable-kvm -m 1G -kernel kernel -append \"bootramdisk=1\" -initrd \"${mods}\""