diff --git a/sbin/mount_kernfs/mount_kernfs.8 b/sbin/mount_kernfs/mount_kernfs.8 index c71054ddc995..407521cfe9a3 100644 --- a/sbin/mount_kernfs/mount_kernfs.8 +++ b/sbin/mount_kernfs/mount_kernfs.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: mount_kernfs.8,v 1.13 2003/08/07 10:04:28 agc Exp $ +.\" $NetBSD: mount_kernfs.8,v 1.14 2003/09/08 06:52:00 itojun Exp $ .\" .\" Copyright (c) 1992, 1993, 1994 .\" The Regents of the University of California. All rights reserved. @@ -33,7 +33,7 @@ .\" .\" @(#)mount_kernfs.8 8.2 (Berkeley) 3/27/94 .\" -.Dd March 27, 1994 +.Dd September 8, 2003 .Dt MOUNT_KERNFS 8 .Os .Sh NAME @@ -83,6 +83,20 @@ The hostname can be changed by writing to this file. A trailing newline will be stripped from the hostname being written. .It Pa hz the frequency of the system clock (decimal ASCII). +.It Pa ipsecsa +the directory contains IPsec security associations (SA) in +.Dv PF_KEY +format. +Filenames are SPI in decimal number. +The content of files can be inspected by using +.Xr setkey 8 . +.It Pa ipsecsp +the directory contains IPsec security policies in +.Dv PF_KEY +format. +Filenames are security policy ID in decimal number. +The content of files can be inspected by using +.Xr setkey 8 . .It Pa loadavg the 1, 5 and 15 minute load average in kernel fixed-point format. The final integer is the fix-point scaling factor. @@ -124,9 +138,11 @@ can be generated by running: .Sh SEE ALSO .Xr mount 2 , .Xr unmount 2 , +.Xr ipsec 4 , .Xr fstab 5 , .Xr dmesg 8 , .Xr mount 8 , +.Xr setkey 8 , .Xr syslogd 8 .Sh HISTORY The @@ -135,3 +151,6 @@ utility first appeared in .Bx 4.4 . .Sh BUGS This filesystem may not be NFS-exported. +.Pp +.Xr lkm 4 +version does not support IPsec-related files/directories. diff --git a/sys/lkm/vfs/miscfs/kernfs/Makefile b/sys/lkm/vfs/miscfs/kernfs/Makefile index 20d484becad1..0d5157ff5451 100644 --- a/sys/lkm/vfs/miscfs/kernfs/Makefile +++ b/sys/lkm/vfs/miscfs/kernfs/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.10 2001/12/12 12:06:48 lukem Exp $ +# $NetBSD: Makefile,v 1.11 2003/09/08 06:51:59 itojun Exp $ .include "../Makefile.inc" @@ -7,6 +7,6 @@ KMOD= kernfs SRCS= lkminit_vfs.c -SRCS+= kernfs_vfsops.c kernfs_vnops.c +SRCS+= kernfs_vfsops.c kernfs_vnops.c kernfs_subr.c .include diff --git a/sys/miscfs/kernfs/files.kernfs b/sys/miscfs/kernfs/files.kernfs index 089f915688a1..30aa8921f1ce 100644 --- a/sys/miscfs/kernfs/files.kernfs +++ b/sys/miscfs/kernfs/files.kernfs @@ -1,6 +1,7 @@ -# $NetBSD: files.kernfs,v 1.1 2002/04/16 23:14:07 thorpej Exp $ +# $NetBSD: files.kernfs,v 1.2 2003/09/08 06:51:53 itojun Exp $ deffs fs_kernfs.h KERNFS # XXX +file miscfs/kernfs/kernfs_subr.c kernfs file miscfs/kernfs/kernfs_vfsops.c kernfs file miscfs/kernfs/kernfs_vnops.c kernfs diff --git a/sys/miscfs/kernfs/kernfs.h b/sys/miscfs/kernfs/kernfs.h index f0bfd79294b5..f0cc001ae756 100644 --- a/sys/miscfs/kernfs/kernfs.h +++ b/sys/miscfs/kernfs/kernfs.h @@ -1,4 +1,4 @@ -/* $NetBSD: kernfs.h,v 1.17 2003/08/07 16:32:37 agc Exp $ */ +/* $NetBSD: kernfs.h,v 1.18 2003/09/08 06:51:53 itojun Exp $ */ /* * Copyright (c) 1992, 1993 @@ -37,36 +37,87 @@ #define _PATH_KERNFS "/kern" /* Default mountpoint */ #ifdef _KERNEL -struct kernfs_mount { - struct vnode *kf_root; /* Root node */ -}; +#include +/* + * The different types of node in a kernfs filesystem + */ +typedef enum { + Pkern, /* the filesystem itself (.) */ + Proot, /* the filesystem root (..) */ + Pnull, /* none aplicable */ + Ptime, /* boottime */ + Pint, /* integer */ + Pstring, /* string */ + Phostname, /* hostname */ + Pavenrun, /* loadavg */ + Pdevice, /* device file (rootdev/rrootdev) */ + Pmsgbuf, /* msgbuf */ + Pipsecsadir, /* ipsec security association (top dir) */ + Pipsecspdir, /* ipsec security policy (top dir) */ + Pipsecsa, /* ipsec security association entry */ + Pipsecsp, /* ipsec security policy entry */ +} kfstype; + +/* + * control data for the kern file system. + */ struct kern_target { - u_char kt_type; - u_char kt_namlen; - const char *kt_name; - void *kt_data; -#define KTT_NULL 1 -#define KTT_TIME 5 -#define KTT_INT 17 -#define KTT_STRING 31 -#define KTT_HOSTNAME 47 -#define KTT_AVENRUN 53 -#define KTT_DEVICE 71 -#define KTT_MSGBUF 89 - u_char kt_tag; - u_char kt_vtype; - mode_t kt_mode; + u_char kt_type; + u_char kt_namlen; + const char *kt_name; + void *kt_data; + kfstype kt_tag; + u_char kt_vtype; + mode_t kt_mode; }; struct kernfs_node { - const struct kern_target *kf_kt; + LIST_ENTRY(kernfs_node) kfs_hash; /* hash chain */ + TAILQ_ENTRY(kernfs_node) kfs_list; /* flat list */ + struct vnode *kfs_vnode; /* vnode associated with this pfsnode */ + kfstype kfs_type; /* type of procfs node */ + mode_t kfs_mode; /* mode bits for stat() */ + long kfs_fileno; /* unique file id */ + u_int32_t kfs_value; /* SA id or SP id (Pint) */ + const struct kern_target *kfs_kt; + void *kfs_v; /* pointer to secasvar/secpolicy/mbuf */ + long kfs_cookie; /* fileno cookie */ }; -#define VFSTOKERNFS(mp) ((struct kernfs_mount *)((mp)->mnt_data)) -#define VTOKERN(vp) ((struct kernfs_node *)(vp)->v_data) +struct kernfs_mount { + TAILQ_HEAD(, kernfs_node) nodelist; + long fileno_cookie; +}; +#define UIO_MX 32 + +#define KERNFS_FILENO(kt, typ, cookie) \ + ((kt) ? 2 + ((kt) - &kern_targets[0]) \ + : (((cookie) << 6) | ((typ) + nkern_targets))) + +#define VFSTOKERNFS(mp) ((struct kernfs_mount *)((mp)->mnt_data)) +#define VTOKERN(vp) ((struct kernfs_node *)(vp)->v_data) +#define KERNFSTOV(kfs) ((kfs)->kfs_vnode) + +extern const struct kern_target kern_targets[]; +extern int nkern_targets; extern int (**kernfs_vnodeop_p) __P((void *)); extern struct vfsops kernfs_vfsops; extern dev_t rrootdev; + +struct secasvar; +struct secpolicy; + +int kernfs_root __P((struct mount *, struct vnode **)); + +void kernfs_hashinit __P((void)); +void kernfs_hashreinit __P((void)); +void kernfs_hashdone __P((void)); +int kernfs_freevp __P((struct vnode *)); +int kernfs_allocvp __P((struct mount *, struct vnode **, kfstype, + const struct kern_target *, u_int32_t)); + +void kernfs_revoke_sa __P((struct secasvar *)); +void kernfs_revoke_sp __P((struct secpolicy *)); #endif /* _KERNEL */ diff --git a/sys/miscfs/kernfs/kernfs_subr.c b/sys/miscfs/kernfs/kernfs_subr.c new file mode 100644 index 000000000000..920eb880ccd8 --- /dev/null +++ b/sys/miscfs/kernfs/kernfs_subr.c @@ -0,0 +1,438 @@ +/* $NetBSD: kernfs_subr.c,v 1.1 2003/09/08 06:51:53 itojun Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kernfs_subr.c 8.6 (Berkeley) 5/14/95 + */ + +/* + * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1993 Jan-Simon Pendry + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kernfs_subr.c 8.6 (Berkeley) 5/14/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: kernfs_subr.c,v 1.1 2003/09/08 06:51:53 itojun Exp $"); + +#ifdef _KERNEL_OPT +#include "opt_ipsec.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef IPSEC +#include +#include +#include +#include +#include +#include +#endif + +void kernfs_hashins __P((struct kernfs_node *)); +void kernfs_hashrem __P((struct kernfs_node *)); +struct vnode *kernfs_hashget __P((kfstype, struct mount *, u_int32_t)); + +static LIST_HEAD(kfs_hashhead, kernfs_node) *kfs_hashtbl; +static u_long kfs_ihash; /* size of hash table - 1 */ +#define KFSVALUEHASH(v) ((v) & kfs_ihash) + +static struct lock kfs_hashlock; +static struct simplelock kfs_hash_slock; + +#define ISSET(t, f) ((t) & (f)) + +/* + * allocate a kfsnode/vnode pair. the vnode is + * referenced, and locked. + * + * the kfs_type, kfs_value and mount point uniquely + * identify a kfsnode. the mount point is needed + * because someone might mount this filesystem + * twice. + * + * all kfsnodes are maintained on a singly-linked + * list. new nodes are only allocated when they cannot + * be found on this list. entries on the list are + * removed when the vfs reclaim entry is called. + * + * a single lock is kept for the entire list. this is + * needed because the getnewvnode() function can block + * waiting for a vnode to become free, in which case there + * may be more than one process trying to get the same + * vnode. this lock is only taken if we are going to + * call getnewvnode, since the kernel itself is single-threaded. + * + * if an entry is found on the list, then call vget() to + * take a reference. this is done because there may be + * zero references to it and so it needs to removed from + * the vnode free list. + */ +int +kernfs_allocvp(mp, vpp, kfs_type, kt, value) + struct mount *mp; + struct vnode **vpp; + kfstype kfs_type; + const struct kern_target *kt; + u_int32_t value; +{ + struct kernfs_node *kfs = NULL, *kfsp; + struct vnode *vp = NULL; + int error; + long *cookie; + + do { + if ((*vpp = kernfs_hashget(kfs_type, mp, value)) != NULL) + return (0); + } while (lockmgr(&kfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0)); + + if (kfs_type == Pdevice) { + /* /kern/rootdev = look for device and obey */ + /* /kern/rrootdev = look for device and obey */ + dev_t *dp; + struct vnode *fvp; + +#ifdef DIAGNOSTIC + if (!kt) + panic("kernfs: kt == NULL for Pdevice"); +#endif + dp = kt->kt_data; + loop: + if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) { + lockmgr(&kfs_hashlock, LK_RELEASE, NULL); + return (ENOENT); + } + vp = fvp; + if (vget(fvp, LK_EXCLUSIVE)) + goto loop; + *vpp = vp; + lockmgr(&kfs_hashlock, LK_RELEASE, NULL); + return (0); + } + + if ((error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &vp)) != 0) { + *vpp = NULL; + lockmgr(&kfs_hashlock, LK_RELEASE, NULL); + return (error); + } + + MALLOC(kfs, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); + memset(kfs, 0, sizeof(*kfs)); + vp->v_data = kfs; + cookie = &(VFSTOKERNFS(mp)->fileno_cookie); +again: + TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) { + if (kfsp->kfs_cookie == *cookie) { + (*cookie) ++; + goto again; + } + if (TAILQ_NEXT(kfsp, kfs_list)) { + if (kfsp->kfs_cookie < *cookie && + *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) + break; + if (kfsp->kfs_cookie + 1 < + TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) { + *cookie = kfsp->kfs_cookie + 1; + break; + } + } + } + + kfs->kfs_cookie = *cookie; + + if (kfsp) + TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs, + kfs_list); + else + TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list); + + kfs->kfs_type = kfs_type; + kfs->kfs_vnode = vp; + kfs->kfs_fileno = KERNFS_FILENO(kt, kfs_type, kfs->kfs_cookie); + kfs->kfs_value = value; + kfs->kfs_kt = kt; + + switch (kfs_type) { + case Pkern: /* /kern = dr-xr-xr-x */ + kfs->kfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; + vp->v_type = VDIR; + vp->v_flag = VROOT; + break; + + case Pnull: /* /kern/?? = -r--r--r-- */ + case Ptime: /* /kern/time = -r--r--r-- */ + case Pint: /* /kern/?? = -r--r--r-- */ + case Pstring: /* /kern/?? = -r--r--r-- */ + case Pavenrun: /* /kern/loadavg = -r--r--r-- */ + case Pmsgbuf: /* /kern/msgbuf = -r--r--r-- */ + kfs->kfs_mode = S_IRUSR|S_IRGRP|S_IROTH; + vp->v_type = VREG; + break; + + case Pipsecsadir: /* /kern/ipsecsa = dr-x------ */ + case Pipsecspdir: /* /kern/ipsecsp = dr-x------ */ + kfs->kfs_mode = S_IRUSR|S_IXUSR; + vp->v_type = VDIR; + break; + + case Pipsecsa: /* /kern/ipsecsa/N = -r-------- */ + case Pipsecsp: /* /kern/ipsecsp/N = -r-------- */ + kfs->kfs_mode = S_IRUSR; + vp->v_type = VREG; + break; + + case Phostname: /* /kern/hostname = -rw------- */ + kfs->kfs_mode = S_IRUSR|S_IWUSR; + vp->v_type = VREG; + break; + + default: + panic("kernfs_allocvp"); + } + + kernfs_hashins(kfs); + uvm_vnp_setsize(vp, 0); + lockmgr(&kfs_hashlock, LK_RELEASE, NULL); + + *vpp = vp; + return (0); +} + +int +kernfs_freevp(vp) + struct vnode *vp; +{ + struct kernfs_node *kfs = VTOKERN(vp); + + kernfs_hashrem(kfs); + TAILQ_REMOVE(&VFSTOKERNFS(vp->v_mount)->nodelist, kfs, kfs_list); + + FREE(vp->v_data, M_TEMP); + vp->v_data = 0; + return (0); +} + +/* + * Initialize kfsnode hash table. + */ +void +kernfs_hashinit() +{ + + lockinit(&kfs_hashlock, PINOD, "kfs_hashlock", 0, 0); + kfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT, + M_WAITOK, &kfs_ihash); + simple_lock_init(&kfs_hash_slock); +} + +void +kernfs_hashreinit() +{ + struct kernfs_node *pp; + struct kfs_hashhead *oldhash, *hash; + u_long i, oldmask, mask, val; + + hash = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT, M_WAITOK, + &mask); + + simple_lock(&kfs_hash_slock); + oldhash = kfs_hashtbl; + oldmask = kfs_ihash; + kfs_hashtbl = hash; + kfs_ihash = mask; + for (i = 0; i <= oldmask; i++) { + while ((pp = LIST_FIRST(&oldhash[i])) != NULL) { + LIST_REMOVE(pp, kfs_hash); + val = KFSVALUEHASH(pp->kfs_value); + LIST_INSERT_HEAD(&hash[val], pp, kfs_hash); + } + } + simple_unlock(&kfs_hash_slock); + hashdone(oldhash, M_UFSMNT); +} + +/* + * Free kfsnode hash table. + */ +void +kernfs_hashdone() +{ + + hashdone(kfs_hashtbl, M_UFSMNT); +} + +struct vnode * +kernfs_hashget(type, mp, value) + kfstype type; + struct mount *mp; + u_int32_t value; +{ + struct kfs_hashhead *ppp; + struct kernfs_node *pp; + struct vnode *vp; + +loop: + simple_lock(&kfs_hash_slock); + ppp = &kfs_hashtbl[KFSVALUEHASH(value)]; + LIST_FOREACH(pp, ppp, kfs_hash) { + vp = KERNFSTOV(pp); + if (pp->kfs_type == type && vp->v_mount == mp && + pp->kfs_value == value) { + simple_lock(&vp->v_interlock); + simple_unlock(&kfs_hash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) + goto loop; + return (vp); + } + } + simple_unlock(&kfs_hash_slock); + return (NULL); +} + +/* + * Insert the kfsnode into the hash table and lock it. + */ +void +kernfs_hashins(pp) + struct kernfs_node *pp; +{ + struct kfs_hashhead *ppp; + + /* lock the kfsnode, then put it on the appropriate hash list */ + lockmgr(&pp->kfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0); + + simple_lock(&kfs_hash_slock); + ppp = &kfs_hashtbl[KFSVALUEHASH(pp->kfs_value)]; + LIST_INSERT_HEAD(ppp, pp, kfs_hash); + simple_unlock(&kfs_hash_slock); +} + +/* + * Remove the kfsnode from the hash table. + */ +void +kernfs_hashrem(pp) + struct kernfs_node *pp; +{ + simple_lock(&kfs_hash_slock); + LIST_REMOVE(pp, kfs_hash); + simple_unlock(&kfs_hash_slock); +} + +#ifdef IPSEC +void +kernfs_revoke_sa(sav) + struct secasvar *sav; +{ + struct kernfs_node *kfs, *pnext; + struct vnode *vp; + struct kfs_hashhead *ppp; + struct mbuf *m; + + ppp = &kfs_hashtbl[KFSVALUEHASH(ntohl(sav->spi))]; + for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) { + vp = KERNFSTOV(kfs); + pnext = LIST_NEXT(kfs, kfs_hash); + if (vp->v_usecount > 0 && kfs->kfs_type == Pipsecsa && + kfs->kfs_value == ntohl(sav->spi)) { + m = key_setdumpsa_spi(sav->spi); + if (!m) + VOP_REVOKE(vp, REVOKEALL); + else + m_freem(m); + break; + } + } +} + +void +kernfs_revoke_sp(sp) + struct secpolicy *sp; +{ + struct kernfs_node *kfs, *pnext; + struct vnode *vp; + struct kfs_hashhead *ppp; + + ppp = &kfs_hashtbl[KFSVALUEHASH(sp->id)]; + for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) { + vp = KERNFSTOV(kfs); + pnext = LIST_NEXT(kfs, kfs_hash); + if (vp->v_usecount > 0 && kfs->kfs_type == Pipsecsa && + kfs->kfs_value == sp->id) + VOP_REVOKE(vp, REVOKEALL); + } +} +#endif diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c index ccdb925f87e2..9d1195a9bc83 100644 --- a/sys/miscfs/kernfs/kernfs_vfsops.c +++ b/sys/miscfs/kernfs/kernfs_vfsops.c @@ -1,4 +1,4 @@ -/* $NetBSD: kernfs_vfsops.c,v 1.53 2003/08/07 16:32:37 agc Exp $ */ +/* $NetBSD: kernfs_vfsops.c,v 1.54 2003/09/08 06:51:54 itojun Exp $ */ /* * Copyright (c) 1992, 1993, 1995 @@ -39,9 +39,9 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kernfs_vfsops.c,v 1.53 2003/08/07 16:32:37 agc Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kernfs_vfsops.c,v 1.54 2003/09/08 06:51:54 itojun Exp $"); -#if defined(_KERNEL_OPT) +#ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" #endif @@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: kernfs_vfsops.c,v 1.53 2003/08/07 16:32:37 agc Exp $ #include #include #include +#include #include #include @@ -62,13 +63,13 @@ MALLOC_DEFINE(M_KERNFSMNT, "kernfs mount", "kernfs mount structures"); dev_t rrootdev = NODEV; void kernfs_init __P((void)); +void kernfs_reinit __P((void)); void kernfs_done __P((void)); void kernfs_get_rrootdev __P((void)); int kernfs_mount __P((struct mount *, const char *, void *, struct nameidata *, struct proc *)); int kernfs_start __P((struct mount *, int, struct proc *)); int kernfs_unmount __P((struct mount *, int, struct proc *)); -int kernfs_root __P((struct mount *, struct vnode **)); int kernfs_statfs __P((struct mount *, struct statfs *, struct proc *)); int kernfs_quotactl __P((struct mount *, int, uid_t, caddr_t, struct proc *)); @@ -87,6 +88,13 @@ kernfs_init() #ifdef _LKM malloc_type_attach(M_KERNFSMNT); #endif + kernfs_hashinit(); +} + +void +kernfs_reinit() +{ + kernfs_hashreinit(); } void @@ -95,6 +103,7 @@ kernfs_done() #ifdef _LKM malloc_type_detach(M_KERNFSMNT); #endif + kernfs_hashdone(); } void @@ -111,13 +120,8 @@ kernfs_get_rrootdev() if (rootdev == NODEV) return; rrootdev = devsw_blk2chr(rootdev); - if (rrootdev != NODEV) { -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount: rootdev = %u.%u; rrootdev = %u.%u\n", - major(rootdev), minor(rootdev), major(rrootdev), minor(rrootdev)); -#endif + if (rrootdev != NODEV) return; - } rrootdev = NODEV; printf("kernfs_get_rrootdev: no raw root device\n"); } @@ -135,11 +139,11 @@ kernfs_mount(mp, path, data, ndp, p) { int error = 0; struct kernfs_mount *fmp; - struct vnode *rvp; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount(mp = %p)\n", mp); -#endif + if (UIO_MX & (UIO_MX - 1)) { + log(LOG_ERR, "kernfs: invalid directory entry size"); + return (EINVAL); + } if (mp->mnt_flag & MNT_GETARGS) return 0; @@ -149,27 +153,17 @@ kernfs_mount(mp, path, data, ndp, p) if (mp->mnt_flag & MNT_UPDATE) return (EOPNOTSUPP); - error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &rvp); - if (error) - return (error); - MALLOC(fmp, struct kernfs_mount *, sizeof(struct kernfs_mount), M_KERNFSMNT, M_WAITOK); - rvp->v_type = VDIR; - rvp->v_flag |= VROOT; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount: root vp = %p\n", rvp); -#endif - fmp->kf_root = rvp; - mp->mnt_flag |= MNT_LOCAL; + memset(fmp, 0, sizeof(*fmp)); + TAILQ_INIT(&fmp->nodelist); + mp->mnt_data = fmp; + mp->mnt_flag |= MNT_LOCAL; vfs_getnewfsid(mp); error = set_statfs_info(path, UIO_USERSPACE, "kernfs", UIO_SYSSPACE, mp, p); -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount: at %s\n", mp->mnt_stat.f_mntonname); -#endif kernfs_get_rrootdev(); return error; @@ -193,36 +187,13 @@ kernfs_unmount(mp, mntflags, p) { int error; int flags = 0; - struct vnode *rootvp = VFSTOKERNFS(mp)->kf_root; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_unmount(mp = %p)\n", mp); -#endif - - if (mntflags & MNT_FORCE) + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ - if (rootvp->v_usecount > 1) - return (EBUSY); -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_unmount: calling vflush\n"); -#endif - if ((error = vflush(mp, rootvp, flags)) != 0) + if ((error = vflush(mp, 0, flags)) != 0) return (error); -#ifdef KERNFS_DIAGNOSTIC - vprint("kernfs root", rootvp); -#endif - /* - * Clean out the old root vnode for reuse. - */ - vrele(rootvp); - vgone(rootvp); /* * Finally, throw away the kernfs_mount structure */ @@ -236,20 +207,9 @@ kernfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { - struct vnode *vp; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_root(mp = %p)\n", mp); -#endif - - /* - * Return locked reference to root. - */ - vp = VFSTOKERNFS(mp)->kf_root; - VREF(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - *vpp = vp; - return (0); + /* setup "." */ + return (kernfs_allocvp(mp, vpp, Pkern, &kern_targets[0], 0)); } int @@ -271,17 +231,13 @@ kernfs_statfs(mp, sbp, p) struct proc *p; { -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_statfs(mp = %p)\n", mp); -#endif - sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; sbp->f_blocks = 2; /* 1K to keep df happy */ sbp->f_bfree = 0; sbp->f_bavail = 0; - sbp->f_files = 0; - sbp->f_ffree = 0; + sbp->f_files = 1024; /* XXX lie */ + sbp->f_ffree = 128; /* XXX lie */ #ifdef COMPAT_09 sbp->f_type = 7; #else @@ -383,7 +339,7 @@ struct vfsops kernfs_vfsops = { kernfs_fhtovp, kernfs_vptofh, kernfs_init, - NULL, + kernfs_reinit, kernfs_done, kernfs_sysctl, NULL, /* vfs_mountroot */ diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c index 86622034d380..a6bfc217855b 100644 --- a/sys/miscfs/kernfs/kernfs_vnops.c +++ b/sys/miscfs/kernfs/kernfs_vnops.c @@ -1,4 +1,4 @@ -/* $NetBSD: kernfs_vnops.c,v 1.89 2003/08/07 16:32:37 agc Exp $ */ +/* $NetBSD: kernfs_vnops.c,v 1.90 2003/09/08 06:51:54 itojun Exp $ */ /* * Copyright (c) 1992, 1993 @@ -39,7 +39,11 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.89 2003/08/07 16:32:37 agc Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.90 2003/09/08 06:51:54 itojun Exp $"); + +#ifdef _KERNEL_OPT +#include "opt_ipsec.h" +#endif #include #include @@ -60,6 +64,14 @@ __KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.89 2003/08/07 16:32:37 agc Exp $" #include #include +#ifdef IPSEC +#include +#include +#include +#include +#include +#endif + #include #define KSTRING 256 /* Largest I/O available via this filesystem */ @@ -68,41 +80,65 @@ __KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.89 2003/08/07 16:32:37 agc Exp $" #define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH) #define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) +#define UDIR_MODE (S_IRUSR|S_IXUSR) +#define N(s) sizeof(s)-1, s const struct kern_target kern_targets[] = { /* NOTE: The name must be less than UIO_MX-16 chars in length */ -#define N(s) sizeof(s)-1, s /* name data tag type ro/rw */ - { DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE }, - { DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE }, - { DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE }, + { DT_DIR, N("."), 0, Pkern, VDIR, DIR_MODE }, + { DT_DIR, N(".."), 0, Proot, VDIR, DIR_MODE }, + { DT_REG, N("boottime"), &boottime.tv_sec, Pint, VREG, READ_MODE }, /* XXX cast away const */ { DT_REG, N("copyright"), (void *)copyright, - KTT_STRING, VREG, READ_MODE }, - { DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE }, - { DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE }, - { DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE }, - { DT_REG, N("msgbuf"), 0, KTT_MSGBUF, VREG, READ_MODE }, - { DT_REG, N("pagesize"), &uvmexp.pagesize, KTT_INT, VREG, READ_MODE }, - { DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE }, -#if 0 - { DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE }, + Pstring, VREG, READ_MODE }, + { DT_REG, N("hostname"), 0, Phostname, VREG, WRITE_MODE }, + { DT_REG, N("hz"), &hz, Pint, VREG, READ_MODE }, +#ifdef IPSEC + { DT_DIR, N("ipsecsa"), 0, Pipsecsadir, VDIR, UDIR_MODE }, + { DT_DIR, N("ipsecsp"), 0, Pipsecspdir, VDIR, UDIR_MODE }, #endif - { DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE }, - { DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE }, - { DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE }, + { DT_REG, N("loadavg"), 0, Pavenrun, VREG, READ_MODE }, + { DT_REG, N("msgbuf"), 0, Pmsgbuf, VREG, READ_MODE }, + { DT_REG, N("pagesize"), &uvmexp.pagesize, Pint, VREG, READ_MODE }, + { DT_REG, N("physmem"), &physmem, Pint, VREG, READ_MODE }, +#if 0 + { DT_DIR, N("root"), 0, Pnull, VDIR, DIR_MODE }, +#endif + { DT_BLK, N("rootdev"), &rootdev, Pdevice, VBLK, READ_MODE }, + { DT_CHR, N("rrootdev"), &rrootdev, Pdevice, VCHR, READ_MODE }, + { DT_REG, N("time"), 0, Ptime, VREG, READ_MODE }, /* XXX cast away const */ { DT_REG, N("version"), (void *)version, - KTT_STRING, VREG, READ_MODE }, -#undef N + Pstring, VREG, READ_MODE }, }; -static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); +#ifdef IPSEC +const struct kern_target ipsecsa_targets[] = { +/* NOTE: The name must be less than UIO_MX-16 chars in length */ + /* name data tag type ro/rw */ + { DT_DIR, N("."), 0, Pipsecsadir, VDIR, DIR_MODE }, + { DT_DIR, N(".."), 0, Pkern, VDIR, DIR_MODE }, +}; +const struct kern_target ipsecsp_targets[] = { +/* NOTE: The name must be less than UIO_MX-16 chars in length */ + /* name data tag type ro/rw */ + { DT_DIR, N("."), 0, Pipsecspdir, VDIR, DIR_MODE }, + { DT_DIR, N(".."), 0, Pkern, VDIR, DIR_MODE }, +}; +#endif +#undef N +int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); +#ifdef IPSEC +int nipsecsa_targets = sizeof(ipsecsa_targets) / sizeof(ipsecsa_targets[0]); +int nipsecsp_targets = sizeof(ipsecsp_targets) / sizeof(ipsecsp_targets[0]); +#endif + int kernfs_lookup __P((void *)); #define kernfs_create genfs_eopnotsupp #define kernfs_mknod genfs_eopnotsupp -#define kernfs_open genfs_nullop -#define kernfs_close genfs_nullop +int kernfs_open __P((void *)); +int kernfs_close __P((void *)); int kernfs_access __P((void *)); int kernfs_getattr __P((void *)); int kernfs_setattr __P((void *)); @@ -141,8 +177,8 @@ int kernfs_pathconf __P((void *)); #define kernfs_bwrite genfs_eopnotsupp #define kernfs_putpages genfs_putpages -static int kernfs_xread __P((const struct kern_target *, int, char **, size_t, size_t *)); -static int kernfs_xwrite __P((const struct kern_target *, char *, size_t)); +static int kernfs_xread __P((struct kernfs_node *, int, char **, size_t, size_t *)); +static int kernfs_xwrite __P((const struct kernfs_node *, char *, size_t)); int (**kernfs_vnodeop_p) __P((void *)); const struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { @@ -195,38 +231,44 @@ const struct vnodeopv_desc kernfs_vnodeop_opv_desc = { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; static int -kernfs_xread(kt, off, bufp, len, wrlen) - const struct kern_target *kt; +kernfs_xread(kfs, off, bufp, len, wrlen) + struct kernfs_node *kfs; int off; char **bufp; size_t len; size_t *wrlen; { + const struct kern_target *kt; +#ifdef IPSEC + struct mbuf *m; +#endif - switch (kt->kt_tag) { - case KTT_TIME: { + kt = kfs->kfs_kt; + + switch (kfs->kfs_type) { + case Ptime: { struct timeval tv; microtime(&tv); - sprintf(*bufp, "%ld %ld\n", tv.tv_sec, tv.tv_usec); + snprintf(*bufp, len, "%ld %ld\n", tv.tv_sec, tv.tv_usec); break; } - case KTT_INT: { + case Pint: { int *ip = kt->kt_data; - sprintf(*bufp, "%d\n", *ip); + snprintf(*bufp, len, "%d\n", *ip); break; } - case KTT_STRING: { + case Pstring: { char *cp = kt->kt_data; *bufp = cp; break; } - case KTT_MSGBUF: { + case Pmsgbuf: { long n; /* @@ -260,26 +302,79 @@ kernfs_xread(kt, off, bufp, len, wrlen) return (0); } - case KTT_HOSTNAME: { + case Phostname: { char *cp = hostname; int xlen = hostnamelen; - if (xlen >= (len-2)) + if (xlen >= (len - 2)) return (EINVAL); memcpy(*bufp, cp, xlen); (*bufp)[xlen] = '\n'; (*bufp)[xlen+1] = '\0'; + len = strlen(*bufp); break; } - case KTT_AVENRUN: + case Pavenrun: averunnable.fscale = FSCALE; - sprintf(*bufp, "%d %d %d %ld\n", + snprintf(*bufp, len, "%d %d %d %ld\n", averunnable.ldavg[0], averunnable.ldavg[1], averunnable.ldavg[2], averunnable.fscale); break; +#ifdef IPSEC + case Pipsecsa: + /* + * Note that SA configuration could be changed during the + * read operation, resulting in garbled output. + */ + m = key_setdumpsa_spi(htonl(kfs->kfs_value)); + if (!m) + return (ENOBUFS); + if (off >= m->m_pkthdr.len) { + *wrlen = 0; + m_freem(m); + return (0); + } + if (len > m->m_pkthdr.len - off) + len = m->m_pkthdr.len - off; + m_copydata(m, off, len, *bufp); + *wrlen = len; + m_freem(m); + return (0); + + case Pipsecsp: + /* + * Note that SP configuration could be changed during the + * read operation, resulting in garbled output. + */ + if (!kfs->kfs_v) { + struct secpolicy *sp; + + sp = key_getspbyid(kfs->kfs_value); + if (sp) + kfs->kfs_v = sp; + else + return (ENOENT); + } + m = key_setdumpsp((struct secpolicy *)kfs->kfs_v, + SADB_X_SPDGET, 0, 0); + if (!m) + return (ENOBUFS); + if (off >= m->m_pkthdr.len) { + *wrlen = 0; + m_freem(m); + return (0); + } + if (len > m->m_pkthdr.len - off) + len = m->m_pkthdr.len - off; + m_copydata(m, off, len, *bufp); + *wrlen = len; + m_freem(m); + return (0); +#endif + default: *wrlen = 0; return (0); @@ -296,14 +391,14 @@ kernfs_xread(kt, off, bufp, len, wrlen) } static int -kernfs_xwrite(kt, buf, len) - const struct kern_target *kt; +kernfs_xwrite(kfs, buf, len) + const struct kernfs_node *kfs; char *buf; size_t len; { - switch (kt->kt_tag) { - case KTT_HOSTNAME: + switch (kfs->kfs_type) { + case Phostname: if (buf[len-1] == '\n') --len; memcpy(hostname, buf, len); @@ -334,14 +429,12 @@ kernfs_lookup(v) struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; const char *pname = cnp->cn_nameptr; + const struct kernfs_node *kfs; const struct kern_target *kt; - struct vnode *fvp; int error, i, wantpunlock; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup(%p)\n", ap); - printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp); - printf("kernfs_lookup(%s)\n", pname); +#ifdef IPSEC + char *ep; + u_int32_t id; #endif *vpp = NULLVP; @@ -356,73 +449,158 @@ kernfs_lookup(v) return (0); } - /* - * This code only supports a flat directory, so we don't - * need to worry about .. - */ - -#if 0 - if (cnp->cn_namelen == 4 && memcmp(pname, "root", 4) == 0) { - *vpp = rootdir; - VREF(rootdir); - vn_lock(rootdir, LK_SHARED | LK_RETRY); - return (0); - } -#endif - wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); + kfs = VTOKERN(dvp); + switch (kfs->kfs_type) { + case Pkern: + /* + * Shouldn't get here with .. in the root node. + */ + if (cnp->cn_flags & ISDOTDOT) + return (EIO); - for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) { - if (cnp->cn_namelen == kt->kt_namlen && - memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) - goto found; - } - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: i = %d, failed", i); -#endif - - return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); - -found: - if (kt->kt_tag == KTT_DEVICE) { - dev_t *dp = kt->kt_data; - loop: - if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) { - return (ENOENT); + for (i = 0; i < nkern_targets; i++) { + kt = &kern_targets[i]; + if (cnp->cn_namelen == kt->kt_namlen && + memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) + goto found; } - *vpp = fvp; - if (vget(fvp, LK_EXCLUSIVE)) - goto loop; - if (wantpunlock) { + break; + + found: + error = kernfs_allocvp(dvp->v_mount, vpp, kt->kt_tag, kt, 0); + if ((error == 0) && wantpunlock) { VOP_UNLOCK(dvp, 0); cnp->cn_flags |= PDIRUNLOCK; } + return (error); + +#ifdef IPSEC + case Pipsecsadir: + for (i = 0; i < nipsecsa_targets; i++) { + kt = &ipsecsa_targets[i]; + if (cnp->cn_namelen == kt->kt_namlen && + memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { + error = kernfs_allocvp(dvp->v_mount, vpp, + kt->kt_tag, kt, 0); + if ((error == 0) && wantpunlock) { + VOP_UNLOCK(dvp, 0); + cnp->cn_flags |= PDIRUNLOCK; + } + return (error); + } + } + + ep = NULL; + id = strtoul(pname, &ep, 10); + if (!ep || *ep || ep == pname) + break; + + error = kernfs_allocvp(dvp->v_mount, vpp, Pipsecsa, NULL, id); + if ((error == 0) && wantpunlock) { + VOP_UNLOCK(dvp, 0); + cnp->cn_flags |= PDIRUNLOCK; + } + return (error); + + case Pipsecspdir: + for (i = 0; i < nipsecsp_targets; i++) { + kt = &ipsecsp_targets[i]; + if (cnp->cn_namelen == kt->kt_namlen && + memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { + error = kernfs_allocvp(dvp->v_mount, vpp, + kt->kt_tag, kt, 0); + if ((error == 0) && wantpunlock) { + VOP_UNLOCK(dvp, 0); + cnp->cn_flags |= PDIRUNLOCK; + } + return (error); + } + } + + ep = NULL; + id = strtoul(pname, &ep, 10); + if (!ep || *ep || ep == pname) + break; + + error = kernfs_allocvp(dvp->v_mount, vpp, Pipsecsp, NULL, id); + if ((error == 0) && wantpunlock) { + VOP_UNLOCK(dvp, 0); + cnp->cn_flags |= PDIRUNLOCK; + } + return (error); +#endif + + default: + return (ENOTDIR); + } + + return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); +} + +int +kernfs_open(v) + void *v; +{ + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap = v; + struct kernfs_node *kfs = VTOKERN(ap->a_vp); +#ifdef IPSEC + struct mbuf *m; + struct secpolicy *sp; +#endif + + switch (kfs->kfs_type) { +#ifdef IPSEC + case Pipsecsa: + m = key_setdumpsa_spi(htonl(kfs->kfs_value)); + if (m) { + m_freem(m); + return (0); + } else + return (ENOENT); + + case Pipsecsp: + sp = key_getspbyid(kfs->kfs_value); + if (sp) { + kfs->kfs_v = sp; + return (0); + } else + return (ENOENT); +#endif + + default: return (0); } +} -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: allocate new vnode\n"); +int +kernfs_close(v) + void *v; +{ + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap = v; + struct kernfs_node *kfs = VTOKERN(ap->a_vp); + + switch (kfs->kfs_type) { +#ifdef IPSEC + case Pipsecsp: + key_freesp((struct secpolicy *)kfs->kfs_v); + break; #endif - error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); - if (error) { - return (error); + + default: + break; } - MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, - M_WAITOK); - VTOKERN(fvp)->kf_kt = kt; - fvp->v_type = kt->kt_vtype; - vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY); - *vpp = fvp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: newvp = %p\n", fvp); -#endif - if (wantpunlock) { - VOP_UNLOCK(dvp, 0); - cnp->cn_flags |= PDIRUNLOCK; - } return (0); } @@ -436,18 +614,14 @@ kernfs_access(v) struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - struct vnode *vp = ap->a_vp; - mode_t mode; + struct vattr va; + int error; - if (vp->v_flag & VROOT) { - mode = DIR_MODE; - } else { - const struct kern_target *kt = VTOKERN(vp)->kf_kt; - mode = kt->kt_mode; - } + if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) != 0) + return (error); - return (vaccess(vp->v_type, mode, (uid_t)0, (gid_t)0, ap->a_mode, - ap->a_cred)); + return (vaccess(va.va_type, va.va_mode, va.va_uid, va.va_gid, + ap->a_mode, ap->a_cred)); } int @@ -460,16 +634,19 @@ kernfs_getattr(v) struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - struct vnode *vp = ap->a_vp; + struct kernfs_node *kfs = VTOKERN(ap->a_vp); struct vattr *vap = ap->a_vap; int error = 0; char strbuf[KSTRING], *buf; + size_t nread, total; - memset((caddr_t) vap, 0, sizeof(*vap)); - vattr_null(vap); + VATTR_NULL(vap); + vap->va_type = ap->a_vp->v_type; vap->va_uid = 0; vap->va_gid = 0; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; + vap->va_mode = kfs->kfs_mode; + vap->va_fileid = kfs->kfs_fileno; + vap->va_flags = 0; vap->va_size = 0; vap->va_blocksize = DEV_BSIZE; /* @@ -484,38 +661,53 @@ kernfs_getattr(v) vap->va_rdev = 0; vap->va_bytes = 0; - if (vp->v_flag & VROOT) { -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_getattr: stat rootdir\n"); -#endif - vap->va_type = VDIR; - vap->va_mode = DIR_MODE; - vap->va_nlink = 2; - vap->va_fileid = 2; - vap->va_size = DEV_BSIZE; - } else { - const struct kern_target *kt = VTOKERN(vp)->kf_kt; - size_t nread, total; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_getattr: stat target %s\n", kt->kt_name); -#endif - vap->va_type = kt->kt_vtype; - vap->va_mode = kt->kt_mode; + switch (kfs->kfs_type) { + case Pkern: + vap->va_nlink = 4; + vap->va_bytes = vap->va_size = DEV_BSIZE; + break; + + case Proot: + vap->va_nlink = 1; + vap->va_bytes = vap->va_size = DEV_BSIZE; + break; + + case Pnull: + case Ptime: + case Pint: + case Pstring: + case Phostname: + case Pavenrun: + case Pdevice: + case Pmsgbuf: +#ifdef IPSEC + case Pipsecsa: + case Pipsecsp: +#endif vap->va_nlink = 1; - vap->va_fileid = 1 + (kt - kern_targets); total = 0; do { buf = strbuf; - error = kernfs_xread(kt, total, &buf, - sizeof(strbuf), &nread); + error = kernfs_xread(kfs, total, &buf, + sizeof(strbuf), &nread); total += nread; } while (error == 0 && nread != 0); - vap->va_size = total; + vap->va_bytes = vap->va_size = total; + break; + +#ifdef IPSEC + case Pipsecsadir: + case Pipsecspdir: + vap->va_nlink = 2; + vap->va_bytes = vap->va_size = DEV_BSIZE; + break; +#endif + + default: + error = EINVAL; + break; } -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_getattr: return error %d\n", error); -#endif return (error); } @@ -524,6 +716,7 @@ int kernfs_setattr(v) void *v; { + /* * Silently ignore attribute changes. * This allows for open with truncate to have no @@ -543,26 +736,19 @@ kernfs_read(v) int a_ioflag; struct ucred *a_cred; } */ *ap = v; - struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; - const struct kern_target *kt; + struct kernfs_node *kfs = VTOKERN(ap->a_vp); char strbuf[KSTRING], *buf; off_t off; size_t len; int error; - if (vp->v_type == VDIR) + if (ap->a_vp->v_type == VDIR) return (EOPNOTSUPP); - kt = VTOKERN(vp)->kf_kt; - -#ifdef KERNFS_DIAGNOSTIC - printf("kern_read %s\n", kt->kt_name); -#endif - off = uio->uio_offset; buf = strbuf; - if ((error = kernfs_xread(kt, off, &buf, sizeof(strbuf), &len)) == 0) + if ((error = kernfs_xread(kfs, off, &buf, sizeof(strbuf), &len)) == 0) error = uiomove(buf, len, uio); return (error); } @@ -577,17 +763,11 @@ kernfs_write(v) int a_ioflag; struct ucred *a_cred; } */ *ap = v; - struct vnode *vp = ap->a_vp; + struct kernfs_node *kfs = VTOKERN(ap->a_vp); struct uio *uio = ap->a_uio; - const struct kern_target *kt; int error, xlen; char strbuf[KSTRING]; - if (vp->v_type == VDIR) - return (EOPNOTSUPP); - - kt = VTOKERN(vp)->kf_kt; - if (uio->uio_offset != 0) return (EINVAL); @@ -600,7 +780,7 @@ kernfs_write(v) strbuf[xlen] = '\0'; xlen = strlen(strbuf); - return (kernfs_xwrite(kt, strbuf, xlen)); + return (kernfs_xwrite(kfs, strbuf, xlen)); } int @@ -617,14 +797,16 @@ kernfs_readdir(v) } */ *ap = v; struct uio *uio = ap->a_uio; struct dirent d; + struct kernfs_node *kfs = VTOKERN(ap->a_vp); const struct kern_target *kt; off_t i; int error; off_t *cookies = NULL; - int ncookies = 0, nc = 0; - - if (ap->a_vp->v_type != VDIR) - return (ENOTDIR); + int ncookies = 0, n; +#ifdef IPSEC + struct secasvar *sav, *sav2; + struct secpolicy *sp; +#endif if (uio->uio_resid < UIO_MX) return (EINVAL); @@ -633,50 +815,204 @@ kernfs_readdir(v) error = 0; i = uio->uio_offset; - - if (i >= nkern_targets) - return 0; - - memset((caddr_t)&d, 0, UIO_MX); + memset(&d, 0, sizeof(d)); d.d_reclen = UIO_MX; + ncookies = uio->uio_resid / UIO_MX; - if (ap->a_ncookies) { - nc = uio->uio_resid / UIO_MX; - nc = min(nc, (nkern_targets - i)); - cookies = malloc(nc * sizeof(off_t), M_TEMP, M_WAITOK); - *ap->a_cookies = cookies; - } + switch (kfs->kfs_type) { + case Pkern: + if (i >= nkern_targets) + return (0); - for (kt = &kern_targets[i]; - uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) { -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_readdir: i = %d\n", (int)i); + if (ap->a_ncookies) { + ncookies = min(ncookies, (nkern_targets - i)); + cookies = malloc(ncookies * sizeof(off_t), M_TEMP, + M_WAITOK); + *ap->a_cookies = cookies; + } + + n = 0; + for (; i < nkern_targets && uio->uio_resid >= UIO_MX; i++) { + kt = &kern_targets[i]; + d.d_namlen = kt->kt_namlen; + if (i < 2) + d.d_fileno = KERNFS_FILENO(&kern_targets[0], + kern_targets[0].kt_tag, 0); + else + d.d_fileno = KERNFS_FILENO(kt, kt->kt_tag, 0); + memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); + d.d_type = kt->kt_type; + if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) + break; + if (cookies) + *cookies++ = i + 1; + n++; + } + ncookies = n; + break; + + case Proot: + if (i >= 2) + return 0; + + if (ap->a_ncookies) { + ncookies = min(ncookies, (2 - i)); + cookies = malloc(ncookies * sizeof(off_t), M_TEMP, + M_WAITOK); + *ap->a_cookies = cookies; + } + + n = 0; + for (; i < 2 && uio->uio_resid >= UIO_MX; i++) { + kt = &kern_targets[i]; + d.d_namlen = kt->kt_namlen; + d.d_fileno = KERNFS_FILENO(kt, kt->kt_tag, 0); + memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); + d.d_type = kt->kt_type; + if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) + break; + if (cookies) + *cookies++ = i + 1; + n++; + } + ncookies = n; + break; + +#ifdef IPSEC + case Pipsecsadir: + /* count SA in the system */ + n = 0; + TAILQ_FOREACH(sav, &satailq, tailq) { + for (sav2 = TAILQ_FIRST(&satailq); + sav2 != sav; + sav2 = TAILQ_NEXT(sav2, tailq)) { + if (sav->spi == sav2->spi) { + /* multiple SA with same SPI */ + break; + } + } + if (sav == sav2 || sav->spi != sav2->spi) + n++; + } + + if (i >= nipsecsa_targets + n) + return (0); + + if (ap->a_ncookies) { + ncookies = min(ncookies, (n - i)); + cookies = malloc(ncookies * sizeof(off_t), M_TEMP, + M_WAITOK); + *ap->a_cookies = cookies; + } + + n = 0; + for (; i < nipsecsa_targets && uio->uio_resid >= UIO_MX; i++) { + kt = &ipsecsa_targets[i]; + d.d_namlen = kt->kt_namlen; + d.d_fileno = KERNFS_FILENO(kt, kt->kt_tag, 0); + memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); + d.d_type = kt->kt_type; + if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) + break; + if (cookies) + *cookies++ = i + 1; + n++; + } + if (error) { + ncookies = n; + break; + } + + TAILQ_FOREACH(sav, &satailq, tailq) { + for (sav2 = TAILQ_FIRST(&satailq); + sav2 != sav; + sav2 = TAILQ_NEXT(sav2, tailq)) { + if (sav->spi == sav2->spi) { + /* multiple SA with same SPI */ + break; + } + } + if (sav != sav2 && sav->spi == sav2->spi) + continue; + if (uio->uio_resid < UIO_MX) + break; + d.d_fileno = KERNFS_FILENO(kfs->kfs_kt, kfs->kfs_type, + kfs->kfs_cookie); + d.d_namlen = snprintf(d.d_name, sizeof(d.d_name), + "%u", ntohl(sav->spi)); + d.d_type = DT_REG; + if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) + break; + if (cookies) + *cookies++ = i + 1; + n++; + i++; + } + ncookies = n; + break; + + case Pipsecspdir: + /* count SP in the system */ + n = 0; + TAILQ_FOREACH(sp, &sptailq, tailq) + n++; + + if (i >= 2 + n) + return (0); + + if (ap->a_ncookies) { + ncookies = min(ncookies, (n - i)); + cookies = malloc(ncookies * sizeof(off_t), M_TEMP, + M_WAITOK); + *ap->a_cookies = cookies; + } + + n = 0; + for (; i < nipsecsp_targets && uio->uio_resid >= UIO_MX; i++) { + kt = &ipsecsp_targets[i]; + d.d_namlen = kt->kt_namlen; + d.d_fileno = KERNFS_FILENO(kt, kt->kt_tag, 0); + memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); + d.d_type = kt->kt_type; + if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) + break; + if (cookies) + *cookies++ = i + 1; + n++; + } + if (error) { + ncookies = n; + break; + } + + TAILQ_FOREACH(sp, &sptailq, tailq) { + if (uio->uio_resid < UIO_MX) + break; + d.d_fileno = KERNFS_FILENO(kfs->kfs_kt, kfs->kfs_type, + kfs->kfs_cookie); + d.d_namlen = snprintf(d.d_name, sizeof(d.d_name), + "%u", sp->id); + d.d_type = DT_REG; + if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) + break; + if (cookies) + *cookies++ = i + 1; + n++; + i++; + } + ncookies = n; + break; #endif - if (kt->kt_tag == KTT_DEVICE) { - dev_t *dp = kt->kt_data; - struct vnode *fvp; - - if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) - continue; - } - - d.d_fileno = i + 3; - d.d_namlen = kt->kt_namlen; - memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); - d.d_type = kt->kt_type; - - if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) - break; - if (cookies) { - *cookies++ = i + 1; - ncookies++; - } + default: + error = ENOTDIR; + break; } if (ap->a_ncookies) { if (error) { - free(*ap->a_cookies, M_TEMP); + if (cookies) + free(*ap->a_cookies, M_TEMP); *ap->a_ncookies = 0; *ap->a_cookies = NULL; } else @@ -696,16 +1032,37 @@ kernfs_inactive(v) struct proc *a_p; } */ *ap = v; struct vnode *vp = ap->a_vp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_inactive(%p)\n", vp); + const struct kernfs_node *kfs = VTOKERN(ap->a_vp); +#ifdef IPSEC + struct mbuf *m; + struct secpolicy *sp; #endif - /* - * Clear out the v_type field to avoid - * nasty things happening in vgone(). - */ + VOP_UNLOCK(vp, 0); - vp->v_type = VNON; + switch (kfs->kfs_type) { +#ifdef IPSEC + case Pipsecsa: + m = key_setdumpsa_spi(htonl(kfs->kfs_value)); + if (m) + m_freem(m); + else { + /* should never happen as we hold a refcnt */ + vgone(vp); + } + break; + case Pipsecsp: + sp = key_getspbyid(kfs->kfs_value); + if (sp) + key_freesp(sp); + else { + /* should never happen as we hold a refcnt */ + vgone(vp); + } + break; +#endif + default: + break; + } return (0); } @@ -716,16 +1073,8 @@ kernfs_reclaim(v) struct vop_reclaim_args /* { struct vnode *a_vp; } */ *ap = v; - struct vnode *vp = ap->a_vp; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_reclaim(%p)\n", vp); -#endif - if (vp->v_data) { - FREE(vp->v_data, M_TEMP); - vp->v_data = 0; - } - return (0); + return (kernfs_freevp(ap->a_vp)); } /* diff --git a/sys/netkey/key.c b/sys/netkey/key.c index f0072a887c4a..a2d4410abd0d 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -1,5 +1,5 @@ -/* $NetBSD: key.c,v 1.92 2003/09/08 01:55:09 itojun Exp $ */ -/* $KAME: key.c,v 1.308 2003/09/07 20:35:59 itojun Exp $ */ +/* $NetBSD: key.c,v 1.93 2003/09/08 06:51:56 itojun Exp $ */ +/* $KAME: key.c,v 1.310 2003/09/08 02:23:44 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,10 +35,11 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.92 2003/09/08 01:55:09 itojun Exp $"); +__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.93 2003/09/08 06:51:56 itojun Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" +#include "fs_kernfs.h" #include #include @@ -91,6 +92,10 @@ __KERNEL_RCSID(0, "$NetBSD: key.c,v 1.92 2003/09/08 01:55:09 itojun Exp $"); #endif #include +#ifdef KERNFS +#include +#endif + #include #include "rnd.h" @@ -312,7 +317,6 @@ static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int)); static void key_delsav __P((struct secasvar *)); static void key_delsp __P((struct secpolicy *)); static struct secpolicy *key_getsp __P((struct secpolicyindex *, int)); -static struct secpolicy *key_getspbyid __P((u_int32_t)); static u_int32_t key_newreqid __P((void)); static struct mbuf *key_gather_mbuf __P((struct mbuf *, const struct sadb_msghdr *, int, int, ...)); @@ -328,8 +332,6 @@ static int key_spdflush __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); static int key_spddump __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); -static struct mbuf *key_setdumpsp __P((struct secpolicy *, - u_int8_t, u_int32_t, u_int32_t)); static u_int key_getspreqmsglen __P((struct secpolicy *)); static int key_spdexpire __P((struct secpolicy *)); static struct secashead *key_newsah __P((struct secasindex *)); @@ -969,6 +971,10 @@ key_delsp(sp) s = splsoftnet(); /*called from softclock()*/ +#ifdef KERNFS + kernfs_revoke_sp(sp); +#endif + { struct ipsecrequest *isr = sp->req, *nextisr; @@ -1027,7 +1033,7 @@ key_getsp(spidx, dir) * OUT: NULL : not found * others : found, pointer to a SP. */ -static struct secpolicy * +struct secpolicy * key_getspbyid(id) u_int32_t id; { @@ -2199,7 +2205,7 @@ key_spddump(so, m, mhp) return 0; } -static struct mbuf * +struct mbuf * key_setdumpsp(sp, type, seq, pid) struct secpolicy *sp; u_int8_t type; @@ -6548,6 +6554,49 @@ key_dump(so, m, mhp) return 0; } +struct mbuf * +key_setdumpsa_spi(spi) + u_int32_t spi; +{ + struct mbuf *m, *n; + struct secasvar *sav; + u_int8_t satype; + int cnt; + + cnt = 0; + LIST_FOREACH(sav, &spihash[spi % SPIHASHSIZE], spihash) { + if (sav->spi != spi) + continue; + cnt++; + } + + if (cnt == 0) + return NULL; + + m = NULL; + LIST_FOREACH(sav, &spihash[spi % SPIHASHSIZE], spihash) { + if (sav->spi != spi) + continue; + satype = key_proto2satype(sav->sah->saidx.proto); + n = key_setdumpsa(sav, SADB_DUMP, satype, --cnt, 0); + if (!m) + m = n; + else if (n) + m_cat(m, n); + } + + if (!m) + return NULL; + + if ((m->m_flags & M_PKTHDR) != 0) { + m->m_pkthdr.len = 0; + for (n = m; n; n = n->m_next) + m->m_pkthdr.len += n->m_len; + } + + return m; +} + /* * SADB_X_PROMISC processing * diff --git a/sys/netkey/key.h b/sys/netkey/key.h index 9d10b1c80767..c9f414370b56 100644 --- a/sys/netkey/key.h +++ b/sys/netkey/key.h @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.15 2003/09/07 15:59:38 itojun Exp $ */ +/* $NetBSD: key.h,v 1.16 2003/09/08 06:51:59 itojun Exp $ */ /* $KAME: key.h,v 1.32 2003/09/07 05:25:20 itojun Exp $ */ /* @@ -56,6 +56,7 @@ extern int key_checkrequest __P((struct ipsecrequest *isr, struct secasindex *)); extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t, u_int, u_int32_t)); +extern struct secpolicy *key_getspbyid __P((u_int32_t)); extern void key_freesp __P((struct secpolicy *)); extern void key_freesav __P((struct secasvar *)); extern struct secpolicy *key_newsp __P((u_int32_t)); @@ -67,9 +68,12 @@ extern int key_cmpspidx_exactly extern int key_cmpspidx_withmask __P((struct secpolicyindex *, struct secpolicyindex *)); extern int key_spdacquire __P((struct secpolicy *)); +extern struct mbuf *key_setdumpsp __P((struct secpolicy *, + u_int8_t, u_int32_t, u_int32_t)); extern void key_timehandler __P((void *)); extern void key_randomfill __P((void *, size_t)); extern void key_freereg __P((struct socket *)); +struct mbuf *key_setdumpsa_spi __P((u_int32_t)); extern int key_parse __P((struct mbuf *, struct socket *)); extern void key_init __P((void)); extern int key_checktunnelsanity __P((struct secasvar *, u_int,