summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>1999-10-02 04:06:24 +0000
committerbp <bp@FreeBSD.org>1999-10-02 04:06:24 +0000
commit99edac4b3b7b369e65394b2bd57332aaad8d6812 (patch)
tree648f799b08d76bc3345446a922bb7985b440fae9 /sys
parent4f9461c0bd8dd6d2fb8a4f0df36c1666e4e25c98 (diff)
downloadFreeBSD-src-99edac4b3b7b369e65394b2bd57332aaad8d6812.zip
FreeBSD-src-99edac4b3b7b369e65394b2bd57332aaad8d6812.tar.gz
Import kernel part of ncplib: netncp and nwfs
Reviewed by: msmith, peter Obtained from: ncplib
Diffstat (limited to 'sys')
-rw-r--r--sys/fs/nwfs/nwfs.h82
-rw-r--r--sys/fs/nwfs/nwfs_io.c650
-rw-r--r--sys/fs/nwfs/nwfs_ioctl.c103
-rw-r--r--sys/fs/nwfs/nwfs_mount.h78
-rw-r--r--sys/fs/nwfs/nwfs_node.c321
-rw-r--r--sys/fs/nwfs/nwfs_node.h100
-rw-r--r--sys/fs/nwfs/nwfs_subr.c669
-rw-r--r--sys/fs/nwfs/nwfs_subr.h84
-rw-r--r--sys/fs/nwfs/nwfs_vfsops.c515
-rw-r--r--sys/fs/nwfs/nwfs_vnops.c1128
-rw-r--r--sys/netncp/ncp.h391
-rw-r--r--sys/netncp/ncp_conn.c541
-rw-r--r--sys/netncp/ncp_conn.h238
-rw-r--r--sys/netncp/ncp_crypt.c278
-rw-r--r--sys/netncp/ncp_login.c202
-rw-r--r--sys/netncp/ncp_mod.c489
-rw-r--r--sys/netncp/ncp_ncp.c613
-rw-r--r--sys/netncp/ncp_ncp.h118
-rw-r--r--sys/netncp/ncp_nls.c305
-rw-r--r--sys/netncp/ncp_nls.h86
-rw-r--r--sys/netncp/ncp_rq.c591
-rw-r--r--sys/netncp/ncp_rq.h191
-rw-r--r--sys/netncp/ncp_sock.c442
-rw-r--r--sys/netncp/ncp_sock.h51
-rw-r--r--sys/netncp/ncp_subr.c255
-rw-r--r--sys/netncp/ncp_subr.h130
-rw-r--r--sys/netncp/ncp_user.h97
-rw-r--r--sys/netncp/nwerror.h634
-rw-r--r--sys/nwfs/nwfs.h82
-rw-r--r--sys/nwfs/nwfs_io.c650
-rw-r--r--sys/nwfs/nwfs_ioctl.c103
-rw-r--r--sys/nwfs/nwfs_mount.h78
-rw-r--r--sys/nwfs/nwfs_node.c321
-rw-r--r--sys/nwfs/nwfs_node.h100
-rw-r--r--sys/nwfs/nwfs_subr.c669
-rw-r--r--sys/nwfs/nwfs_subr.h84
-rw-r--r--sys/nwfs/nwfs_vfsops.c515
-rw-r--r--sys/nwfs/nwfs_vnops.c1128
38 files changed, 13112 insertions, 0 deletions
diff --git a/sys/fs/nwfs/nwfs.h b/sys/fs/nwfs/nwfs.h
new file mode 100644
index 0000000..950d18a
--- /dev/null
+++ b/sys/fs/nwfs/nwfs.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NWFS_H_
+#define _NWFS_H_
+
+#include <nwfs/nwfs_mount.h>
+
+#define NR_OPEN 0
+#define NW_NSB_DOS (1 << NW_NS_DOS)
+#define NW_NSB_MAC (1 << NW_NS_MAC)
+#define NW_NSB_NFS (1 << NW_NS_NFS)
+#define NW_NSB_FTAM (1 << NW_NS_FTAM)
+#define NW_NSB_OS2 (1 << NW_NS_OS2)
+
+#define NWFSIOC_GETCONN _IOR('n',1,int)
+#define NWFSIOC_GETEINFO _IOR('n',2,struct nw_entry_info)
+#define NWFSIOC_GETNS _IOR('n',3,int)
+
+#ifdef KERNEL
+
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+struct nwfsnode;
+
+struct nwmount {
+ struct nwfs_args m;
+ struct mount *mp;
+ struct ncp_handle *connh;
+ int name_space;
+ struct nwnode *n_root;
+ u_int32_t n_volume;
+ ncpfid n_rootent;
+ int n_id;
+};
+
+#define VFSTONWFS(mntp) ((struct nwmount *)((mntp)->mnt_data))
+#define NWFSTOVFS(mnp) ((struct mount *)((mnp)->mount))
+#define VTOVFS(vp) ((vp)->v_mount)
+#define VTONWFS(vp) (VFSTONWFS(VTOVFS(vp)))
+#define NWFSTOCONN(nmp) ((nmp)->connh->nh_conn)
+
+int ncp_conn_logged_in(struct nwmount *);
+int nwfs_ioctl(struct vop_ioctl_args *ap);
+int nwfs_doio(struct buf *bp, struct ucred *cr, struct proc *p);
+int nwfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
+ struct proc *p, int intrflg);
+#endif /* KERNEL */
+
+#endif /* _NWFS_H_ */
diff --git a/sys/fs/nwfs/nwfs_io.c b/sys/fs/nwfs/nwfs_io.c
new file mode 100644
index 0000000..21339b3
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_io.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+
+#include <sys/ioccom.h>
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+static int nwfs_fastlookup = 1;
+
+extern struct linker_set sysctl_vfs_nwfs;
+
+SYSCTL_DECL(_vfs_nwfs);
+SYSCTL_INT(_vfs_nwfs, OID_AUTO, fastlookup, CTLFLAG_RW, &nwfs_fastlookup, 0, "");
+
+
+extern int nwfs_pbuf_freecnt;
+
+#define DE_SIZE (sizeof(struct dirent))
+#define NWFS_RWCACHE
+
+static int
+nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) {
+ struct nwmount *nmp = VTONWFS(vp);
+ int error, count, i, len;
+ struct dirent dp;
+ struct nwnode *np = VTONW(vp);
+ struct nw_entry_info fattr;
+ struct vnode *newvp;
+ struct nameidata nami, *ndp = &nami;
+ struct componentname *cnp = &ndp->ni_cnd;
+ ncpfid fid;
+ u_char *cp;
+
+ np = VTONW(vp);
+ NCPVNDEBUG("dirname='%s'\n",np->n_name);
+ if (uio->uio_resid < DE_SIZE || (uio->uio_offset < 0))
+ return (EINVAL);
+ error = 0;
+ count = 0;
+ ndp->ni_dvp = vp;
+ i = uio->uio_offset / DE_SIZE; /* offset in directory */
+ if (i == 0) {
+ error = ncp_initsearch(vp, uio->uio_procp, cred);
+ if (error) {
+ NCPVNDEBUG("cannot initialize search, error=%d",error);
+ return( error );
+ }
+ }
+
+ for (; uio->uio_resid >= DE_SIZE; i++) {
+ bzero((char *) &dp, DE_SIZE);
+ dp.d_reclen = DE_SIZE;
+ switch (i) {
+ case 0: /* `.' */
+ case 1: /* `..' */
+ dp.d_fileno = (i == 0) ? np->n_fid.f_id : np->n_parent.f_id;
+ if (!dp.d_fileno) dp.d_fileno = NWFS_ROOT_INO;
+ dp.d_namlen = i + 1;
+ dp.d_name[0] = '.';
+ dp.d_name[1] = '.';
+ dp.d_name[i + 1] = '\0';
+ dp.d_type = DT_DIR;
+ break;
+ default:
+ error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_procp, cred);
+ if (error && error < 0x80) break;
+ dp.d_fileno = fattr.dirEntNum;
+ dp.d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG;
+ dp.d_namlen = fattr.nameLen;
+ bcopy(fattr.entryName, dp.d_name, dp.d_namlen);
+ dp.d_name[dp.d_namlen] = '\0';
+#if 0
+ if (error && eofflag) {
+ /* *eofflag = 1;*/
+ break;
+ }
+#endif
+ break;
+ }
+ if (nwfs_fastlookup && !error && i > 1) {
+ fid.f_id = fattr.dirEntNum;
+ fid.f_parent = np->n_fid.f_id;
+ error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp);
+ if (!error) {
+ VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec;
+ cnp->cn_nameptr = dp.d_name;
+ len = cnp->cn_namelen = dp.d_namlen;
+ ndp->ni_vp = newvp;
+ cnp->cn_hash = 0;
+ for (cp = cnp->cn_nameptr; len; len--, cp++)
+ cnp->cn_hash += *cp;
+ cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
+ vput(newvp);
+ } else
+ error = 0;
+ }
+ if (error >= 0x80) {
+ error = 0;
+ break;
+ }
+ if ((error = uiomove((caddr_t)&dp, DE_SIZE, uio)))
+ break;
+ }
+
+ uio->uio_offset = i * DE_SIZE;
+ return (error);
+}
+
+int
+nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred) {
+ struct nwmount *nmp = VFSTONWFS(vp->v_mount);
+ struct nwnode *np = VTONW(vp);
+ struct proc *p;
+ struct vattr vattr;
+ int error, biosize;
+
+ if (vp->v_type != VREG && vp->v_type != VDIR) {
+ printf("%s: vn types other than VREG or VDIR are unsupported !\n",__FUNCTION__);
+ return EIO;
+ }
+ if (uiop->uio_resid == 0) return 0;
+ if (uiop->uio_offset < 0) return EINVAL;
+/* if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
+ return (EFBIG);*/
+ p = uiop->uio_procp;
+ if (vp->v_type == VDIR) {
+ error = nwfs_readvdir(vp, uiop, cred);
+ return error;
+ }
+ biosize = NWFSTOCONN(nmp)->buffer_size;
+ if (np->n_flag & NMODIFIED) {
+ nwfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ } else {
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+ if (np->n_mtime != vattr.va_mtime.tv_sec) {
+ error = nwfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error) return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ }
+ }
+ error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop,cred);
+ return (error);
+}
+
+int
+nwfs_writevnode(vp, uiop, cred, ioflag)
+ register struct vnode *vp;
+ register struct uio *uiop;
+ struct ucred *cred;
+ int ioflag;
+{
+ struct nwmount *nmp = VTONWFS(vp);
+ struct nwnode *np = VTONW(vp);
+ struct proc *p;
+/* struct vattr vattr;*/
+ int error = 0;
+
+ if (vp->v_type != VREG) {
+ printf("%s: vn types other than VREG unsupported !\n",__FUNCTION__);
+ return EIO;
+ }
+ NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
+ if (uiop->uio_offset < 0) return EINVAL;
+/* if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
+ return (EFBIG);*/
+ p = uiop->uio_procp;
+ if (ioflag & (IO_APPEND | IO_SYNC)) {
+ if (np->n_flag & NMODIFIED) {
+ nwfs_attr_cacheremove(vp);
+ error = nwfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error) return (error);
+ }
+ if (ioflag & IO_APPEND) {
+ /* We can relay only on local information about file size,
+ * because until file is closed NetWare will not return
+ * the correct size. */
+#if notyet
+ nwfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+#endif
+ uiop->uio_offset = np->n_size;
+ }
+ }
+ if (uiop->uio_resid == 0) return 0;
+ if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ psignal(p, SIGXFSZ);
+ return (EFBIG);
+ }
+ error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
+ NCPVNDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
+ if (!error) {
+ if (uiop->uio_offset > np->n_size) {
+ np->n_vattr.va_size = np->n_size = uiop->uio_offset;
+ vnode_pager_setsize(vp, np->n_size);
+ }
+ }
+ return (error);
+}
+
+/*
+ * Do an I/O operation to/from a cache block.
+ */
+int
+nwfs_doio(bp, cr, p)
+ register struct buf *bp;
+ struct ucred *cr;
+ struct proc *p;
+{
+ register struct uio *uiop;
+ register struct vnode *vp;
+ struct nwnode *np;
+ struct nwmount *nmp;
+ int error = 0;
+ struct uio uio;
+ struct iovec io;
+
+ vp = bp->b_vp;
+ np = VTONW(vp);
+ nmp = VFSTONWFS(vp->v_mount);
+ uiop = &uio;
+ uiop->uio_iov = &io;
+ uiop->uio_iovcnt = 1;
+ uiop->uio_segflg = UIO_SYSSPACE;
+ uiop->uio_procp = p;
+ if (bp->b_flags & B_READ) {
+ io.iov_len = uiop->uio_resid = bp->b_bcount;
+ io.iov_base = bp->b_data;
+ uiop->uio_rw = UIO_READ;
+ switch (vp->v_type) {
+ case VREG:
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
+ error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
+ if (error)
+ break;
+ if (uiop->uio_resid) {
+ int left = uiop->uio_resid;
+ int nread = bp->b_bcount - left;
+ if (left > 0)
+ bzero((char *)bp->b_data + nread, left);
+ }
+ break;
+/* case VDIR:
+ nfsstats.readdir_bios++;
+ uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
+ if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
+ error = nfs_readdirplusrpc(vp, uiop, cr);
+ if (error == NFSERR_NOTSUPP)
+ nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
+ }
+ if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
+ error = nfs_readdirrpc(vp, uiop, cr);
+ if (error == 0 && uiop->uio_resid == bp->b_bcount)
+ bp->b_flags |= B_INVAL;
+ break;
+*/
+ default:
+ printf("nwfs_doio: type %x unexpected\n",vp->v_type);
+ break;
+ };
+ if (error) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = error;
+ }
+ } else { /* write */
+ if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
+ bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
+
+ if (bp->b_dirtyend > bp->b_dirtyoff) {
+ io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
+ io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
+ uiop->uio_rw = UIO_WRITE;
+ bp->b_flags |= B_WRITEINPROG;
+ error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
+ bp->b_flags &= ~B_WRITEINPROG;
+
+ /*
+ * For an interrupted write, the buffer is still valid
+ * and the write hasn't been pushed to the server yet,
+ * so we can't set B_ERROR and report the interruption
+ * by setting B_EINTR. For the B_ASYNC case, B_EINTR
+ * is not relevant, so the rpc attempt is essentially
+ * a noop. For the case of a V3 write rpc not being
+ * committed to stable storage, the block is still
+ * dirty and requires either a commit rpc or another
+ * write rpc with iomode == NFSV3WRITE_FILESYNC before
+ * the block is reused. This is indicated by setting
+ * the B_DELWRI and B_NEEDCOMMIT flags.
+ */
+ if (error == EINTR
+ || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
+ int s;
+
+ s = splbio();
+ bp->b_flags &= ~(B_INVAL|B_NOCACHE);
+ if ((bp->b_flags & B_ASYNC) == 0)
+ bp->b_flags |= B_EINTR;
+ if ((bp->b_flags & B_PAGING) == 0) {
+ bdirty(bp);
+ bp->b_flags &= ~B_DONE;
+ }
+ if ((bp->b_flags & B_ASYNC) == 0)
+ bp->b_flags |= B_EINTR;
+ splx(s);
+ } else {
+ if (error) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error /*= np->n_error */= error;
+/* np->n_flag |= NWRITEERR;*/
+ }
+ bp->b_dirtyoff = bp->b_dirtyend = 0;
+ }
+ } else {
+ bp->b_resid = 0;
+ biodone(bp);
+ return (0);
+ }
+ }
+ bp->b_resid = uiop->uio_resid;
+ biodone(bp);
+ return (error);
+}
+
+/*
+ * Vnode op for VM getpages.
+ * Wish wish .... get rid from multiple IO routines
+ */
+int
+nwfs_getpages(ap)
+ struct vop_getpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_reqpage;
+ vm_ooffset_t a_offset;
+ } */ *ap;
+{
+#ifndef NWFS_RWCACHE
+ return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
+ ap->a_reqpage);
+#else
+ int i, error, nextoff, size, toff, npages, count;
+ struct uio uio;
+ struct iovec iov;
+ vm_offset_t kva;
+ struct buf *bp;
+ struct vnode *vp;
+ struct proc *p;
+ struct ucred *cred;
+ struct nwmount *nmp;
+ struct nwnode *np;
+ vm_page_t *pages;
+
+ vp = ap->a_vp;
+ p = curproc; /* XXX */
+ cred = curproc->p_ucred; /* XXX */
+ np = VTONW(vp);
+ nmp = VFSTONWFS(vp->v_mount);
+ pages = ap->a_m;
+ count = ap->a_count;
+
+ if (vp->v_object == NULL) {
+ printf("nwfs_getpages: called with non-merged cache vnode??\n");
+ return VM_PAGER_ERROR;
+ }
+
+ bp = getpbuf(&nwfs_pbuf_freecnt);
+ npages = btoc(count);
+ kva = (vm_offset_t) bp->b_data;
+ pmap_qenter(kva, pages, npages);
+
+ iov.iov_base = (caddr_t) kva;
+ iov.iov_len = count;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+ uio.uio_resid = count;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+
+ error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, &uio,cred);
+ pmap_qremove(kva, npages);
+
+ relpbuf(bp, &nwfs_pbuf_freecnt);
+
+ if (error && (uio.uio_resid == count)) {
+ printf("nwfs_getpages: error %d\n",error);
+ for (i = 0; i < npages; i++) {
+ if (ap->a_reqpage != i)
+ vnode_pager_freepage(pages[i]);
+ }
+ return VM_PAGER_ERROR;
+ }
+
+ size = count - uio.uio_resid;
+
+ for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
+ vm_page_t m;
+ nextoff = toff + PAGE_SIZE;
+ m = pages[i];
+
+ m->flags &= ~PG_ZERO;
+
+ if (nextoff <= size) {
+ m->valid = VM_PAGE_BITS_ALL;
+ m->dirty = 0;
+ } else {
+ int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
+ vm_page_set_validclean(m, 0, nvalid);
+ }
+
+ if (i != ap->a_reqpage) {
+ /*
+ * Whether or not to leave the page activated is up in
+ * the air, but we should put the page on a page queue
+ * somewhere (it already is in the object). Result:
+ * It appears that emperical results show that
+ * deactivating pages is best.
+ */
+
+ /*
+ * Just in case someone was asking for this page we
+ * now tell them that it is ok to use.
+ */
+ if (!error) {
+ if (m->flags & PG_WANTED)
+ vm_page_activate(m);
+ else
+ vm_page_deactivate(m);
+ vm_page_wakeup(m);
+ } else {
+ vnode_pager_freepage(m);
+ }
+ }
+ }
+ return 0;
+#endif /* NWFS_RWCACHE */
+}
+
+/*
+ * Vnode op for VM putpages.
+ * possible bug: all IO done in sync mode
+ * Note that vop_close always invalidate pages before close, so it's
+ * not necessary to open vnode.
+ */
+int
+nwfs_putpages(ap)
+ struct vop_putpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_sync;
+ int *a_rtvals;
+ vm_ooffset_t a_offset;
+ } */ *ap;
+{
+ int error;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p;
+ struct ucred *cred;
+
+#ifndef NWFS_RWCACHE
+ p = curproc; /* XXX */
+ cred = p->p_ucred; /* XXX */
+ VOP_OPEN(vp, FWRITE, cred, p);
+ error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
+ ap->a_sync, ap->a_rtvals);
+ VOP_CLOSE(vp, FWRITE, cred, p);
+ return error;
+#else
+ struct uio uio;
+ struct iovec iov;
+ vm_offset_t kva;
+ struct buf *bp;
+ int i, npages, count;
+ int *rtvals;
+ struct nwmount *nmp;
+ struct nwnode *np;
+ vm_page_t *pages;
+
+ p = curproc; /* XXX */
+ cred = p->p_ucred; /* XXX */
+/* VOP_OPEN(vp, FWRITE, cred, p);*/
+ np = VTONW(vp);
+ nmp = VFSTONWFS(vp->v_mount);
+ pages = ap->a_m;
+ count = ap->a_count;
+ rtvals = ap->a_rtvals;
+ npages = btoc(count);
+
+ for (i = 0; i < npages; i++) {
+ rtvals[i] = VM_PAGER_AGAIN;
+ }
+
+ bp = getpbuf(&nwfs_pbuf_freecnt);
+ kva = (vm_offset_t) bp->b_data;
+ pmap_qenter(kva, pages, npages);
+
+ iov.iov_base = (caddr_t) kva;
+ iov.iov_len = count;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+ uio.uio_resid = count;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = p;
+ NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
+
+ error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, &uio, cred);
+/* VOP_CLOSE(vp, FWRITE, cred, p);*/
+ NCPVNDEBUG("paged write done: %d\n", error);
+
+ pmap_qremove(kva, npages);
+ relpbuf(bp, &nwfs_pbuf_freecnt);
+
+ if (!error) {
+ int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
+ for (i = 0; i < nwritten; i++) {
+ rtvals[i] = VM_PAGER_OK;
+ pages[i]->dirty = 0;
+ }
+ }
+ return rtvals[0];
+#endif /* NWFS_RWCACHE */
+}
+/*
+ * Flush and invalidate all dirty buffers. If another process is already
+ * doing the flush, just wait for completion.
+ */
+int
+nwfs_vinvalbuf(vp, flags, cred, p, intrflg)
+ struct vnode *vp;
+ int flags;
+ struct ucred *cred;
+ struct proc *p;
+ int intrflg;
+{
+ register struct nwnode *np = VTONW(vp);
+/* struct nwmount *nmp = VTONWFS(vp);*/
+ int error = 0, slpflag, slptimeo;
+
+ if (vp->v_flag & VXLOCK) {
+ return (0);
+ }
+ if (intrflg) {
+ slpflag = PCATCH;
+ slptimeo = 2 * hz;
+ } else {
+ slpflag = 0;
+ slptimeo = 0;
+ }
+ while (np->n_flag & NFLUSHINPROG) {
+ np->n_flag |= NFLUSHWANT;
+ error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "nwfsvinv", slptimeo);
+ error = ncp_chkintr(NWFSTOCONN(VTONWFS(vp)), p);
+ if (error == EINTR && intrflg)
+ return EINTR;
+ }
+ np->n_flag |= NFLUSHINPROG;
+ error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
+ while (error) {
+ if (intrflg && (error == ERESTART || error == EINTR)) {
+ np->n_flag &= ~NFLUSHINPROG;
+ if (np->n_flag & NFLUSHWANT) {
+ np->n_flag &= ~NFLUSHWANT;
+ wakeup((caddr_t)&np->n_flag);
+ }
+ return EINTR;
+ }
+ error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
+ }
+ np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
+ if (np->n_flag & NFLUSHWANT) {
+ np->n_flag &= ~NFLUSHWANT;
+ wakeup((caddr_t)&np->n_flag);
+ }
+ return (error);
+}
diff --git a/sys/fs/nwfs/nwfs_ioctl.c b/sys/fs/nwfs/nwfs_ioctl.c
new file mode 100644
index 0000000..6b4b510
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_ioctl.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/ioccom.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+int
+nwfs_ioctl(ap)
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ u_long a_command;
+ caddr_t a_data;
+ int fflag;
+ struct ucred *cred;
+ struct proc *p;
+ } */ *ap;
+{
+ int error;
+ struct proc *p = ap->a_p;
+ struct ucred *cred = ap->a_cred;
+ struct vnode *vp = ap->a_vp;
+ struct nwnode *np = VTONW(vp);
+ struct nwmount *nmp = VTONWFS(vp);
+ struct ncp_conn *conn = NWFSTOCONN(nmp);
+ struct ncp_handle *hp;
+ struct nw_entry_info *fap;
+ void *data = ap->a_data;
+
+ switch (ap->a_command) {
+ case NWFSIOC_GETCONN:
+ error = ncp_conn_lock(conn, p, cred, NCPM_READ);
+ if (error) break;
+ error = ncp_conn_gethandle(conn, p, &hp);
+ ncp_conn_unlock(conn, p);
+ if (error) break;
+ *(int*)data = hp->nh_id;
+ break;
+ case NWFSIOC_GETEINFO:
+ if ((error = VOP_ACCESS(vp, VEXEC, cred, p))) break;
+ fap = data;
+ error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, fap,
+ ap->a_p,ap->a_cred);
+ strcpy(fap->entryName, np->n_name);
+ fap->nameLen = np->n_nmlen;
+ break;
+ case NWFSIOC_GETNS:
+ if ((error = VOP_ACCESS(vp, VEXEC, cred, p))) break;
+ *(int*)data = nmp->name_space;
+ break;
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
diff --git a/sys/fs/nwfs/nwfs_mount.h b/sys/fs/nwfs/nwfs_mount.h
new file mode 100644
index 0000000..56a3241
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_mount.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NWFS_MOUNT_H_
+#define _NWFS_MOUNT_H_
+
+#ifndef _NCP_NCP_NLS_H_
+#include <netncp/ncp_nls.h>
+#endif
+
+#define NWFS_VERMAJ 1
+#define NWFS_VERMIN 3200
+#define NWFS_VERSION (NWFS_VERMAJ*100000 + NWFS_VERMIN)
+
+/* Values for flags */
+#define NWFS_MOUNT_SOFT 0x0001
+#define WNFS_MOUNT_INTR 0x0002
+#define NWFS_MOUNT_STRONG 0x0004
+#define NWFS_MOUNT_NO_OS2 0x0008
+#define NWFS_MOUNT_NO_NFS 0x0010
+#define NWFS_MOUNT_NO_LONG 0x0020
+#define NWFS_MOUNT_GET_SYSENT 0x0040 /* special case, look to vfsops :) */
+#define NWFS_MOUNT_HAVE_NLS 0x0080
+
+
+/* Layout of the mount control block for a netware file system. */
+struct nwfs_args {
+ int connRef; /* connection reference */
+ char mount_point[MAXPATHLEN];
+ u_int flags;
+ u_char mounted_vol[NCP_VOLNAME_LEN + 1];
+ u_char root_path[512+1];
+ int version;
+ uid_t uid;
+ gid_t gid;
+ mode_t file_mode;
+ mode_t dir_mode;
+ struct ncp_nlstables nls;
+};
+
+#ifdef KERNEL
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_NWFSMNT);
+#endif
+
+#endif /* KERNEL */
+#endif /* !_NWFS_MOUNT_H_ */
diff --git a/sys/fs/nwfs/nwfs_node.c b/sys/fs/nwfs/nwfs_node.c
new file mode 100644
index 0000000..55e19b7
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_node.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+#include <vm/vm_zone.h>
+#include <sys/queue.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_mount.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+#define NWNOHASH(fhsum) (&nwhashtbl[(fhsum.f_id) & nwnodehash])
+
+extern vop_t **nwfs_vnodeop_p;
+
+static LIST_HEAD(nwnode_hash_head,nwnode) *nwhashtbl;
+static u_long nwnodehash;
+static int nwhashlock = 0;
+
+MALLOC_DEFINE(M_NWNODE, "NWFS node", "NWFS vnode private part");
+MALLOC_DEFINE(M_NWFSHASH, "NWFS hash", "NWFS has table");
+
+static int nwfs_sysctl_vnprint SYSCTL_HANDLER_ARGS;
+
+extern struct linker_set sysctl_vfs_nwfs;
+
+SYSCTL_DECL(_vfs_nwfs);
+
+SYSCTL_PROC(_vfs_nwfs, OID_AUTO, vnprint, CTLFLAG_WR|CTLTYPE_OPAQUE,
+ NULL, 0, nwfs_sysctl_vnprint, "S,vnlist", "vnode hash");
+
+void
+nwfs_hash_init(void) {
+ nwhashtbl = hashinit(desiredvnodes, M_NWFSHASH, &nwnodehash);
+}
+
+void
+nwfs_hash_free(void) {
+ free(nwhashtbl, M_NWFSHASH);
+}
+
+int
+nwfs_sysctl_vnprint SYSCTL_HANDLER_ARGS {
+ struct nwnode *np;
+ struct nwnode_hash_head *nhpp;
+ struct vnode *vp;
+ int i;
+
+ if (nwfs_debuglevel == 0)
+ return 0;
+ printf("Name:uc:hc:fid:pfid\n");
+ for(i = 0; i <= nwnodehash; i++) {
+ nhpp = &nwhashtbl[i];
+ for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
+ vp = NWTOV(np);
+ printf("%s:%d:%d:%d:%d\n",np->n_name,vp->v_usecount,vp->v_holdcnt,
+ np->n_fid.f_id, np->n_fid.f_parent);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Allocate new nwfsnode/vnode from given nwnode.
+ * Vnode referenced and not locked.
+ */
+int
+nwfs_allocvp(struct mount *mp, ncpfid fid, struct vnode **vpp) {
+ struct proc *p = curproc; /* XXX */
+ struct nwnode *np, *np2;
+ struct nwnode_hash_head *nhpp;
+ struct vnode *vp;
+ int error;
+
+retry:
+ nhpp = NWNOHASH(fid);
+loop:
+ for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
+ vp = NWTOV(np);
+ if (mp != vp->v_mount || !NWCMPF(&fid, &np->n_fid))
+ continue;
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ *vpp = vp;
+ return(0);
+ }
+
+ /* lock list, or waiting in malloc can cause problems */
+ if (nwhashlock) {
+ while(nwhashlock) {
+ nwhashlock = -1;
+ tsleep((caddr_t) &nwhashlock, PVM, "nwfsvp", 0);
+ }
+ goto loop;
+ }
+ nwhashlock = 1;
+ /*
+ * Do the MALLOC before the getnewvnode since doing so afterward
+ * might cause a bogus v_data pointer to get dereferenced
+ * elsewhere if MALLOC should block.
+ */
+ MALLOC(np, struct nwnode *, sizeof *np, M_NWNODE, M_WAITOK);
+ error = getnewvnode(VT_NWFS, mp, nwfs_vnodeop_p, &vp);
+ if (error) {
+ if (nwhashlock < 0)
+ wakeup(&nwhashlock);
+ nwhashlock = 0;
+ *vpp = 0;
+ FREE(np, M_NWNODE);
+ return (error);
+ }
+ *vpp = vp;
+ bzero(np,sizeof(*np));
+ vp->v_data = np;
+ np->n_vnode = vp;
+ np->n_mount = VFSTONWFS(mp);
+ np->n_fid = fid;
+ for (np2 = nhpp->lh_first; np2 != 0; np2 = np->n_hash.le_next) {
+ if (mp != NWTOV(np2)->v_mount || !NWCMPF(&fid, &np2->n_fid))
+ continue;
+ vrele(vp);
+ FREE(np, M_NWNODE);
+ if (nwhashlock < 0)
+ wakeup(&nwhashlock);
+ nwhashlock = 0;
+ goto retry;
+ }
+ LIST_INSERT_HEAD(nhpp, np, n_hash);
+ if (nwhashlock < 0)
+ wakeup(&nwhashlock);
+ nwhashlock = 0;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ np->n_flag |= NNEW;
+ return (error);
+}
+
+int
+nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct nwnode **npp) {
+ struct nwnode *np;
+ struct nwnode_hash_head *nhpp;
+
+ nhpp = NWNOHASH(fid);
+ for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
+ if (nmp != np->n_mount || !NWCMPF(&fid, &np->n_fid))
+ continue;
+ *npp = np;
+ return(0);
+ }
+ return ENOENT;
+}
+
+/*
+ * Free nwnode, and give vnode back to system
+ */
+int
+nwfs_reclaim(ap)
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *dvp = NULL, *vp = ap->a_vp;
+ struct nwnode *dnp, *np = VTONW(vp);
+ struct nwmount *nmp=VTONWFS(vp);
+
+ NCPVNDEBUG("%s,%d\n", np->n_name, vp->v_usecount);
+ if (np->n_refparent) {
+ np->n_refparent = 0;
+ if (nwfs_lookupnp(nmp, np->n_parent, &dnp) == 0) {
+ dvp = dnp->n_vnode;
+ } else {
+ NCPVNDEBUG("%s: has no parent ?\n",np->n_name);
+ }
+ }
+ LIST_REMOVE(np, n_hash);
+ cache_purge(vp);
+ if (nmp->n_root == np) {
+ nmp->n_root = NULL;
+ }
+ vp->v_data = NULL;
+ FREE(np, M_NWNODE);
+ if (dvp) {
+ vrele(dvp);
+ }
+ return (0);
+}
+
+int
+nwfs_inactive(ap)
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct proc *p = ap->a_p;
+ struct ucred *cred = p->p_ucred;
+ struct vnode *vp = ap->a_vp;
+ struct nwnode *np = VTONW(vp);
+ int error;
+
+ NCPVNDEBUG("%s: %d\n", VTONW(vp)->n_name, vp->v_usecount);
+ if (np->opened) {
+ error = nwfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, p, cred);
+ np->opened = 0;
+ }
+ VOP_UNLOCK(vp, 0, p);
+ return (0);
+}
+/*
+ * routines to maintain vnode attributes cache
+ * nwfs_attr_cacheenter: unpack np.i to va structure
+ */
+void
+nwfs_attr_cacheenter(struct vnode *vp, struct nw_entry_info *fi) {
+ struct nwnode *np = VTONW(vp);
+ struct nwmount *nmp = VTONWFS(vp);
+ register struct vattr *va = &np->n_vattr;
+
+ va->va_type = vp->v_type; /* vnode type (for create) */
+ if (vp->v_type == VREG) {
+ if (va->va_size != fi->dataStreamSize) {
+ va->va_size = fi->dataStreamSize;
+ vnode_pager_setsize(vp, va->va_size);
+ }
+ va->va_mode = nmp->m.file_mode; /* files access mode and type */
+ } else if (vp->v_type == VDIR) {
+ va->va_size = 16384; /* should be a better way ... */
+ va->va_mode = nmp->m.dir_mode; /* files access mode and type */
+ } else
+ return;
+ np->n_size = va->va_size;
+ va->va_nlink = 1; /* number of references to file */
+ va->va_uid = nmp->m.uid; /* owner user id */
+ va->va_gid = nmp->m.gid; /* owner group id */
+ va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
+ va->va_fileid = np->n_fid.f_id; /* file id */
+ if (va->va_fileid == 0)
+ va->va_fileid = NWFS_ROOT_INO;
+ va->va_blocksize=nmp->connh->nh_conn->buffer_size;/* blocksize preferred for i/o */
+ /* time of last modification */
+ ncp_dos2unixtime(fi->modifyDate, fi->modifyTime, 0, &va->va_mtime);
+ /* time of last access */
+ ncp_dos2unixtime(fi->lastAccessDate, 0, 0, &va->va_atime);
+ va->va_ctime = va->va_mtime; /* time file changed */
+ va->va_gen = VNOVAL; /* generation number of file */
+ va->va_flags = 0; /* flags defined for file */
+ va->va_rdev = VNOVAL; /* device the special file represents */
+ va->va_bytes = va->va_size; /* bytes of disk space held by file */
+ va->va_filerev = 0; /* file modification number */
+ va->va_vaflags = 0; /* operations flags */
+ np->n_vattr = *va;
+ if (np->n_mtime == 0) {
+ np->n_mtime = va->va_mtime.tv_sec;
+ }
+ np->n_atime = time_second;
+ return;
+}
+
+int
+nwfs_attr_cachelookup(struct vnode *vp, struct vattr *va) {
+ struct nwnode *np = VTONW(vp);
+ int diff;
+
+ diff = time_second - np->n_atime;
+ if (diff > 2) { /* XXX should be configurable */
+ return ENOENT;
+ }
+ *va = np->n_vattr;
+ return 0;
+}
diff --git a/sys/fs/nwfs/nwfs_node.h b/sys/fs/nwfs/nwfs_node.h
new file mode 100644
index 0000000..c88c4b4
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_node.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NWFS_NODE_H_
+#define _NWFS_NODE_H_
+
+#define NWFS_ROOT_INO 0x7ffffffd
+#define NWFS_ROOTVOL "#.ROOT"
+
+/* Bits for nwnode.n_flag */
+#define NFLUSHINPROG 0x0001
+#define NFLUSHWANT 0x0002 /* they should gone ... */
+#define NMODIFIED 0x0004 /* bogus, until async IO implemented */
+#define NNEW 0x0008 /* vnode has been allocated */
+#define NVOLUME 0x0010 /* vnode references a volume */
+
+#ifndef VT_NWFS
+#define VT_NWFS VT_TFS
+#endif
+
+struct nwnode {
+ LIST_ENTRY(nwnode) n_hash;
+ struct vnode *n_vnode;
+ struct vattr n_vattr;
+ struct nwmount *n_mount;
+ time_t n_atime; /* attributes cache time*/
+ time_t n_ctime;
+ time_t n_mtime;
+ int n_flag;
+ ncpfid n_parent;
+ ncpfid n_fid;
+ int n_refparent;
+ u_long n_attr; /* LH */
+ u_long n_size;
+ u_long n_dosfid;
+ int opened;
+/* int access;*/
+ u_long n_origfh;
+ ncp_fh n_fh;
+ struct nw_search_seq n_seq;
+ u_char n_nmlen;
+ u_char n_name[256];
+};
+
+#define VTONW(vp) ((struct nwnode *)(vp)->v_data)
+#define NWTOV(np) ((struct vnode *)(np)->n_vnode)
+#define NWCMPF(f1,f2) ((f1)->f_parent == (f2)->f_parent && \
+ (f1)->f_id == (f2)->f_id)
+#define NWCMPN(np1,np2) NWCMPF(&(np1)->n_fid, &(np2)->n_fid)
+#define NWCMPV(vp1,vp2) NWCMPN(VTONW(vp1),VTONW(vp2))
+
+void nwfs_hash_init(void);
+void nwfs_hash_free(void);
+int nwfs_allocvp(struct mount *mp, ncpfid fid, struct vnode **vpp);
+int nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct nwnode **npp);
+int nwfs_inactive __P((struct vop_inactive_args *));
+int nwfs_reclaim __P((struct vop_reclaim_args *));
+int nwfs_nget(struct mount *mp, ncpfid fid, struct nw_entry_info *fap,
+ struct vnode *dvp, struct vnode **vpp);
+
+int nwfs_getpages __P((struct vop_getpages_args *));
+int nwfs_putpages __P((struct vop_putpages_args *));
+int nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred);
+int nwfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag);
+void nwfs_attr_cacheenter(struct vnode *vp, struct nw_entry_info *fi);
+int nwfs_attr_cachelookup(struct vnode *vp,struct vattr *va);
+
+#define nwfs_attr_cacheremove(vp) VTONW(vp)->n_atime = 0
+
+#endif /* _NWFS_NODE_H_ */
diff --git a/sys/fs/nwfs/nwfs_subr.c b/sys/fs/nwfs/nwfs_subr.c
new file mode 100644
index 0000000..d57d675
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_subr.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <machine/clock.h>
+#include <sys/time.h>
+#include <sys/namei.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_user.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/nwerror.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+MALLOC_DEFINE(M_NWFSDATA, "NWFS data", "NWFS private data");
+
+static void
+ncp_extract_file_info(struct nwmount *nmp, struct ncp_rq *rqp, struct nw_entry_info *target) {
+ u_char name_len;
+ const int info_struct_size = sizeof(struct nw_entry_info) - 257;
+
+ ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
+ name_len = ncp_rp_byte(rqp);
+ target->nameLen = name_len;
+ ncp_rp_mem(rqp,(caddr_t)target->entryName, name_len);
+ target->entryName[name_len] = '\0';
+ ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls);
+ return;
+}
+
+static void
+ncp_update_file_info(struct nwmount *nmp, struct ncp_rq *rqp,
+ struct nw_entry_info *target)
+{
+ int info_struct_size = sizeof(struct nw_entry_info) - 257;
+
+ ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
+ return;
+}
+
+int
+ncp_initsearch(struct vnode *dvp,struct proc *p,struct ucred *cred)
+{
+ struct nwmount *nmp = VTONWFS(dvp);
+ struct ncp_conn *conn = NWFSTOCONN(nmp);
+ struct nwnode *np = VTONW(dvp);
+ u_int8_t volnum = nmp->n_volume;
+ u_int32_t dirent = np->n_fid.f_id;
+ int error;
+ DECLARE_RQ;
+
+ NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent);
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 2); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* reserved */
+ ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
+ checkbad(ncp_request(conn,rqp));
+ ncp_rp_mem(rqp,(caddr_t)&np->n_seq, sizeof(np->n_seq));
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_search_for_file_or_subdir(struct nwmount *nmp,
+ struct nw_search_seq *seq,
+ struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred)
+{
+ struct ncp_conn *conn = NWFSTOCONN(nmp);
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 3); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* data stream */
+ ncp_rq_word_lh(rqp, 0xffff); /* Search attribs */
+ ncp_rq_dword(rqp, IM_ALL); /* return info mask */
+ ncp_rq_mem(rqp, (caddr_t)seq, 9);
+ ncp_rq_byte(rqp, 2); /* 2 byte pattern */
+ ncp_rq_byte(rqp, 0xff); /* following is a wildcard */
+ ncp_rq_byte(rqp, '*');
+ checkbad(ncp_request(conn,rqp));
+ ncp_rp_mem(rqp,(caddr_t)seq, sizeof(*seq));
+ ncp_rp_byte(rqp); /* skip */
+ ncp_extract_file_info(nmp, rqp, target);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+/*
+ * Returns information for a (one-component) name relative to the specified
+ * directory.
+ */
+int
+ncp_obtain_info(struct nwmount *nmp, u_int32_t dirent,
+ int namelen, char *path, struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred)
+{
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ int error;
+ u_char volnum = nmp->n_volume, ns;
+ DECLARE_RQ;
+
+ if (target == NULL) {
+ NCPFATAL("target == NULL\n");
+ return EINVAL;
+ }
+ ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space;
+ NCP_RQ_HEAD(87, p, cred);
+ ncp_rq_byte(rqp, 6); /* subfunction */
+ ncp_rq_byte(rqp, ns);
+ ncp_rq_byte(rqp, ns); /* DestNameSpace */
+ ncp_rq_word(rqp, htons(0xff00)); /* get all */
+ ncp_rq_dword(rqp, IM_ALL);
+ ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls);
+ checkbad(ncp_request(conn,rqp));
+ if (path)
+ ncp_extract_file_info(nmp, rqp, target);
+ else
+ ncp_update_file_info(nmp, rqp, target);
+ NCP_RQ_EXIT;
+ return error;
+}
+/*
+ * lookup name pointed by cnp in directory dvp and return file info in np.
+ * May be I should create a little cache, but another way is to minimize
+ * number of calls, on other hand, in multiprocess environment ...
+ */
+int
+ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
+ struct proc *p,struct ucred *cred)
+{
+ struct nwmount *nmp;
+ struct nwnode *dnp = VTONW(dvp);
+ struct ncp_conn *conn;
+ int error;
+
+ if (!dvp || dvp->v_type != VDIR) {
+ nwfs_printf("dvp is NULL or not a directory.\n");
+ return (ENOENT);
+ }
+ nmp = VTONWFS(dvp);
+ conn = NWFSTOCONN(nmp);
+
+ if (len == 1 && name[0] == '.') {
+ if (strcmp(dnp->n_name, NWFS_ROOTVOL) == 0) {
+ error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL,
+ fap, p, cred);
+ } else {
+ error = ncp_obtain_info(nmp, dnp->n_fid.f_parent,
+ dnp->n_nmlen, dnp->n_name, fap, p, cred);
+ }
+ return error;
+ } else if (len == 2 && name[0] == '.' && name[1] == '.') {
+ printf("%s: knows NOTHING about '..'\n", __FUNCTION__);
+ return EIO;
+ } else {
+ error = ncp_obtain_info(nmp, dnp->n_fid.f_id,
+ len, name, fap, p, cred);
+ }
+ return error;
+}
+
+static void ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh);
+static void
+ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
+ fh->val1 = (fh->val.val32 = sfd);
+ return;
+}
+
+/*
+ * If both dir and name are NULL, then in target there's already a looked-up
+ * entry that wants to be opened.
+ */
+int
+ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp,int namelen,
+ char *name, int open_create_mode, u_int32_t create_attributes,
+ int desired_acc_rights, struct ncp_open_info *nop,
+ struct proc *p,struct ucred *cred)
+{
+
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES);
+ u_int8_t volnum;
+ u_int32_t dirent;
+ int error;
+ DECLARE_RQ;
+
+ volnum = nmp->n_volume;
+ dirent = VTONW(dvp)->n_fid.f_id;
+ if ((create_attributes & aDIR) != 0) {
+ search_attribs |= SA_SUBDIR_FILES;
+ }
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 1);/* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, open_create_mode);
+ ncp_rq_word(rqp, search_attribs);
+ ncp_rq_dword(rqp, IM_ALL);
+ ncp_rq_dword(rqp, create_attributes);
+ /*
+ * The desired acc rights seem to be the inherited rights mask for
+ * directories
+ */
+ ncp_rq_word(rqp, desired_acc_rights);
+ ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls);
+ checkbad(ncp_request(conn,rqp));
+
+ nop->origfh = ncp_rp_dword_lh(rqp);
+ nop->action = ncp_rp_byte(rqp);
+ ncp_rp_byte(rqp); /* skip */
+ ncp_extract_file_info(nmp, rqp, &nop->fattr);
+ ConvertToNWfromDWORD(nop->origfh, &nop->fh);
+ NCP_RQ_EXIT;
+ switch(error) {
+ case NWE_FILE_NO_CREATE_PRIV:
+ error = EACCES;
+ break;
+ }
+ return error;
+}
+
+int
+ncp_close_file(struct ncp_conn *conn, ncp_fh *fh,struct proc *p,struct ucred *cred) {
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(66,p,cred);
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_mem(rqp, (caddr_t)fh, 6);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_DeleteNSEntry(struct nwmount *nmp, u_int32_t dirent,
+ int namelen,char *name,struct proc *p,struct ucred *cred)
+{
+ int error;
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 8); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* reserved */
+ ncp_rq_word(rqp, SA_ALL); /* search attribs: all */
+ ncp_rq_dbase_path(rqp, nmp->n_volume, dirent, namelen, name, &nmp->m.nls);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype,
+ struct ncp_nlstables *nt,
+ nwdirent fdir, char *old_name, int oldlen,
+ nwdirent tdir, char *new_name, int newlen,
+ struct proc *p, struct ucred *cred)
+{
+ DECLARE_RQ;
+ int error;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 4);
+ ncp_rq_byte(rqp, ns);
+ ncp_rq_byte(rqp, 1);
+ ncp_rq_word(rqp, oldtype);
+ /* source Handle Path */
+ ncp_rq_byte(rqp, volume);
+ ncp_rq_dword(rqp, fdir);
+ ncp_rq_byte(rqp, 1);
+ ncp_rq_byte(rqp, 1); /* 1 source component */
+ /* dest Handle Path */
+ ncp_rq_byte(rqp, volume);
+ ncp_rq_dword(rqp, tdir);
+ ncp_rq_byte(rqp, 1);
+ ncp_rq_byte(rqp, 1); /* 1 destination component */
+ ncp_rq_pathstring(rqp, oldlen, old_name, nt);
+ ncp_rq_pathstring(rqp, newlen, new_name, nt);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp,
+ u_int32_t info_mask,
+ struct nw_modify_dos_info *info,
+ struct proc *p,struct ucred *cred)
+{
+ struct nwnode *np=VTONW(vp);
+ u_int8_t volnum = nmp->n_volume;
+ u_int32_t dirent = np->n_fid.f_id;
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 7); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* reserved */
+ ncp_rq_word(rqp, htons(0x0680)); /* search attribs: all */
+ ncp_rq_dword(rqp, info_mask);
+ ncp_rq_mem(rqp, (caddr_t)info, sizeof(*info));
+ ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_setattr(vp, vap, cred, procp)
+ register struct vnode *vp;
+ register struct vattr *vap;
+ struct ucred *cred;
+ struct proc *procp;
+{
+ struct nwmount *nmp=VTONWFS(vp);
+ struct nwnode *np=VTONW(vp);
+ struct ncp_open_info nwn;
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ struct nw_modify_dos_info info;
+ int error = 0, info_mask;
+ DECLARE_RQ;
+
+ if (vap->va_size != VNOVAL) {
+ error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
+ AR_WRITE | AR_READ, &nwn,procp,cred);
+ if (error) return error;
+ NCP_RQ_HEAD(73,procp,cred);
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_mem(rqp, (caddr_t)&nwn.fh, 6);
+ ncp_rq_dword(rqp, htonl(vap->va_size));
+ ncp_rq_word_hl(rqp, 0);
+ checkbad(ncp_request(conn,rqp));
+ np->n_vattr.va_size = np->n_size = vap->va_size;
+ NCP_RQ_EXIT;
+ ncp_close_file(conn, &nwn.fh, procp, cred);
+ if (error) return error;
+ }
+ info_mask = 0;
+ bzero(&info, sizeof(info));
+
+ if (vap->va_mtime.tv_sec != VNOVAL) {
+ info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
+ ncp_unix2dostime(&vap->va_mtime, &info.modifyDate, &info.modifyTime, NULL);
+ }
+ if (vap->va_atime.tv_sec != VNOVAL) {
+ info_mask |= (DM_LAST_ACCESS_DATE);
+ ncp_unix2dostime(&vap->va_atime, &info.lastAccessDate,NULL,NULL);
+ }
+ if (info_mask) {
+ error = ncp_modify_file_or_subdir_dos_info(nmp, vp, info_mask, &info,procp,cred);
+ }
+ return (error);
+}
+
+int
+ncp_get_volume_info_with_number(struct ncp_conn *conn,
+ int n, struct ncp_volume_info *target,
+ struct proc *p,struct ucred *cred) {
+ int error,len;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD_S(22,44,p,cred);
+ ncp_rq_byte(rqp,n);
+ checkbad(ncp_request(conn,rqp));
+ target->total_blocks = ncp_rp_dword_lh(rqp);
+ target->free_blocks = ncp_rp_dword_lh(rqp);
+ target->purgeable_blocks = ncp_rp_dword_lh(rqp);
+ target->not_yet_purgeable_blocks = ncp_rp_dword_lh(rqp);
+ target->total_dir_entries = ncp_rp_dword_lh(rqp);
+ target->available_dir_entries = ncp_rp_dword_lh(rqp);
+ ncp_rp_dword_lh(rqp);
+ target->sectors_per_block = ncp_rp_byte(rqp);
+ bzero(&target->volume_name, sizeof(target->volume_name));
+ len = ncp_rp_byte(rqp);
+ if (len > NCP_VOLNAME_LEN) {
+ error = ENAMETOOLONG;
+ } else {
+ ncp_rp_mem(rqp,(caddr_t)&target->volume_name, len);
+ }
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
+ struct proc *p,struct ucred *cred) {
+ int error;
+ u_int8_t ns;
+ u_int16_t nscnt;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 24); /* Subfunction: Get Loaded Name Spaces */
+ ncp_rq_word(rqp, 0);
+ ncp_rq_byte(rqp, volume);
+ checkbad(ncp_request(conn,rqp));
+ nscnt = ncp_rp_word_lh(rqp);
+ *nsf = 0;
+ while (nscnt-- > 0) {
+ ns = ncp_rp_byte(rqp);
+ *nsf |= 1 << ns;
+ }
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_lookup_volume(struct ncp_conn *conn, char *volname,
+ u_char *volNum, u_int32_t *dirEnt,
+ struct proc *p,struct ucred *cred)
+{
+ int error;
+ DECLARE_RQ;
+
+ NCPNDEBUG("looking up vol %s\n", volname);
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 22); /* Subfunction: Generate dir handle */
+ ncp_rq_byte(rqp, 0); /* src name space */
+ ncp_rq_byte(rqp, 0); /* dst name space, always zero */
+ ncp_rq_word(rqp, 0); /* dstNSIndicator */
+
+ ncp_rq_byte(rqp, 0); /* faked volume number */
+ ncp_rq_dword(rqp, 0); /* faked dir_base */
+ ncp_rq_byte(rqp, 0xff); /* Don't have a dir_base */
+ ncp_rq_byte(rqp, 1); /* 1 path component */
+ ncp_rq_pstring(rqp, volname);
+ checkbad(ncp_request(conn,rqp));
+ ncp_rp_dword_lh(rqp); /* NSDirectoryBase*/
+ *dirEnt = ncp_rp_dword_lh(rqp);
+ *volNum = ncp_rp_byte(rqp);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+/*
+ * Time & date conversion routines taken from msdosfs. Although leap
+ * year calculation is bogus, it's sufficient before 2100 :)
+ */
+/*
+ * This is the format of the contents of the deTime field in the direntry
+ * structure.
+ * We don't use bitfields because we don't know how compilers for
+ * arbitrary machines will lay them out.
+ */
+#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
+#define DT_2SECONDS_SHIFT 0
+#define DT_MINUTES_MASK 0x7E0 /* minutes */
+#define DT_MINUTES_SHIFT 5
+#define DT_HOURS_MASK 0xF800 /* hours */
+#define DT_HOURS_SHIFT 11
+
+/*
+ * This is the format of the contents of the deDate field in the direntry
+ * structure.
+ */
+#define DD_DAY_MASK 0x1F /* day of month */
+#define DD_DAY_SHIFT 0
+#define DD_MONTH_MASK 0x1E0 /* month */
+#define DD_MONTH_SHIFT 5
+#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
+#define DD_YEAR_SHIFT 9
+/*
+ * Total number of days that have passed for each month in a regular year.
+ */
+static u_short regyear[] = {
+ 31, 59, 90, 120, 151, 181,
+ 212, 243, 273, 304, 334, 365
+};
+
+/*
+ * Total number of days that have passed for each month in a leap year.
+ */
+static u_short leapyear[] = {
+ 31, 60, 91, 121, 152, 182,
+ 213, 244, 274, 305, 335, 366
+};
+
+/*
+ * Variables used to remember parts of the last time conversion. Maybe we
+ * can avoid a full conversion.
+ */
+static u_long lasttime;
+static u_long lastday;
+static u_short lastddate;
+static u_short lastdtime;
+/*
+ * Convert the unix version of time to dos's idea of time to be used in
+ * file timestamps. The passed in unix time is assumed to be in GMT.
+ */
+void
+ncp_unix2dostime(tsp, ddp, dtp, dhp)
+ struct timespec *tsp;
+ u_int16_t *ddp;
+ u_int16_t *dtp;
+ u_int8_t *dhp;
+{
+ u_long t;
+ u_long days;
+ u_long inc;
+ u_long year;
+ u_long month;
+ u_short *months;
+
+ /*
+ * If the time from the last conversion is the same as now, then
+ * skip the computations and use the saved result.
+ */
+ t = tsp->tv_sec - (tz.tz_minuteswest * 60)
+ - (wall_cmos_clock ? adjkerntz : 0);
+ /* - daylight savings time correction */
+ t &= ~1;
+ if (lasttime != t) {
+ lasttime = t;
+ lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ + (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ + (((t / 3600) % 24) << DT_HOURS_SHIFT);
+
+ /*
+ * If the number of days since 1970 is the same as the last
+ * time we did the computation then skip all this leap year
+ * and month stuff.
+ */
+ days = t / (24 * 60 * 60);
+ if (days != lastday) {
+ lastday = days;
+ for (year = 1970;; year++) {
+ inc = year & 0x03 ? 365 : 366;
+ if (days < inc)
+ break;
+ days -= inc;
+ }
+ months = year & 0x03 ? regyear : leapyear;
+ for (month = 0; days >= months[month]; month++)
+ ;
+ if (month > 0)
+ days -= months[month - 1];
+ lastddate = ((days + 1) << DD_DAY_SHIFT)
+ + ((month + 1) << DD_MONTH_SHIFT);
+ /*
+ * Remember dos's idea of time is relative to 1980.
+ * unix's is relative to 1970. If somehow we get a
+ * time before 1980 then don't give totally crazy
+ * results.
+ */
+ if (year > 1980)
+ lastddate += (year - 1980) << DD_YEAR_SHIFT;
+ }
+ }
+ if (dtp)
+ *dtp = lastdtime;
+ if (dhp)
+ *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
+
+ *ddp = lastddate;
+}
+
+/*
+ * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
+ * interval there were 8 regular years and 2 leap years.
+ */
+#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
+
+static u_short lastdosdate;
+static u_long lastseconds;
+
+/*
+ * Convert from dos' idea of time to unix'. This will probably only be
+ * called from the stat(), and fstat() system calls and so probably need
+ * not be too efficient.
+ */
+void
+ncp_dos2unixtime(dd, dt, dh, tsp)
+ u_int dd;
+ u_int dt;
+ u_int dh;
+ struct timespec *tsp;
+{
+ u_long seconds;
+ u_long month;
+ u_long year;
+ u_long days;
+ u_short *months;
+
+ if (dd == 0) {
+ /*
+ * Uninitialized field, return the epoch.
+ */
+ tsp->tv_sec = 0;
+ tsp->tv_nsec = 0;
+ return;
+ }
+ seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+ + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+ + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+ + dh / 100;
+ /*
+ * If the year, month, and day from the last conversion are the
+ * same then use the saved value.
+ */
+ if (lastdosdate != dd) {
+ lastdosdate = dd;
+ days = 0;
+ year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
+ days = year * 365;
+ days += year / 4 + 1; /* add in leap days */
+ if ((year & 0x03) == 0)
+ days--; /* if year is a leap year */
+ months = year & 0x03 ? regyear : leapyear;
+ month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
+ if (month < 1 || month > 12) {
+ month = 1;
+ }
+ if (month > 1)
+ days += months[month - 2];
+ days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
+ lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
+ }
+ tsp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
+ + adjkerntz;
+ /* + daylight savings time correction */
+ tsp->tv_nsec = (dh % 100) * 10000000;
+}
diff --git a/sys/fs/nwfs/nwfs_subr.h b/sys/fs/nwfs/nwfs_subr.h
new file mode 100644
index 0000000..6112933
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_subr.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NWFS_SUBR_H_
+#define _NWFS_SUBR_H_
+
+extern int nwfs_debuglevel;
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_NWFSDATA);
+#endif
+
+int ncp_initsearch(struct vnode *dvp,struct proc *p,struct ucred *cred);
+int ncp_search_for_file_or_subdir(struct nwmount *nmp,struct nw_search_seq *seq,
+ struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred);
+int ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
+ struct proc *p,struct ucred *cred);
+int ncp_lookup_volume(struct ncp_conn *conn, char *volname,
+ u_char *volNum, u_int32_t *dirEnt,
+ struct proc *p,struct ucred *cred);
+int ncp_close_file(struct ncp_conn *conn, ncp_fh *fh,
+ struct proc *p,struct ucred *cred);
+int ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp, int namelen,char *name,
+ int open_create_mode, u_int32_t create_attributes,
+ int desired_acc_rights, struct ncp_open_info *nop,
+ struct proc *p,struct ucred *cred);
+int ncp_DeleteNSEntry(struct nwmount *nmp,
+ u_int32_t dirent, int namelen, char *name,
+ struct proc *p,struct ucred *cred);
+int ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype,
+ struct ncp_nlstables *nt,
+ nwdirent fdir, char *old_name, int oldlen,
+ nwdirent tdir, char *new_name, int newlen,
+ struct proc *p, struct ucred *cred);
+int ncp_obtain_info(struct nwmount *nmp, u_int32_t dirent,
+ int namelen, char *path, struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred);
+int ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp,
+ u_int32_t info_mask,
+ struct nw_modify_dos_info *info,
+ struct proc *p,struct ucred *cred);
+int ncp_setattr(struct vnode *,struct vattr *,struct ucred *,struct proc *);
+int ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
+ struct proc *p,struct ucred *cred);
+int ncp_get_volume_info_with_number(struct ncp_conn *conn,
+ int n, struct ncp_volume_info *target,
+ struct proc *p,struct ucred *cred);
+
+void ncp_unix2dostime __P((struct timespec *tsp, u_int16_t *ddp,
+ u_int16_t *dtp, u_int8_t *dhp));
+void ncp_dos2unixtime __P((u_int dd, u_int dt, u_int dh, struct timespec *tsp));
+
+#endif /* !_NWFS_SUBR_H_ */
diff --git a/sys/fs/nwfs/nwfs_vfsops.c b/sys/fs/nwfs/nwfs_vfsops.c
new file mode 100644
index 0000000..53ecf98
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_vfsops.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "opt_ncp.h"
+#ifndef NCP
+#error "NWFS requires NCP protocol"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/ncp_nls.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+int nwfs_debuglevel = 0;
+
+static int nwfs_version = NWFS_VERSION;
+
+SYSCTL_DECL(_vfs_nwfs);
+SYSCTL_NODE(_vfs, OID_AUTO, nwfs, CTLFLAG_RW, 0, "Netware file system");
+SYSCTL_INT(_vfs_nwfs, OID_AUTO, version, CTLFLAG_RD, &nwfs_version, 0, "");
+SYSCTL_INT(_vfs_nwfs, OID_AUTO, debuglevel, CTLFLAG_RW, &nwfs_debuglevel, 0, "");
+
+static int nwfs_mount __P((struct mount *, char *, caddr_t,
+ struct nameidata *, struct proc *));
+static int nwfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
+ struct proc *));
+static int nwfs_root __P((struct mount *, struct vnode **));
+static int nwfs_start __P((struct mount *, int, struct proc *));
+static int nwfs_statfs __P((struct mount *, struct statfs *,
+ struct proc *));
+static int nwfs_sync __P((struct mount *, int, struct ucred *,
+ struct proc *));
+static int nwfs_unmount __P((struct mount *, int, struct proc *));
+static int nwfs_init __P((struct vfsconf *vfsp));
+static int nwfs_uninit __P((struct vfsconf *vfsp));
+
+static struct vfsops nwfs_vfsops = {
+ nwfs_mount,
+ nwfs_start,
+ nwfs_unmount,
+ nwfs_root,
+ nwfs_quotactl,
+ nwfs_statfs,
+ nwfs_sync,
+ vfs_stdvget,
+ vfs_stdfhtovp, /* shouldn't happen */
+ vfs_stdcheckexp,
+ vfs_stdvptofh, /* shouldn't happen */
+ nwfs_init,
+ nwfs_uninit
+};
+
+
+VFS_SET(nwfs_vfsops, nwfs, VFCF_NETWORK);
+
+int nwfs_pbuf_freecnt = -1; /* start out unlimited */
+static int nwfsid = 1;
+
+static int
+nwfs_initnls(struct nwmount *nmp) {
+ char *pc, *pe;
+ int error = 0;
+#define COPY_TABLE(t,d) { \
+ if (t) { \
+ error = copyin((t), pc, 256); \
+ if (error) break; \
+ } else \
+ bcopy(d, pc, 256); \
+ (t) = pc; pc += 256; \
+ }
+
+ nmp->m.nls.opt |= NWHP_NLS | NWHP_DOS;
+ if ((nmp->m.flags & NWFS_MOUNT_HAVE_NLS) == 0) {
+ nmp->m.nls.tolower = ncp_defnls.tolower;
+ nmp->m.nls.toupper = ncp_defnls.toupper;
+ nmp->m.nls.n2u = ncp_defnls.n2u;
+ nmp->m.nls.u2n = ncp_defnls.u2n;
+ return 0;
+ }
+ MALLOC(pe, char *, 256 * 4, M_NWFSDATA, M_WAITOK);
+ if (pe == NULL) return ENOMEM;
+ pc = pe;
+ do {
+ COPY_TABLE(nmp->m.nls.tolower, ncp_defnls.tolower);
+ COPY_TABLE(nmp->m.nls.toupper, ncp_defnls.toupper);
+ COPY_TABLE(nmp->m.nls.n2u, ncp_defnls.n2u);
+ COPY_TABLE(nmp->m.nls.u2n, ncp_defnls.u2n);
+ } while(0);
+ if (error) {
+ free(pe, M_NWFSDATA);
+ return error;
+ }
+ return 0;
+}
+/*
+ * mp - path - addr in user space of mount point (ie /usr or whatever)
+ * data - addr in user space of mount params
+ */
+static int nwfs_mount(struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct nwfs_args args; /* will hold data from mount request */
+ size_t size;
+ int error;
+ struct nwmount *nmp = NULL;
+ struct ncp_conn *conn = NULL;
+ struct ncp_handle *handle = NULL;
+ struct vnode *vp;
+ char *pc,*pe;
+
+ if (data == NULL) {
+ nwfs_printf("missing data argument\n");
+ return 1;
+ }
+ if (mp->mnt_flag & MNT_UPDATE) {
+ nwfs_printf("MNT_UPDATE not implemented");
+ return (EOPNOTSUPP);
+ }
+ error = copyin(data, (caddr_t)&args, sizeof(struct nwfs_args));
+ if (error)
+ return (error);
+ if (args.version != NWFS_VERSION) {
+ nwfs_printf("mount version mismatch: kernel=%d, mount=%d\n",NWFS_VERSION,args.version);
+ return (1);
+ }
+ error = ncp_conn_getbyref(args.connRef,p,p->p_ucred,NCPM_EXECUTE,&conn);
+ if (error) {
+ nwfs_printf("invalid connection refernce %d\n",args.connRef);
+ return (error);
+ }
+ error = ncp_conn_gethandle(conn, NULL, &handle);
+ if (error) {
+ nwfs_printf("can't get connection handle\n");
+ return (error);
+ }
+ ncp_conn_unlock(conn,p); /* we keep the ref */
+ mp->mnt_stat.f_iosize = conn->buffer_size;
+ /* We must malloc our own mount info */
+ MALLOC(nmp,struct nwmount *,sizeof(struct nwmount),M_NWFSDATA,M_USE_RESERVE);
+ if (nmp == NULL) {
+ nwfs_printf("could not alloc nwmount\n");
+ error = ENOMEM;
+ goto bad;
+ }
+ bzero(nmp,sizeof(*nmp));
+ mp->mnt_data = (qaddr_t)nmp;
+ nmp->connh = handle;
+ nmp->n_root = NULL;
+ nmp->n_id = nwfsid++;
+ nmp->m = args;
+ nmp->m.file_mode = (nmp->m.file_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
+ nmp->m.dir_mode = (nmp->m.dir_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
+ if ((error = nwfs_initnls(nmp)) != 0) goto bad;
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ pc = mp->mnt_stat.f_mntfromname;
+ pe = pc+sizeof(mp->mnt_stat.f_mntfromname);
+ bzero(pc, MNAMELEN);
+ *(pc++) = '/';
+ pc = index(strncpy(pc, conn->li.server, pe-pc-2),0);
+ if (pc < pe-1) {
+ *(pc++) = ':';
+ pc=index(strncpy(pc, conn->li.user, pe-pc-2),0);
+ if (pc < pe-1) {
+ *(pc++) = '/';
+ strncpy(pc, nmp->m.mounted_vol, pe-pc-2);
+ }
+ }
+ /* protect against invalid mount points */
+ nmp->m.mount_point[sizeof(nmp->m.mount_point)-1] = '\0';
+ vfs_getnewfsid(mp);
+ error = nwfs_root(mp, &vp);
+ if (error)
+ goto bad;
+ /*
+ * Lose the lock but keep the ref.
+ */
+ VOP_UNLOCK(vp, 0, curproc);
+ NCPVODEBUG("rootvp.vrefcnt=%d\n",vp->v_usecount);
+ return error;
+bad:
+ if (nmp)
+ free(nmp, M_NWFSDATA);
+ if (handle)
+ ncp_conn_puthandle(handle, NULL, 0);
+ return error;
+}
+
+/* Unmount the filesystem described by mp. */
+static int
+nwfs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct nwmount *nmp = VFSTONWFS(mp);
+ struct ncp_conn *conn;
+ struct vnode *vp;
+ int error, flags;
+
+ NCPVODEBUG("nwfs_unmount: flags=%04x\n",mntflags);
+ flags = 0;
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+ error = VFS_ROOT(mp,&vp);
+ if (error) return (error);
+ if (vp->v_usecount > 2) {
+ printf("nwfs_unmount: usecnt=%d\n",vp->v_usecount);
+ vput(vp);
+ return (EBUSY);
+ }
+ error = vflush(mp, vp, flags);
+ if (error) {
+ vput(vp);
+ return (error);
+ }
+ /*
+ * There are two reference counts and one lock to get rid of here.
+ */
+ NCPVODEBUG("v_use: %d\n",vp->v_usecount);
+ vput(vp);
+ NCPVODEBUG("v_use after vput: %d\n",vp->v_usecount);
+ vrele(vp);
+ NCPVODEBUG("v_use after vrele: %d\n",vp->v_usecount);
+ vgone(vp);
+ NCPVODEBUG("v_gone finished !!!!\n");
+ conn = NWFSTOCONN(nmp);
+ ncp_conn_puthandle(nmp->connh,NULL,0);
+ if (ncp_conn_lock(conn,p,p->p_ucred,NCPM_WRITE | NCPM_EXECUTE) == 0) {
+ if(ncp_disconnect(conn))
+ ncp_conn_unlock(conn,p);
+ }
+ mp->mnt_data = (qaddr_t)0;
+ if (nmp->m.flags & NWFS_MOUNT_HAVE_NLS)
+ free(nmp->m.nls.tolower, M_NWFSDATA);
+ free(nmp, M_NWFSDATA);
+ mp->mnt_flag &= ~MNT_LOCAL;
+ return (error);
+}
+
+/* Return locked vnode to root of a filesystem */
+static int
+nwfs_root(struct mount *mp, struct vnode **vpp) {
+ struct vnode *vp;
+ struct nwmount *nmp;
+ struct nwnode *np;
+ struct ncp_conn *conn;
+ struct nw_entry_info fattr;
+ struct proc *p = curproc;
+ struct ucred *cred = p->p_ucred;
+ int error, nsf, opt;
+ u_char vol;
+
+ nmp = VFSTONWFS(mp);
+ conn = NWFSTOCONN(nmp);
+ if (nmp->n_root) {
+ *vpp = NWTOV(nmp->n_root);
+ vget(*vpp, LK_EXCLUSIVE, curproc);
+ return 0;
+ }
+ error = ncp_lookup_volume(conn, nmp->m.mounted_vol, &vol,
+ &nmp->n_rootent.f_id, p, cred);
+ if (error)
+ return ENOENT;
+ nmp->n_volume = vol;
+ error = ncp_get_namespaces(conn, vol, &nsf, p, cred);
+ if (error)
+ return ENOENT;
+ if (nsf & NW_NSB_OS2) {
+ NCPVODEBUG("volume %s has os2 namespace\n",nmp->m.mounted_vol);
+ if ((nmp->m.flags & NWFS_MOUNT_NO_OS2) == 0) {
+ nmp->name_space = NW_NS_OS2;
+ nmp->m.nls.opt &= ~NWHP_DOS;
+ }
+ }
+ opt = nmp->m.nls.opt;
+ nsf = opt & (NWHP_UPPER | NWHP_LOWER);
+ if (opt & NWHP_DOS) {
+ if (nsf == (NWHP_UPPER | NWHP_LOWER)) {
+ nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER);
+ } else if (nsf == 0) {
+ nmp->m.nls.opt |= NWHP_LOWER;
+ }
+ } else {
+ if (nsf == (NWHP_UPPER | NWHP_LOWER)) {
+ nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER);
+ }
+ }
+ if (nmp->m.root_path[0]) {
+ nmp->m.root_path[0]--;
+ error = ncp_obtain_info(nmp, nmp->n_rootent.f_id,
+ -nmp->m.root_path[0], nmp->m.root_path, &fattr, p, cred);
+ if (error) {
+ NCPFATAL("Invalid root path specified\n");
+ return ENOENT;
+ }
+ nmp->n_rootent.f_parent = fattr.dirEntNum;
+ nmp->m.root_path[0]++;
+ error = ncp_obtain_info(nmp, nmp->n_rootent.f_id,
+ -nmp->m.root_path[0], nmp->m.root_path, &fattr, p, cred);
+ if (error) {
+ NCPFATAL("Invalid root path specified\n");
+ return ENOENT;
+ }
+ nmp->n_rootent.f_id = fattr.dirEntNum;
+ } else {
+ error = ncp_obtain_info(nmp, nmp->n_rootent.f_id,
+ 0, NULL, &fattr, p, cred);
+ if (error) {
+ NCPFATAL("Can't obtain volume info\n");
+ return ENOENT;
+ }
+ fattr.nameLen = strlen(strcpy(fattr.entryName, NWFS_ROOTVOL));
+ nmp->n_rootent.f_parent = nmp->n_rootent.f_id;
+ }
+ error = nwfs_nget(mp, nmp->n_rootent, &fattr, NULL, &vp);
+ if (error)
+ return (error);
+ vp->v_flag |= VROOT;
+ np = VTONW(vp);
+ if (nmp->m.root_path[0] == 0)
+ np->n_flag |= NVOLUME;
+ nmp->n_root = np;
+/* error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) {
+ vput(vp);
+ NCPFATAL("Can't get root directory entry\n");
+ return error;
+ }*/
+ *vpp = vp;
+ return (0);
+}
+
+/*
+ * Vfs start routine, a no-op.
+ */
+/* ARGSUSED */
+static int
+nwfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+ NCPVODEBUG("flags=%04x\n",flags);
+ return (0);
+}
+
+/*
+ * Do operations associated with quotas, not supported
+ */
+/* ARGSUSED */
+static int
+nwfs_quotactl(mp, cmd, uid, arg, p)
+ struct mount *mp;
+ int cmd;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
+{
+ NCPVODEBUG("return EOPNOTSUPP\n");
+ return (EOPNOTSUPP);
+}
+
+/*ARGSUSED*/
+int
+nwfs_init(struct vfsconf *vfsp)
+{
+
+ nwfs_hash_init();
+ nwfs_pbuf_freecnt = nswbuf / 2 + 1;
+ NCPVODEBUG("always happy to load!\n");
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nwfs_uninit(struct vfsconf *vfsp)
+{
+
+ nwfs_hash_free();
+ NCPVODEBUG("unloaded\n");
+ return (0);
+}
+
+/*
+ * nwfs_statfs call
+ */
+int
+nwfs_statfs(mp, sbp, p)
+ struct mount *mp;
+ register struct statfs *sbp;
+ struct proc *p;
+{
+ struct nwmount *nmp = VFSTONWFS(mp);
+ int error = 0, secsize;
+ struct nwnode *np = nmp->n_root;
+ struct ncp_volume_info vi;
+
+ if (np == NULL) return EINVAL;
+ error = ncp_get_volume_info_with_number(NWFSTOCONN(nmp), nmp->n_volume, &vi,p,p->p_ucred);
+ if (error) return error;
+ secsize = 512; /* XXX how to get real value ??? */
+ sbp->f_spare2=0; /* placeholder */
+ /* fundamental file system block size */
+ sbp->f_bsize = vi.sectors_per_block*secsize;
+ /* optimal transfer block size */
+ sbp->f_iosize = NWFSTOCONN(nmp)->buffer_size;
+ /* total data blocks in file system */
+ sbp->f_blocks= vi.total_blocks;
+ /* free blocks in fs */
+ sbp->f_bfree = vi.free_blocks + vi.purgeable_blocks;
+ /* free blocks avail to non-superuser */
+ sbp->f_bavail= vi.free_blocks+vi.purgeable_blocks;
+ /* total file nodes in file system */
+ sbp->f_files = vi.total_dir_entries;
+ /* free file nodes in fs */
+ sbp->f_ffree = vi.available_dir_entries;
+ sbp->f_flags = 0; /* copy of mount exported flags */
+ if (sbp != &mp->mnt_stat) {
+ sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */
+ sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
+ sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return 0;
+}
+
+/*
+ * Flush out the buffer cache
+ */
+/* ARGSUSED */
+static int
+nwfs_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
+{
+ register struct vnode *vp;
+ int error, allerror = 0;
+ /*
+ * Force stale buffer cache information to be flushed.
+ */
+loop:
+ for (vp = mp->mnt_vnodelist.lh_first;
+ vp != NULL;
+ vp = vp->v_mntvnodes.le_next) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * associated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
+ goto loop;
+ if (VOP_ISLOCKED(vp) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+ waitfor == MNT_LAZY)
+ continue;
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ error = VOP_FSYNC(vp, cred, waitfor, p);
+ if (error)
+ allerror = error;
+ vput(vp);
+ }
+ return (allerror);
+}
diff --git a/sys/fs/nwfs/nwfs_vnops.c b/sys/fs/nwfs/nwfs_vnops.c
new file mode 100644
index 0000000..ab9f220
--- /dev/null
+++ b/sys/fs/nwfs/nwfs_vnops.c
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/ioccom.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+#include <vm/vnode_pager.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/nwerror.h>
+#include <netncp/ncp_nls.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+/*
+ * Prototypes for NWFS vnode operations
+ */
+static int nwfs_create __P((struct vop_create_args *));
+static int nwfs_mknod __P((struct vop_mknod_args *));
+static int nwfs_open __P((struct vop_open_args *));
+static int nwfs_close __P((struct vop_close_args *));
+static int nwfs_access __P((struct vop_access_args *));
+static int nwfs_getattr __P((struct vop_getattr_args *));
+static int nwfs_setattr __P((struct vop_setattr_args *));
+static int nwfs_read __P((struct vop_read_args *));
+static int nwfs_write __P((struct vop_write_args *));
+static int nwfs_fsync __P((struct vop_fsync_args *));
+static int nwfs_remove __P((struct vop_remove_args *));
+static int nwfs_link __P((struct vop_link_args *));
+static int nwfs_lookup __P((struct vop_lookup_args *));
+static int nwfs_rename __P((struct vop_rename_args *));
+static int nwfs_mkdir __P((struct vop_mkdir_args *));
+static int nwfs_rmdir __P((struct vop_rmdir_args *));
+static int nwfs_symlink __P((struct vop_symlink_args *));
+static int nwfs_readdir __P((struct vop_readdir_args *));
+static int nwfs_abortop __P((struct vop_abortop_args *));
+static int nwfs_bmap __P((struct vop_bmap_args *));
+static int nwfs_strategy __P((struct vop_strategy_args *));
+static int nwfs_print __P((struct vop_print_args *));
+static int nwfs_pathconf __P((struct vop_pathconf_args *ap));
+
+/* Global vfs data structures for nwfs */
+vop_t **nwfs_vnodeop_p;
+static struct vnodeopv_entry_desc nwfs_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) vop_defaultop },
+ { &vop_abortop_desc, (vop_t *) nwfs_abortop },
+ { &vop_access_desc, (vop_t *) nwfs_access },
+ { &vop_bmap_desc, (vop_t *) nwfs_bmap },
+ { &vop_open_desc, (vop_t *) nwfs_open },
+ { &vop_close_desc, (vop_t *) nwfs_close },
+ { &vop_create_desc, (vop_t *) nwfs_create },
+ { &vop_fsync_desc, (vop_t *) nwfs_fsync },
+ { &vop_getattr_desc, (vop_t *) nwfs_getattr },
+ { &vop_getpages_desc, (vop_t *) nwfs_getpages },
+ { &vop_putpages_desc, (vop_t *) nwfs_putpages },
+ { &vop_ioctl_desc, (vop_t *) nwfs_ioctl },
+ { &vop_inactive_desc, (vop_t *) nwfs_inactive },
+ { &vop_islocked_desc, (vop_t *) vop_noislocked },
+ { &vop_link_desc, (vop_t *) nwfs_link },
+ { &vop_lock_desc, (vop_t *) vop_sharedlock },
+ { &vop_lookup_desc, (vop_t *) nwfs_lookup },
+ { &vop_mkdir_desc, (vop_t *) nwfs_mkdir },
+ { &vop_mknod_desc, (vop_t *) nwfs_mknod },
+ { &vop_pathconf_desc, (vop_t *) nwfs_pathconf },
+ { &vop_print_desc, (vop_t *) nwfs_print },
+ { &vop_read_desc, (vop_t *) nwfs_read },
+ { &vop_readdir_desc, (vop_t *) nwfs_readdir },
+ { &vop_reclaim_desc, (vop_t *) nwfs_reclaim },
+ { &vop_remove_desc, (vop_t *) nwfs_remove },
+ { &vop_rename_desc, (vop_t *) nwfs_rename },
+ { &vop_rmdir_desc, (vop_t *) nwfs_rmdir },
+ { &vop_setattr_desc, (vop_t *) nwfs_setattr },
+ { &vop_strategy_desc, (vop_t *) nwfs_strategy },
+ { &vop_symlink_desc, (vop_t *) nwfs_symlink },
+ { &vop_unlock_desc, (vop_t *) vop_nounlock },
+ { &vop_write_desc, (vop_t *) nwfs_write },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc nwfs_vnodeop_opv_desc =
+ { &nwfs_vnodeop_p, nwfs_vnodeop_entries };
+
+VNODEOP_SET(nwfs_vnodeop_opv_desc);
+
+void nwfs_createname(char *_name,struct vnode *vp,struct componentname *cnp);
+
+
+void nwfs_createname(char *_name,struct vnode *vp,struct componentname *cnp){
+ strncpy(_name, cnp->cn_nameptr, cnp->cn_namelen);
+ _name[cnp->cn_namelen] = '\0';
+ ncp_str_upper(_name);
+}
+/*
+ * nwfs_access vnode op
+ * for now just return ok
+ */
+static int
+nwfs_access(ap)
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ struct ucred *cred = ap->a_cred;
+ u_int mode = ap->a_mode;
+ struct nwmount *nmp = VTONWFS(vp);
+ int error = 0;
+
+ NCPVNDEBUG("\n");
+ if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+ switch (vp->v_type) {
+ case VREG: case VDIR: case VLNK:
+ return (EROFS);
+ default:
+ break;
+ }
+ }
+ if (cred->cr_uid == 0)
+ return 0;
+ if (cred->cr_uid != nmp->m.uid) {
+ mode >>= 3;
+ if (!groupmember(nmp->m.gid, cred))
+ mode >>= 3;
+ }
+ error = (((vp->v_type == VREG) ? nmp->m.file_mode : nmp->m.dir_mode) & mode) == mode ? 0 : EACCES;
+ return error;
+}
+/*
+ * nwfs_open vnode op
+ */
+/* ARGSUSED */
+static int
+nwfs_open(ap)
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ int mode = ap->a_mode;
+ struct nwnode *np = VTONW(vp);
+ struct ncp_open_info no;
+ struct nwmount *nmp = VTONWFS(vp);
+ struct vattr vattr;
+ int error, nwm;
+
+ NCPVNDEBUG("%s,%d\n",np->n_name, np->opened);
+ if (vp->v_type != VREG && vp->v_type != VDIR) {
+ NCPFATAL("open eacces vtype=%d\n", vp->v_type);
+ return (EACCES);
+ }
+ if (vp->v_type == VDIR) return 0; /* nothing to do now */
+ if (np->n_flag & NMODIFIED) {
+ if ((error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR)
+ return (error);
+ np->n_atime = 0;
+ error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+ if (error) return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ } else {
+ error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+ if (error) return (error);
+ if (np->n_mtime != vattr.va_mtime.tv_sec) {
+ if ((error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR)
+ return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ }
+ }
+ if (np->opened) {
+ np->opened++;
+ return 0;
+ }
+ nwm = AR_READ;
+ if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
+ nwm |= AR_WRITE;
+ error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN,
+ 0, nwm, &no, ap->a_p, ap->a_cred);
+ if (error) {
+ if (mode & FWRITE)
+ return EACCES;
+ nwm = AR_READ;
+ error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
+ nwm, &no, ap->a_p,ap->a_cred);
+ }
+ if (!error) {
+ np->opened++;
+ np->n_fh = no.fh;
+ np->n_origfh = no.origfh;
+ }
+ np->n_atime = 0;
+ return (error);
+}
+
+static int
+nwfs_close(ap)
+ struct vop_close_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct nwnode *np = VTONW(vp);
+ int error;
+
+ NCPVNDEBUG("name=%s,pid=%d,c=%d\n",np->n_name,ap->a_p->p_pid,np->opened);
+
+ if (vp->v_type == VDIR) return 0; /* nothing to do now */
+ error = 0;
+ simple_lock(&vp->v_interlock);
+ if (np->opened == 0) {
+ simple_unlock(&vp->v_interlock);
+ return 0;
+ }
+ error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
+ if (--np->opened == 0) {
+ error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, ap->a_p,ap->a_cred);
+ }
+ simple_unlock(&vp->v_interlock);
+ np->n_atime = 0;
+ return (error);
+}
+
+/*
+ * nwfs_getattr call from vfs.
+ */
+static int
+nwfs_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct nwnode *np = VTONW(vp);
+ struct vattr *va=ap->a_vap;
+ struct nwmount *nmp = VTONWFS(vp);
+ struct nw_entry_info fattr;
+ int error;
+ u_int32_t oldsize;
+
+ NCPVNDEBUG("%lx:%d: '%s' %d\n", (long)vp, nmp->n_volume, np->n_name, (vp->v_flag & VROOT) != 0);
+ error = nwfs_attr_cachelookup(vp,va);
+ if (!error) return 0;
+ NCPVNDEBUG("not in cache\n");
+ oldsize = np->n_size;
+ if (np->n_flag & NVOLUME) {
+ error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, &fattr,
+ ap->a_p,ap->a_cred);
+ } else {
+ error = ncp_obtain_info(nmp, np->n_fid.f_parent, np->n_nmlen,
+ np->n_name, &fattr, ap->a_p, ap->a_cred);
+ }
+ if (error) {
+ NCPVNDEBUG("error %d\n", error);
+ return error;
+ }
+ nwfs_attr_cacheenter(vp, &fattr);
+ *va = np->n_vattr;
+ if (np->opened)
+ np->n_size = oldsize;
+ return (0);
+}
+/*
+ * nwfs_setattr call from vfs.
+ */
+static int
+nwfs_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct nwnode *np = VTONW(vp);
+ register struct vattr *vap = ap->a_vap;
+ u_quad_t tsize=0;
+ int error = 0;
+
+ NCPVNDEBUG("\n");
+ if (vap->va_flags != VNOVAL)
+ return (EOPNOTSUPP);
+ /*
+ * Disallow write attempts if the filesystem is mounted read-only.
+ */
+ if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL ||
+ vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
+ vap->va_mode != (mode_t)VNOVAL) &&(vp->v_mount->mnt_flag & MNT_RDONLY))
+ return (EROFS);
+ if (vap->va_size != VNOVAL) {
+ switch (vp->v_type) {
+ case VDIR:
+ return (EISDIR);
+ case VREG:
+ /*
+ * Disallow write attempts if the filesystem is
+ * mounted read-only.
+ */
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ vnode_pager_setsize(vp, (u_long)vap->va_size);
+ tsize = np->n_size;
+ np->n_size = vap->va_size;
+ break;
+ default:
+ return EINVAL;
+ };
+ }
+ error = ncp_setattr(vp, vap, ap->a_cred, ap->a_p);
+ if (error && vap->va_size != VNOVAL) {
+ np->n_size = tsize;
+ vnode_pager_setsize(vp, (u_long)tsize);
+ }
+ np->n_atime = 0; /* invalidate cache */
+ VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
+ np->n_mtime = vap->va_mtime.tv_sec;
+ return (0);
+}
+/*
+ * nwfs_read call.
+ */
+static int
+nwfs_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ struct uio *uio=ap->a_uio;
+ int error;
+ NCPVNDEBUG("nwfs_read:\n");
+
+ if (vp->v_type != VREG && vp->v_type != VDIR)
+ return (EPERM);
+ error = nwfs_readvnode(vp, uio, ap->a_cred);
+ return error;
+}
+
+static int
+nwfs_write(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ int error;
+
+ NCPVNDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid);
+
+ if (vp->v_type != VREG)
+ return (EPERM);
+ error = nwfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag);
+ return(error);
+}
+/*
+ * nwfs_create call
+ * Create a regular file. On entry the directory to contain the file being
+ * created is locked. We must release before we return. We must also free
+ * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
+ * only if the SAVESTART bit in cn_flags is clear on success.
+ */
+static int
+nwfs_create(ap)
+ struct vop_create_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ register struct vnode *dvp = ap->a_dvp;
+ register struct vattr *vap = ap->a_vap;
+ struct vnode **vpp=ap->a_vpp;
+ register struct componentname *cnp = ap->a_cnp;
+ struct vnode *vp = (struct vnode *)0;
+ int error = 0, fmode;
+ struct vattr vattr;
+ struct nwnode *np;
+ struct ncp_open_info no;
+ struct nwmount *nmp=VTONWFS(dvp);
+ ncpfid fid;
+
+
+ NCPVNDEBUG("\n");
+ *vpp = NULL;
+ if (vap->va_type == VSOCK)
+ return (EOPNOTSUPP);
+ if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
+ VOP_ABORTOP(dvp, cnp);
+ return (error);
+ }
+ fmode = AR_READ | AR_WRITE;
+/* if (vap->va_vaflags & VA_EXCLUSIVE)
+ fmode |= AR_DENY_READ | AR_DENY_WRITE;*/
+
+ error = ncp_open_create_file_or_subdir(nmp,dvp,cnp->cn_namelen,cnp->cn_nameptr,
+ OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
+ 0, fmode, &no, cnp->cn_proc, cnp->cn_cred);
+ if (!error) {
+ error = ncp_close_file(NWFSTOCONN(nmp), &no.fh, cnp->cn_proc,cnp->cn_cred);
+ fid.f_parent = VTONW(dvp)->n_fid.f_id;
+ fid.f_id = no.fattr.dirEntNum;
+ error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &vp);
+ if (!error) {
+ np = VTONW(vp);
+ np->opened = 0;
+ *vpp = vp;
+ }
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, vp, cnp);
+ }
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+}
+
+/*
+ * nwfs_remove call. It isn't possible to emulate UFS behaivour because
+ * NetWare doesn't allow delete/rename operations on an opened file.
+ */
+static int
+nwfs_remove(ap)
+ struct vop_remove_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_dvp;
+ struct vnode * a_vp;
+ struct componentname * a_cnp;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct vnode *dvp = ap->a_dvp;
+ register struct componentname *cnp = ap->a_cnp;
+ register struct nwnode *np = VTONW(vp);
+ struct nwmount *nmp = VTONWFS(vp);
+ int error;
+
+ if (vp->v_type == VDIR || np->opened || vp->v_usecount != 1) {
+ error = EPERM;
+ } else if (!ncp_conn_valid(NWFSTOCONN(nmp))) {
+ error = EIO;
+ } else {
+ cache_purge(vp);
+ error = ncp_DeleteNSEntry(nmp, VTONW(dvp)->n_fid.f_id,
+ cnp->cn_namelen,cnp->cn_nameptr,cnp->cn_proc,cnp->cn_cred);
+ if (error == 0x899c) error = EACCES;
+ }
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+}
+
+/*
+ * nwfs_file rename call
+ */
+static int
+nwfs_rename(ap)
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap;
+{
+ register struct vnode *fvp = ap->a_fvp;
+ register struct vnode *tvp = ap->a_tvp;
+ register struct vnode *fdvp = ap->a_fdvp;
+ register struct vnode *tdvp = ap->a_tdvp;
+ register struct componentname *tcnp = ap->a_tcnp;
+ register struct componentname *fcnp = ap->a_fcnp;
+ struct nwmount *nmp=VTONWFS(fvp);
+ u_int16_t oldtype = 6;
+ int error=0;
+
+ /* Check for cross-device rename */
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+ goto out;
+ }
+
+ if (tvp && tvp->v_usecount > 1) {
+ error = EBUSY;
+ goto out;
+ }
+ if (tvp && tvp != fvp) {
+ error = ncp_DeleteNSEntry(nmp, VTONW(tdvp)->n_fid.f_id,
+ tcnp->cn_namelen, tcnp->cn_nameptr,
+ tcnp->cn_proc, tcnp->cn_cred);
+ if (error == 0x899c) error = EACCES;
+ if (error)
+ goto out;
+ }
+ if (fvp->v_type == VDIR) {
+ oldtype |= NW_TYPE_SUBDIR;
+ } else if (fvp->v_type == VREG) {
+ oldtype |= NW_TYPE_FILE;
+ } else
+ return EINVAL;
+ error = ncp_nsrename(NWFSTOCONN(nmp), nmp->n_volume, nmp->name_space,
+ oldtype, &nmp->m.nls,
+ VTONW(fdvp)->n_fid.f_id, fcnp->cn_nameptr, fcnp->cn_namelen,
+ VTONW(tdvp)->n_fid.f_id, tcnp->cn_nameptr, tcnp->cn_namelen,
+ tcnp->cn_proc,tcnp->cn_cred);
+
+ if (error == 0x8992)
+ error = EEXIST;
+ if (fvp->v_type == VDIR) {
+ if (tvp != NULL && tvp->v_type == VDIR)
+ cache_purge(tdvp);
+ cache_purge(fdvp);
+ }
+out:
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ vrele(fdvp);
+ vrele(fvp);
+ nwfs_attr_cacheremove(fdvp);
+ nwfs_attr_cacheremove(tdvp);
+ /*
+ * Need to get rid of old vnodes, because netware will change
+ * file id on rename
+ */
+ vgone(fvp);
+ if (tvp)
+ vgone(tvp);
+ /*
+ * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
+ */
+ if (error == ENOENT)
+ error = 0;
+ return (error);
+}
+
+/*
+ * nwfs hard link create call
+ * Netware filesystems don't know what links are. But since we already called
+ * nwfs_lookup() with create and lockparent, the parent is locked so we
+ * have to free it before we return the error.
+ */
+static int
+nwfs_link(ap)
+ struct vop_link_args /* {
+ struct vnode *a_tdvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+/* VOP_ABORTOP(ap->a_tdvp, ap->a_cnp);*/
+ zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ return EOPNOTSUPP;
+}
+
+/*
+ * nwfs_symlink link create call
+ * Netware filesystems don't know what symlinks are.
+ */
+static int
+nwfs_symlink(ap)
+ struct vop_symlink_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ char *a_target;
+ } */ *ap;
+{
+ zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
+ return (EOPNOTSUPP);
+}
+
+static int nwfs_mknod(ap)
+ struct vop_mknod_args /* {
+ } */ *ap;
+{
+ return (EOPNOTSUPP);
+}
+
+/*
+ * nwfs_mkdir call
+ */
+static int
+nwfs_mkdir(ap)
+ struct vop_mkdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ register struct vnode *dvp = ap->a_dvp;
+/* register struct vattr *vap = ap->a_vap;*/
+ register struct componentname *cnp = ap->a_cnp;
+ register int len=cnp->cn_namelen;
+ struct ncp_open_info no;
+ struct nwnode *np;
+ struct vnode *newvp = (struct vnode *)0;
+ ncpfid fid;
+ int error = 0;
+ struct vattr vattr;
+ char *name=cnp->cn_nameptr;
+
+ if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
+ VOP_ABORTOP(dvp, cnp);
+ return (error);
+ }
+ if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) {
+ VOP_ABORTOP(dvp, cnp);
+ return EEXIST;
+ }
+ if (ncp_open_create_file_or_subdir(VTONWFS(dvp),dvp, cnp->cn_namelen,
+ cnp->cn_nameptr,OC_MODE_CREATE, aDIR, 0xffff,
+ &no, cnp->cn_proc, cnp->cn_cred) != 0) {
+ error = EACCES;
+ } else {
+ error = 0;
+ }
+ if (!error) {
+ fid.f_parent = VTONW(dvp)->n_fid.f_id;
+ fid.f_id = no.fattr.dirEntNum;
+ error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &newvp);
+ if (!error) {
+ np = VTONW(newvp);
+ newvp->v_type = VDIR;
+ *ap->a_vpp = newvp;
+ }
+ }
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+}
+
+/*
+ * nwfs_remove directory call
+ */
+static int
+nwfs_rmdir(ap)
+ struct vop_rmdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct vnode *dvp = ap->a_dvp;
+ register struct componentname *cnp = ap->a_cnp;
+ struct nwmount *nmp = VTONWFS(vp);
+ struct nwnode *dnp = VTONW(dvp);
+ int error = EIO;
+
+ if (dvp == vp) return EINVAL;
+ if (!ncp_conn_valid(NWFSTOCONN(nmp))) return(error);
+
+ error = ncp_DeleteNSEntry(nmp, dnp->n_fid.f_id,
+ cnp->cn_namelen, cnp->cn_nameptr,cnp->cn_proc,cnp->cn_cred);
+ if (error == NWE_DIR_NOT_EMPTY) error = ENOTEMPTY;
+ zfree(namei_zone, cnp->cn_pnbuf);
+ dnp->n_flag |= NMODIFIED;
+ nwfs_attr_cacheremove(dvp);
+ cache_purge(dvp);
+ cache_purge(vp);
+ return (error);
+}
+
+/*
+ * nwfs_readdir call
+ */
+static int
+nwfs_readdir(ap)
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct uio *uio = ap->a_uio;
+ int error;
+
+ if (vp->v_type != VDIR)
+ return (EPERM);
+ if (ap->a_ncookies) {
+ printf("nwfs_readdir: no support for cookies now...");
+ return (EOPNOTSUPP);
+ }
+
+ error = nwfs_readvnode(vp, uio, ap->a_cred);
+ return error;
+}
+/* ARGSUSED */
+static int
+nwfs_fsync(ap)
+ struct vop_fsync_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_vp;
+ struct ucred * a_cred;
+ int a_waitfor;
+ struct proc * a_p;
+ } */ *ap;
+{
+/* return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));*/
+ return (0);
+}
+/* ARGSUSED */
+static
+int nwfs_print (ap)
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ return (0);
+}
+
+static int nwfs_pathconf (ap)
+ struct vop_pathconf_args /* {
+ struct vnode *vp;
+ int name;
+ int *retval;
+ } */ *ap;
+{
+ int name=ap->a_name, error=0;
+ int *retval=ap->a_retval;
+
+ switch(name){
+ case _PC_LINK_MAX:
+ *retval=0;
+ break;
+ case _PC_NAME_MAX:
+ *retval=NCP_MAX_FILENAME; /* XXX from nwfsnode */
+ break;
+ case _PC_PATH_MAX:
+ *retval=NCP_MAXPATHLEN; /* XXX from nwfsnode */
+ break;
+ default:
+ error=EINVAL;
+ }
+ return(error);
+}
+
+static int nwfs_strategy (ap)
+ struct vop_strategy_args /* {
+ struct buf *a_bp
+ } */ *ap;
+{
+ struct buf *bp=ap->a_bp;
+ struct ucred *cr;
+ struct proc *p;
+ int error = 0;
+
+ NCPVNDEBUG("\n");
+ if (bp->b_flags & B_PHYS)
+ panic("nwfs physio");
+ if (bp->b_flags & B_ASYNC)
+ p = (struct proc *)0;
+ else
+ p = curproc; /* XXX */
+ if (bp->b_flags & B_READ)
+ cr = bp->b_rcred;
+ else
+ cr = bp->b_wcred;
+ /*
+ * If the op is asynchronous and an i/o daemon is waiting
+ * queue the request, wake it up and wait for completion
+ * otherwise just do it ourselves.
+ */
+ if ((bp->b_flags & B_ASYNC) == 0 )
+ error = nwfs_doio(bp, cr, p);
+ return (error);
+}
+
+static int
+nwfs_bmap(ap)
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct vnode **a_vpp;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+
+ if (ap->a_vpp != NULL)
+ *ap->a_vpp = vp;
+ if (ap->a_bnp != NULL)
+ *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
+ if (ap->a_runp != NULL)
+ *ap->a_runp = 0;
+ if (ap->a_runb != NULL)
+ *ap->a_runb = 0;
+ return (0);
+}
+/*
+ * nwfs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Currently nothing to do.
+ */
+/* ARGSUSED */
+int
+nwfs_abortop(ap)
+ struct vop_abortop_args /* {
+ struct vnode *a_dvp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+
+ if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
+ zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ return (0);
+}
+
+int
+nwfs_nget(struct mount *mp, ncpfid fid, struct nw_entry_info *fap,
+ struct vnode *dvp, struct vnode **vpp)
+{
+ int error;
+ struct nwnode *newnp;
+ struct vnode *vp;
+
+ *vpp = NULL;
+ error = nwfs_allocvp(mp, fid, &vp);
+ if (error)
+ return error;
+ newnp = VTONW(vp);
+ if (fap) {
+ if (newnp->n_flag & NNEW) {
+ newnp->n_nmlen = fap->nameLen;
+ bcopy(fap->entryName, newnp->n_name, newnp->n_nmlen);
+ newnp->n_name[fap->nameLen] = 0;
+ }
+ newnp->n_attr = fap->attributes;
+ newnp->n_dosfid = fap->DosDirNum;
+ vp->v_type = newnp->n_attr & aDIR ? VDIR : VREG;
+ nwfs_attr_cacheenter(vp, fap);
+ }
+ if (dvp) {
+ newnp->n_parent = VTONW(dvp)->n_fid;
+ if ((newnp->n_flag & NNEW) && vp->v_type == VDIR) {
+ if ((dvp->v_flag & VROOT) == 0) {
+ newnp->n_refparent = 1;
+ vref(dvp); /* vhold */
+ }
+ }
+ } else {
+ if ((newnp->n_flag & NNEW) && vp->v_type == VREG)
+ printf("new vnode '%s' borned without parent ?\n",newnp->n_name);
+ }
+ newnp->n_flag &= ~NNEW;
+ *vpp = vp;
+ return 0;
+}
+
+/*
+ * How to keep the brain busy ...
+ * Currently lookup routine can make two lookup for vnode. This can be
+ * avoided by reorg the code.
+ */
+int
+nwfs_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ int flags = cnp->cn_flags;
+ struct vnode *vp;
+ struct nwmount *nmp;
+ struct mount *mp = dvp->v_mount;
+ struct nwnode *dnp, *npp;
+ struct nw_entry_info fattr, *fap;
+ ncpfid fid;
+ int nameiop=cnp->cn_nameiop, islastcn;
+ int lockparent, wantparent, error = 0, notfound;
+ struct proc *p = cnp->cn_proc;
+ char _name[cnp->cn_namelen+1];
+ bcopy(cnp->cn_nameptr,_name,cnp->cn_namelen);
+ _name[cnp->cn_namelen]=0;
+
+ if (dvp->v_type != VDIR)
+ return (ENOTDIR);
+ if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) {
+ printf("nwfs_lookup: invalid '..'\n");
+ return EIO;
+ }
+
+ NCPVNDEBUG("%d '%s' in '%s' id=d\n", nameiop, _name,
+ VTONW(dvp)->n_name/*, VTONW(dvp)->n_name*/);
+
+ islastcn = flags & ISLASTCN;
+ if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP))
+ return (EROFS);
+ if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p)))
+ return (error);
+ lockparent = flags & LOCKPARENT;
+ wantparent = flags & (LOCKPARENT|WANTPARENT);
+ nmp = VFSTONWFS(mp);
+ dnp = VTONW(dvp);
+/*
+printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & ISDOTDOT);
+*/
+ error = ncp_pathcheck(cnp->cn_nameptr, cnp->cn_namelen, &nmp->m.nls,
+ (nameiop == CREATE || nameiop == RENAME) && (nmp->m.nls.opt & NWHP_NOSTRICT) == 0);
+ if (error)
+ return ENOENT;
+
+ error = cache_lookup(dvp, vpp, cnp);
+ NCPVNDEBUG("cache_lookup returned %d\n",error);
+ if (error > 0)
+ return error;
+ if (error) { /* name was found */
+ struct vattr vattr;
+ int vpid;
+
+ vp = *vpp;
+ vpid = vp->v_id;
+ if (dvp == vp) { /* lookup on current */
+ vref(vp);
+ error = 0;
+ NCPVNDEBUG("cached '.'");
+ } else if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p); /* unlock parent */
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (!error && lockparent && islastcn)
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ } else {
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (!lockparent || error || !islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ if (!error) {
+ if (vpid == vp->v_id) {
+ if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, p)
+ && vattr.va_ctime.tv_sec == VTONW(vp)->n_ctime) {
+ if (nameiop != LOOKUP && islastcn)
+ cnp->cn_flags |= SAVENAME;
+ NCPVNDEBUG("use cached vnode");
+ return (0);
+ }
+ cache_purge(vp);
+ }
+ vput(vp);
+ if (lockparent && dvp != vp && islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ *vpp = NULLVP;
+ if (error)
+ return (error);
+ }
+ /* not in cache, so ... */
+ error = 0;
+ *vpp = NULLVP;
+ fap = NULL;
+ if (flags & ISDOTDOT) {
+ if (NWCMPF(&dnp->n_parent, &nmp->n_rootent)) {
+ fid = nmp->n_rootent;
+ fap = NULL;
+ notfound = 0;
+ } else {
+ error = nwfs_lookupnp(nmp, dnp->n_parent, &npp);
+ if (error) {
+ return error;
+ }
+ fid = dnp->n_parent;
+ fap = &fattr;
+ /*np = *npp;*/
+ notfound = ncp_obtain_info(nmp, npp->n_dosfid,
+ 0, NULL, fap, p, cnp->cn_cred);
+ }
+ } else {
+ fap = &fattr;
+ notfound = ncp_lookup(dvp, cnp->cn_namelen, cnp->cn_nameptr,
+ fap, p, cnp->cn_cred);
+ fid.f_parent = dnp->n_fid.f_id;
+ fid.f_id = fap->dirEntNum;
+ NCPVNDEBUG("call to ncp_lookup returned=%d\n",notfound);
+ }
+ if (notfound && notfound < 0x80 )
+ return (notfound); /* hard error */
+ if (notfound) { /* entry not found */
+ /* Handle RENAME or CREATE case... */
+ if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) {
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent)
+ VOP_UNLOCK(dvp, 0, p);
+ return (EJUSTRETURN);
+ }
+ return ENOENT;
+ }/* else {
+ NCPVNDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum);
+ }*/
+ /* handle DELETE case ... */
+ if (nameiop == DELETE && islastcn) { /* delete last component */
+ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error) return (error);
+ if (NWCMPF(&dnp->n_fid, &fid)) { /* we found ourselfs */
+ VREF(dvp);
+ *vpp = dvp;
+ return 0;
+ }
+ error = nwfs_nget(mp, fid, fap, dvp, &vp);
+ if (error) return (error);
+ *vpp = vp;
+ cnp->cn_flags |= SAVENAME; /* I free it later */
+ if (!lockparent) VOP_UNLOCK(dvp,0,p);
+ return (0);
+ }
+ if (nameiop == RENAME && islastcn && wantparent) {
+ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error) return (error);
+ if (NWCMPF(&dnp->n_fid, &fid)) return EISDIR;
+ error = nwfs_nget(mp, fid, fap, dvp, &vp);
+ if (error) return (error);
+ *vpp = vp;
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent)
+ VOP_UNLOCK(dvp,0,p);
+ return (0);
+ }
+ if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p); /* race to get the inode */
+ error = nwfs_nget(mp, fid, NULL, NULL, &vp);
+ if (error) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
+ }
+ if (lockparent && islastcn &&
+ (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
+ vput(vp);
+ return (error);
+ }
+ *vpp = vp;
+ } else if (NWCMPF(&dnp->n_fid, &fid)) {
+ vref(dvp);
+ *vpp = dvp;
+ } else {
+ error = nwfs_nget(mp, fid, fap, dvp, &vp);
+ if (error) return (error);
+ *vpp = vp;
+ NCPVNDEBUG("lookup: getnewvp!\n");
+ if (!lockparent || !islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) {
+ VTONW(*vpp)->n_ctime = VTONW(*vpp)->n_vattr.va_ctime.tv_sec;
+ cache_enter(dvp, *vpp, cnp);
+ }
+ return (0);
+}
diff --git a/sys/netncp/ncp.h b/sys/netncp/ncp.h
new file mode 100644
index 0000000..4c285ef
--- /dev/null
+++ b/sys/netncp/ncp.h
@@ -0,0 +1,391 @@
+/*
+ * ncp.h
+ *
+ * Copyright (C) 1995 by Volker Lendecke
+ * New version derived from original ncp.h, 1998 Boris Popov
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NCP_H_
+#define _NCP_H_
+
+#define NCP_VERMAJ 1
+#define NCP_VERMIN 3200
+#define NCP_VERSION (NCP_VERMAJ*100000 + NCP_VERMIN)
+
+typedef u_int32_t nwdirent;
+
+typedef char nstr8;
+typedef nstr8* pnstr8;
+typedef u_int8_t nuint8;
+typedef u_int8_t* pnuint8;
+typedef u_int16_t nuint16;
+typedef nuint16* pnuint16;
+typedef u_int32_t nuint32;
+typedef nuint32* pnuint32;
+
+
+#define NCP_DEFAULT_BUFSIZE 1024
+#define NCP_MAX_BUFSIZE 1024
+#define NCP_MAX_PACKET_SIZE 4070
+#define NCP_MAXUSERNAMELEN 255
+#define NCP_MAXPASSWORDLEN 255
+#define NCP_MAXPATHLEN 255
+#define NCP_MAX_FILENAME 14
+#define NCP_FILE_ID_LEN 6
+
+#define NCP_BINDERY_USER 0x0001
+#define NCP_BINDERY_UGROUP 0x0002
+#define NCP_BINDERY_PQUEUE 0x0003
+#define NCP_BINDERY_FSERVER 0x0004
+#define NCP_BINDERY_PSERVER 0x0007
+#define NCP_BINDERY_NAME_LEN 48
+
+/* Handle Flags */
+#define NCP_HF_DIRSHORT 0 /* short directory handle */
+#define NCP_HF_DIRBASE 1 /* directory base */
+#define NCP_HF_NONE 0xff /* no handle or dirbase */
+
+/* Options to negotiate */
+#define NCP_IPX_CHECKSUM 1
+#define NCP_SECURITY_LEVEL_SIGN_HEADERS 2
+
+#ifndef NWCONN_HANDLE
+#define NWCONN_HANDLE unsigned int
+#define pNWCONN_HANDLE (unsigned int*)
+#define NWCONN_NUM u_int16_t
+#define NWCCODE unsigned int
+#define NWDIR_HANDLE u_int8_t
+#define NWFILE_HANDLE int
+#endif
+
+struct ncp_fh_s {
+ u_int16_t val1;
+ union {
+ u_int32_t val32;
+ u_int16_t val16;
+ } val;
+} __attribute__((packed));
+
+typedef struct ncp_fh_s ncp_fh;
+
+typedef struct ncpfid_s {
+ nwdirent f_parent;
+ nwdirent f_id;
+} ncpfid;
+
+/* -- Bindery properties -- */
+struct ncp_bindery_object {
+ u_int32_t object_id;
+ u_int16_t object_type;
+ u_int8_t object_name[NCP_BINDERY_NAME_LEN];
+ u_int8_t object_flags;
+ u_int8_t object_security;
+ u_int8_t object_has_prop;
+};
+
+struct nw_property {
+ u_int8_t value[128];
+ u_int8_t more_flag;
+ u_int8_t property_flag;
+};
+
+struct ncp_filesearch_info {
+ u_int8_t volume_number;
+ u_int16_t directory_id;
+ u_int16_t sequence_no;
+ u_int8_t access_rights;
+};
+
+
+struct ncp_file_info {
+ u_int8_t file_id[NCP_FILE_ID_LEN];
+ char file_name[NCP_MAX_FILENAME + 1];
+ u_int8_t file_attributes;
+ u_int8_t file_mode;
+ u_int32_t file_length;
+ u_int16_t creation_date;
+ u_int16_t access_date;
+ u_int16_t update_date;
+ u_int16_t update_time;
+};
+
+struct nw_queue_job_entry {
+ u_int16_t InUse __attribute__((packed));
+ u_int32_t prev __attribute__((packed));
+ u_int32_t next __attribute__((packed));
+ u_int32_t ClientStation __attribute__((packed));
+ u_int32_t ClientTask __attribute__((packed));
+ u_int32_t ClientObjectID __attribute__((packed));
+ u_int32_t TargetServerID __attribute__((packed));
+ u_int8_t TargetExecTime[6] __attribute__((packed));
+ u_int8_t JobEntryTime[6] __attribute__((packed));
+ u_int32_t JobNumber __attribute__((packed));
+ u_int16_t JobType __attribute__((packed));
+ u_int16_t JobPosition __attribute__((packed));
+ u_int16_t JobControlFlags __attribute__((packed));
+ u_int8_t FileNameLen __attribute__((packed));
+ char JobFileName[13] __attribute__((packed));
+ u_int32_t JobFileHandle __attribute__((packed));
+ u_int32_t ServerStation __attribute__((packed));
+ u_int32_t ServerTaskNumber __attribute__((packed));
+ u_int32_t ServerObjectID __attribute__((packed));
+ char JobTextDescription[50] __attribute__((packed));
+ char ClientRecordArea[152] __attribute__((packed));
+};
+
+struct queue_job {
+ struct nw_queue_job_entry j;
+ ncp_fh file_handle;
+};
+
+#define QJE_OPER_HOLD 0x80
+#define QJE_USER_HOLD 0x40
+#define QJE_ENTRYOPEN 0x20
+#define QJE_SERV_RESTART 0x10
+#define QJE_SERV_AUTO 0x08
+
+/* ClientRecordArea for print jobs */
+
+#define KEEP_ON 0x0400
+#define NO_FORM_FEED 0x0800
+#define NOTIFICATION 0x1000
+#define DELETE_FILE 0x2000
+#define EXPAND_TABS 0x4000
+#define PRINT_BANNER 0x8000
+
+struct print_job_record {
+ u_int8_t Version __attribute__((packed));
+ u_int8_t TabSize __attribute__((packed));
+ u_int16_t Copies __attribute__((packed));
+ u_int16_t CtrlFlags __attribute__((packed));
+ u_int16_t Lines __attribute__((packed));
+ u_int16_t Rows __attribute__((packed));
+ char FormName[16] __attribute__((packed));
+ u_int8_t Reserved[6] __attribute__((packed));
+ char BannerName[13] __attribute__((packed));
+ char FnameBanner[13] __attribute__((packed));
+ char FnameHeader[14] __attribute__((packed));
+ char Path[80] __attribute__((packed));
+};
+
+struct ncp_station_addr {
+ u_int32_t NetWork;
+ u_int8_t Node[6];
+ u_int16_t Socket;
+} __attribute__((packed));
+
+struct ncp_prop_login_control {
+ u_int8_t AccountExpireDate[3] __attribute__((packed));
+ u_int8_t Disabled __attribute__((packed));
+ u_int8_t PasswordExpireDate[3] __attribute__((packed));
+ u_int8_t GraceLogins __attribute__((packed));
+ u_int16_t PasswordExpireInterval __attribute__((packed));
+ u_int8_t MaxGraceLogins __attribute__((packed));
+ u_int8_t MinPasswordLength __attribute__((packed));
+ u_int16_t MaxConnections __attribute__((packed));
+ u_int8_t ConnectionTimeMask[42] __attribute__((packed));
+ u_int8_t LastLogin[6] __attribute__((packed));
+ u_int8_t RestrictionMask __attribute__((packed));
+ u_int8_t reserved __attribute__((packed));
+ u_int32_t MaxDiskUsage __attribute__((packed));
+ u_int16_t BadLoginCount __attribute__((packed));
+ u_int32_t BadLoginCountDown __attribute__((packed));
+ struct ncp_station_addr LastIntruder __attribute__((packed));
+};
+
+#define NCP_VOLNAME_LEN (16)
+#define NCP_NUMBER_OF_VOLUMES (64)
+struct ncp_volume_info {
+ u_int32_t total_blocks;
+ u_int32_t free_blocks;
+ u_int32_t purgeable_blocks;
+ u_int32_t not_yet_purgeable_blocks;
+ u_int32_t total_dir_entries;
+ u_int32_t available_dir_entries;
+ u_int8_t sectors_per_block;
+ char volume_name[NCP_VOLNAME_LEN + 1];
+};
+/*
+ * Name space constants, taken from NDK
+ */
+#define aRONLY (ntohl(0x01000000))
+#define aHIDDEN (ntohl(0x02000000))
+#define aSYSTEM (ntohl(0x04000000))
+#define aEXECUTE (ntohl(0x08000000))
+#define aDIR (ntohl(0x10000000))
+#define aARCH (ntohl(0x20000000))
+
+/* Defines for Name Spaces */
+#define NW_NS_DOS 0
+#define NW_NS_MAC 1
+#define NW_NS_NFS 2
+#define NW_NS_FTAM 3
+#define NW_NS_OS2 4
+
+/* for _ScanNSEntryInfo */
+#define IM_NAME 0x00000001
+#define IM_SPACE_ALLOCATED 0x00000002
+#define IM_ATTRIBUTES 0x00000004
+#define IM_SIZE 0x00000008
+#define IM_TOTAL_SIZE 0x00000010
+#define IM_EA 0x00000020
+#define IM_ARCHIVE 0x00000040
+#define IM_MODIFY 0x00000080
+#define IM_CREATION 0x00000100
+#define IM_OWNING_NAMESPACE 0x00000200
+#define IM_DIRECTORY 0x00000400
+#define IM_RIGHTS 0x00000800
+#define IM_ALMOST_ALL 0x00000FED
+#define IM_ALL 0x00000FFF
+#define IM_REFERENCE_ID 0x00001000
+#define IM_NS_ATTRIBUTES 0x00002000
+#define IM_COMPRESSED_INFO 0x80000000UL
+
+/* open/create modes */
+#define OC_MODE_OPEN 0x01
+#define OC_MODE_TRUNCATE 0x02
+#define OC_MODE_REPLACE 0x02
+#define OC_MODE_CREATE 0x08
+
+/* open/create results */
+#define OC_ACTION_NONE 0x00
+#define OC_ACTION_OPEN 0x01
+#define OC_ACTION_CREATE 0x02
+#define OC_ACTION_TRUNCATE 0x04
+#define OC_ACTION_REPLACE 0x04
+
+/* renameFlag in NSRename */
+#define NW_TYPE_FILE 0x8000
+#define NW_TYPE_SUBDIR 0x0010
+
+#define NW_NAME_CONVERT 0x0003 /* don't report error and set comp mode */
+#define NW_NO_NAME_CONVERT 0x0004 /* only in specified name space */
+
+/* search attributes */
+#ifndef SA_HIDDEN
+#define SA_NORMAL 0x0000
+#define SA_HIDDEN 0x0002
+#define SA_SYSTEM 0x0004
+#define SA_SUBDIR_ONLY 0x0010
+#define SA_SUBDIR_FILES 0x8000
+#define SA_ALL 0x8006
+#endif
+
+/* access rights attributes */
+#ifndef AR_READ
+#define AR_READ 0x0001
+#define AR_WRITE 0x0002
+#define AR_READ_ONLY 0x0001
+#define AR_WRITE_ONLY 0x0002
+#define AR_DENY_READ 0x0004
+#define AR_DENY_WRITE 0x0008
+#define AR_COMPATIBILITY 0x0010
+#define AR_WRITE_THROUGH 0x0040
+#define AR_OPEN_COMPRESSED 0x0100
+#endif
+
+struct nw_entry_info {
+ u_int32_t spaceAlloc;
+ u_int32_t attributes; /* LH */
+ u_int16_t flags; /* internal */
+ u_int32_t dataStreamSize;
+ u_int32_t totalStreamSize;
+ u_int16_t numberOfStreams;
+ u_int16_t creationTime; /* LH */
+ u_int16_t creationDate; /* LH */
+ u_int32_t creatorID; /* HL */
+ u_int16_t modifyTime; /* LH */
+ u_int16_t modifyDate; /* LH */
+ u_int32_t modifierID; /* HL */
+ u_int16_t lastAccessDate; /* LH */
+ u_int16_t archiveTime; /* LH */
+ u_int16_t archiveDate; /* LH */
+ u_int32_t archiverID; /* HL */
+ u_int16_t inheritedRightsMask; /* LH */
+ u_int32_t dirEntNum;
+ u_int32_t DosDirNum;
+ u_int32_t volNumber;
+ u_int32_t EADataSize;
+ u_int32_t EAKeyCount;
+ u_int32_t EAKeySize;
+ u_int32_t NSCreator;
+ u_int8_t nameLen;
+ u_int8_t entryName[256];
+} __attribute__((packed));
+
+typedef struct nw_entry_info NW_ENTRY_INFO;
+
+/* modify mask - use with MODIFY_DOS_INFO structure */
+#define DM_ATTRIBUTES 0x0002L
+#define DM_CREATE_DATE 0x0004L
+#define DM_CREATE_TIME 0x0008L
+#define DM_CREATOR_ID 0x0010L
+#define DM_ARCHIVE_DATE 0x0020L
+#define DM_ARCHIVE_TIME 0x0040L
+#define DM_ARCHIVER_ID 0x0080L
+#define DM_MODIFY_DATE 0x0100L
+#define DM_MODIFY_TIME 0x0200L
+#define DM_MODIFIER_ID 0x0400L
+#define DM_LAST_ACCESS_DATE 0x0800L
+#define DM_INHERITED_RIGHTS_MASK 0x1000L))
+#define DM_MAXIMUM_SPACE 0x2000L
+
+struct nw_modify_dos_info {
+ u_int32_t attributes __attribute__((packed));
+ u_int16_t creationDate __attribute__((packed));
+ u_int16_t creationTime __attribute__((packed));
+ u_int32_t creatorID __attribute__((packed));
+ u_int16_t modifyDate __attribute__((packed));
+ u_int16_t modifyTime __attribute__((packed));
+ u_int32_t modifierID __attribute__((packed));
+ u_int16_t archiveDate __attribute__((packed));
+ u_int16_t archiveTime __attribute__((packed));
+ u_int32_t archiverID __attribute__((packed));
+ u_int16_t lastAccessDate __attribute__((packed));
+ u_int16_t inheritanceGrantMask __attribute__((packed));
+ u_int16_t inheritanceRevokeMask __attribute__((packed));
+ u_int32_t maximumSpace __attribute__((packed));
+};
+
+struct nw_search_seq {
+ u_int8_t volNumber;
+ u_int32_t dirNumber;
+ u_int32_t searchDirNumber;
+} __attribute__((packed));
+
+typedef struct nw_search_seq SEARCH_SEQUENCE;
+
+struct ncp_file_server_info {
+ u_int8_t ServerName[48] __attribute__((packed));
+ u_int8_t FileServiceVersion __attribute__((packed));
+ u_int8_t FileServiceSubVersion __attribute__((packed));
+ u_int16_t MaximumServiceConnections __attribute__((packed));
+ u_int16_t ConnectionsInUse __attribute__((packed));
+ u_int16_t NumberMountedVolumes __attribute__((packed));
+ u_int8_t Revision __attribute__((packed));
+ u_int8_t SFTLevel __attribute__((packed));
+ u_int8_t TTSLevel __attribute__((packed));
+ u_int16_t MaxConnectionsEverUsed __attribute__((packed));
+ u_int8_t AccountVersion __attribute__((packed));
+ u_int8_t VAPVersion __attribute__((packed));
+ u_int8_t QueueVersion __attribute__((packed));
+ u_int8_t PrintVersion __attribute__((packed));
+ u_int8_t VirtualConsoleVersion __attribute__((packed));
+ u_int8_t RestrictionLevel __attribute__((packed));
+ u_int8_t InternetBridge __attribute__((packed));
+ u_int8_t Reserved[60] __attribute__((packed));
+};
+
+struct nw_time_buffer {
+ u_int8_t year __attribute__((packed));
+ u_int8_t month __attribute__((packed));
+ u_int8_t day __attribute__((packed));
+ u_int8_t hour __attribute__((packed));
+ u_int8_t minute __attribute__((packed));
+ u_int8_t second __attribute__((packed));
+ u_int8_t wday __attribute__((packed));
+};
+
+#endif /*_NCP_H_ */
diff --git a/sys/netncp/ncp_conn.c b/sys/netncp/ncp_conn.c
new file mode 100644
index 0000000..d02ca48f
--- /dev/null
+++ b/sys/netncp/ncp_conn.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * $FreeBSD$
+ *
+ * Connection tables
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/sysctl.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_user.h>
+#include <netncp/ncp_conn.h>
+
+SLIST_HEAD(ncp_handle_head,ncp_handle);
+
+int ncp_burst_enabled = 1;
+
+struct ncp_conn_head conn_list={NULL};
+static int ncp_conn_cnt = 0;
+static int ncp_next_ref = 1;
+static struct lock listlock;
+
+struct ncp_handle_head lhlist={NULL};
+static int ncp_next_handle = 1;
+static struct lock lhlock;
+
+static int ncp_sysctl_connstat SYSCTL_HANDLER_ARGS;
+static int ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p,
+ struct ucred *cred);
+
+extern struct linker_set sysctl_net_ncp;
+
+SYSCTL_DECL(_net_ncp);
+SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
+SYSCTL_INT (_net_ncp, OID_AUTO, burst_enabled, CTLFLAG_RD, &ncp_burst_enabled, 0, "");
+SYSCTL_INT (_net_ncp, OID_AUTO, conn_cnt, CTLFLAG_RD, &ncp_conn_cnt, 0, "");
+SYSCTL_PROC(_net_ncp, OID_AUTO, conn_stat, CTLFLAG_RD|CTLTYPE_OPAQUE,
+ NULL, 0, ncp_sysctl_connstat, "S,connstat", "Connections list");
+
+MALLOC_DEFINE(M_NCPDATA, "NCP data", "NCP private data");
+
+int
+ncp_conn_init(void) {
+ lockinit(&listlock, PSOCK, "ncpll", 0, 0);
+ lockinit(&lhlock, PSOCK, "ncplh", 0, 0);
+ return 0;
+}
+
+int
+ncp_conn_locklist(int flags, struct proc *p){
+ return lockmgr(&listlock, flags | LK_CANRECURSE, 0, p);
+}
+
+void
+ncp_conn_unlocklist(struct proc *p){
+ lockmgr(&listlock, LK_RELEASE, 0, p);
+}
+
+int
+ncp_conn_access(struct ncp_conn *conn, struct ucred *cred, mode_t mode) {
+ int error;
+
+ if (ncp_suser(cred) == 0 || cred->cr_uid == conn->nc_owner->cr_uid)
+ return 0;
+ mode >>= 3;
+ if (!groupmember(conn->nc_group, cred))
+ mode >>= 3;
+ error = (conn->li.access_mode & mode) == mode ? 0 : EACCES;
+ return error;
+}
+
+int
+ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p, struct ucred *cred) {
+ int error;
+
+ if (conn->nc_id == 0) return EACCES;
+ error = lockmgr(&conn->nc_lock, LK_EXCLUSIVE | LK_CANRECURSE, 0, p);
+ if (error == ERESTART)
+ return EINTR;
+ error = ncp_chkintr(conn, p);
+ if (error) {
+ lockmgr(&conn->nc_lock, LK_RELEASE, 0, p);
+ return error;
+ }
+
+ if (conn->nc_id == 0) {
+ lockmgr(&conn->nc_lock, LK_RELEASE, 0, p);
+ return EACCES;
+ }
+ conn->procp = p; /* who currently operates */
+ conn->ucred = cred;
+ return 0;
+}
+
+int
+ncp_conn_lock(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode) {
+ int error;
+
+ error = ncp_conn_access(conn,cred,mode);
+ if (error) return error;
+ return ncp_conn_lock_any(conn, p, cred);
+}
+
+/*
+ * Lock conn but unlock connlist
+ */
+static int
+ncp_conn_lock2(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode) {
+ int error;
+
+ error = ncp_conn_access(conn,cred,mode);
+ if (error) {
+ ncp_conn_unlocklist(p);
+ return error;
+ }
+ conn->nc_lwant++;
+ ncp_conn_unlocklist(p);
+ error = ncp_conn_lock_any(conn,p,cred);
+ conn->nc_lwant--;
+ if (conn->nc_lwant == 0) {
+ wakeup(&conn->nc_lwant);
+ }
+ return error;
+}
+
+void
+ncp_conn_unlock(struct ncp_conn *conn, struct proc *p) {
+ /*
+ * note, that LK_RELASE will do wakeup() instead of wakeup_one().
+ * this will do a little overhead
+ */
+ lockmgr(&conn->nc_lock, LK_RELEASE, 0, p);
+}
+
+int
+ncp_conn_assert_locked(struct ncp_conn *conn,char *checker, struct proc *p){
+ if (conn->nc_lock.lk_flags & LK_HAVE_EXCL) return 0;
+ printf("%s: connection isn't locked!\n", checker);
+ return EIO;
+}
+
+/*
+ * create, fill with defaults and return in locked state
+ */
+int
+ncp_conn_alloc(struct proc *p, struct ucred *cred, struct ncp_conn **conn)
+{
+ int error;
+ struct ncp_conn *ncp;
+
+ MALLOC(ncp, struct ncp_conn *, sizeof(struct ncp_conn),
+ M_NCPDATA, M_WAITOK);
+ if (ncp == NULL) return ENOMEM;
+ error = 0;
+ bzero(ncp,sizeof(*ncp));
+ lockinit(&ncp->nc_lock, PZERO, "ncplck", 0, 0);
+ ncp_conn_cnt++;
+ ncp->nc_id = ncp_next_ref++;
+ ncp->nc_owner = cred;
+ ncp->seq = 0;
+ ncp->connid = 0xFFFF;
+ ncp_conn_lock_any(ncp, p, ncp->nc_owner);
+ *conn = ncp;
+ ncp_conn_locklist(LK_EXCLUSIVE, p);
+ SLIST_INSERT_HEAD(&conn_list,ncp,nc_next);
+ ncp_conn_unlocklist(p);
+ return (error);
+}
+
+/*
+ * Remove the connection, on entry it must be locked
+ */
+int
+ncp_conn_free(struct ncp_conn *ncp) {
+ int error;
+ struct ncp_conn *ncp1;
+
+ if (ncp->nc_id == 0) {
+ printf("already!!!!\n");
+ return EACCES;
+ }
+ if (ncp==NULL) {
+ NCPFATAL("conn==NULL !\n");
+ return(EIO);
+ }
+ error = ncp_conn_assert_locked(ncp, __FUNCTION__, ncp->procp);
+ if (error) return error;
+ if (ncp->ref_cnt) {
+ NCPFATAL("there are %d referenses left\n",ncp->ref_cnt);
+ return(EBUSY);
+ }
+ /*
+ * Mark conn as died and wait for other process
+ */
+ ncp->nc_id = 0;
+ ncp_conn_unlock(ncp,ncp->procp);
+ /*
+ * if signal is raised - how I do react ?
+ */
+ lockmgr(&ncp->nc_lock, LK_DRAIN, 0, ncp->procp);
+ while (ncp->nc_lwant) {
+ printf("lwant = %d\n", ncp->nc_lwant);
+ tsleep(&ncp->nc_lwant, PZERO,"ncpdr",2*hz);
+ }
+ ncp_conn_locklist(LK_EXCLUSIVE, ncp->procp);
+ /*
+ * It is possible, that other process destroy connection while we draining,
+ * and free it. So, we must rescan list
+ */
+ SLIST_FOREACH(ncp1, &conn_list, nc_next) {
+ if (ncp1 == ncp) break;
+ }
+ if (ncp1 == NULL) {
+ ncp_conn_unlocklist(ncp->procp);
+ return 0;
+ }
+ SLIST_REMOVE(&conn_list, ncp, ncp_conn, nc_next);
+ ncp_conn_cnt--;
+ ncp_conn_unlocklist(ncp->procp);
+ if (ncp->li.user) free(ncp->li.user, M_NCPDATA);
+ if (ncp->li.password) free(ncp->li.password, M_NCPDATA);
+ crfree(ncp->nc_owner);
+ FREE(ncp, M_NCPDATA);
+ return (0);
+}
+
+/*
+ * Lookup connection by handle, return a locked conn descriptor
+ */
+int
+ncp_conn_getbyref(int ref,struct proc *p,struct ucred *cred, int mode, struct ncp_conn **connpp){
+ struct ncp_conn *ncp;
+ int error=0;
+
+ ncp_conn_locklist(LK_SHARED, p);
+ SLIST_FOREACH(ncp, &conn_list, nc_next)
+ if (ncp->nc_id == ref) break;
+ if (ncp == NULL) {
+ ncp_conn_unlocklist(p);
+ return(EBADF);
+ }
+ error = ncp_conn_lock2(ncp, p, cred, mode);
+ if (!error)
+ *connpp = ncp;
+ return (error);
+}
+/*
+ * find attached, but not logged in connection to specified server
+ */
+int
+ncp_conn_getattached(struct ncp_conn_args *li,struct proc *p,struct ucred *cred,int mode, struct ncp_conn **connpp){
+ struct ncp_conn *ncp, *ncp2=NULL;
+ int error = 0;
+
+ ncp_conn_locklist(LK_SHARED, p);
+ SLIST_FOREACH(ncp, &conn_list, nc_next) {
+ if ((ncp->flags & NCPFL_LOGGED) != 0 ||
+ strcmp(ncp->li.server,li->server) != 0 ||
+ ncp->li.saddr.sa_len != li->saddr.sa_len ||
+ memcmp(&ncp->li.saddr,&ncp->li.saddr,li->saddr.sa_len) != 0)
+ continue;
+ if (ncp_suser(cred) == 0 ||
+ cred->cr_uid == ncp->nc_owner->cr_uid)
+ break;
+ error = ncp_conn_access(ncp,cred,mode);
+ if (!error && ncp2 == NULL)
+ ncp2 = ncp;
+ }
+ if (ncp == NULL) ncp = ncp2;
+ if (ncp == NULL) {
+ ncp_conn_unlocklist(p);
+ return(EBADF);
+ }
+ error = ncp_conn_lock2(ncp,p,cred,mode);
+ if (!error)
+ *connpp=ncp;
+ return (error);
+}
+
+/*
+ * Lookup connection by server/user pair, return a locked conn descriptor.
+ * if li is NULL or server/user pair incomplete, try to select best connection
+ * based on owner.
+ * Connection selected in next order:
+ * 1. Try to search conn with ucred owner, if li is NULL also find a primary
+ * 2. If 1. fails try to get first suitable shared connection
+ * 3. If 2. fails then nothing can help to poor ucred owner
+ */
+
+int
+ncp_conn_getbyli(struct ncp_conn_args *li,struct proc *p,struct ucred *cred,int mode, struct ncp_conn **connpp){
+ struct ncp_conn *ncp, *ncp2=NULL;
+ int error=0, partial, haveserv;
+
+ partial = (li == NULL || li->server[0] == 0 || li->user == NULL);
+ haveserv = (li && li->server[0]);
+ ncp_conn_locklist(LK_SHARED, p);
+ SLIST_FOREACH(ncp, &conn_list, nc_next) {
+ if (partial) {
+ if (cred->cr_uid == ncp->nc_owner->cr_uid) {
+ if (haveserv) {
+ if (strcmp(ncp->li.server,li->server) == 0)
+ break;
+ } else {
+ if (ncp->flags & NCPFL_PRIMARY)
+ break;
+ ncp2 = ncp;
+ }
+ continue;
+ }
+ } else {
+ if (strcmp(ncp->li.server,li->server) != 0 ||
+ ncp->li.user == NULL ||
+ strcmp(ncp->li.user,li->user) != 0)
+ continue;
+ if (cred->cr_uid == ncp->nc_owner->cr_uid)
+ break;
+ if (ncp_suser(cred) == 0)
+ ncp2 = ncp;
+ }
+ error = ncp_conn_access(ncp,cred,mode);
+ if (!error && ncp2 == NULL)
+ ncp2 = ncp;
+ }
+ if (ncp == NULL) ncp = ncp2;
+ if (ncp == NULL) {
+ ncp_conn_unlocklist(p);
+ return(EBADF);
+ }
+ error = ncp_conn_lock2(ncp,p,cred,mode);
+ if (!error)
+ *connpp=ncp;
+ return (error);
+}
+
+/*
+ * Set primary connection flag, since it have sence only for an owner,
+ * only owner can modify this flag.
+ * connection expected to be locked.
+ */
+int
+ncp_conn_setprimary(struct ncp_conn *conn, int on){
+ struct ncp_conn *ncp=NULL;
+
+ if (conn->ucred->cr_uid != conn->nc_owner->cr_uid)
+ return EACCES;
+ ncp_conn_locklist(LK_SHARED, conn->procp);
+ SLIST_FOREACH(ncp, &conn_list, nc_next) {
+ if (conn->ucred->cr_uid == ncp->nc_owner->cr_uid)
+ ncp->flags &= ~NCPFL_PRIMARY;
+ }
+ ncp_conn_unlocklist(conn->procp);
+ if (on)
+ conn->flags |= NCPFL_PRIMARY;
+ return 0;
+}
+/*
+ * Lease conn to given proc, returning unique handle
+ * problem: how locks should be applied ?
+ */
+int
+ncp_conn_gethandle(struct ncp_conn *conn, struct proc *p, struct ncp_handle **handle){
+ struct ncp_handle *refp;
+
+ lockmgr(&lhlock, LK_EXCLUSIVE, 0, p);
+ SLIST_FOREACH(refp, &lhlist, nh_next)
+ if (refp->nh_conn == conn && p == refp->nh_proc) break;
+ if (refp) {
+ conn->ref_cnt++;
+ refp->nh_ref++;
+ *handle = refp;
+ lockmgr(&lhlock, LK_RELEASE, 0, p);
+ return 0;
+ }
+ MALLOC(refp,struct ncp_handle *,sizeof(struct ncp_handle),M_NCPDATA,M_WAITOK);
+ if (refp == NULL) return ENOMEM;
+ bzero(refp,sizeof(*refp));
+ SLIST_INSERT_HEAD(&lhlist,refp,nh_next);
+ refp->nh_ref++;
+ refp->nh_proc = p;
+ refp->nh_conn = conn;
+ refp->nh_id = ncp_next_handle++;
+ *handle = refp;
+ conn->ref_cnt++;
+ lockmgr(&lhlock, LK_RELEASE, 0, p);
+ return 0;
+}
+/*
+ * release reference, if force - ignore refcount
+ */
+int
+ncp_conn_puthandle(struct ncp_handle *handle, struct proc *p, int force) {
+ struct ncp_handle *refp = handle;
+
+ lockmgr(&lhlock, LK_EXCLUSIVE, 0, p);
+ refp->nh_ref--;
+ refp->nh_conn->ref_cnt--;
+ if (force) {
+ refp->nh_conn->ref_cnt -= refp->nh_ref;
+ refp->nh_ref = 0;
+ }
+ if (refp->nh_ref == 0) {
+ SLIST_REMOVE(&lhlist, refp, ncp_handle, nh_next);
+ FREE(refp, M_NCPDATA);
+ }
+ lockmgr(&lhlock, LK_RELEASE, 0, p);
+ return 0;
+}
+/*
+ * find a connHandle
+ */
+int
+ncp_conn_findhandle(int connHandle, struct proc *p, struct ncp_handle **handle) {
+ struct ncp_handle *refp;
+
+ lockmgr(&lhlock, LK_SHARED, 0, p);
+ SLIST_FOREACH(refp, &lhlist, nh_next)
+ if (refp->nh_proc == p && refp->nh_id == connHandle) break;
+ lockmgr(&lhlock, LK_RELEASE, 0, p);
+ if (refp == NULL) {
+ return EBADF;
+ }
+ *handle = refp;
+ return 0;
+}
+/*
+ * Clear handles associated with specified process
+ */
+int
+ncp_conn_putprochandles(struct proc *p) {
+ struct ncp_handle *hp, *nhp;
+ int haveone = 0;
+
+ lockmgr(&lhlock, LK_EXCLUSIVE, 0, p);
+ for (hp = lhlist.slh_first; hp; hp = nhp) {
+ nhp = hp->nh_next.sle_next;
+ if (hp->nh_proc != p) continue;
+ haveone = 1;
+ hp->nh_conn->ref_cnt -= hp->nh_ref;
+ SLIST_REMOVE(&lhlist, hp, ncp_handle, nh_next);
+ FREE(hp, M_NCPDATA);
+ }
+ lockmgr(&lhlock, LK_RELEASE, 0, p);
+ return haveone;
+}
+/*
+ * remove references in all possible connections,
+ * XXX - possible problem is a locked list.
+ */
+/*void
+ncp_conn_list_rm_ref(pid_t pid) {
+ struct ncp_conn *ncp;
+
+ ncp_conn_locklist(LK_SHARED, NULL);
+ SLIST_FOREACH(ncp, &conn_list, nc_next) {
+ ncp_conn_rm_ref(ncp,pid,1);
+ }
+ ncp_conn_unlocklist(NULL);
+ return;
+}
+*/
+int
+ncp_conn_getinfo(struct ncp_conn *ncp, struct ncp_conn_stat *ncs) {
+ bzero(ncs,sizeof(*ncs));
+ ncs->li = ncp->li;
+ ncs->li.user = ncs->user;
+ if (ncp->li.user)
+ strcpy(ncs->user, ncp->li.user);
+ ncs->li.password = NULL;
+ ncs->connRef = ncp->nc_id;
+ ncs->ref_cnt = ncp->ref_cnt;
+ ncs->connid = ncp->connid;
+ ncs->owner = ncp->nc_owner->cr_uid;
+ ncs->group = ncp->nc_group;
+ ncs->flags = ncp->flags;
+ ncs->buffer_size = ncp->buffer_size;
+ return 0;
+}
+
+static int
+ncp_sysctl_connstat SYSCTL_HANDLER_ARGS {
+ int error;
+ struct ncp_conn_stat ncs;
+ struct ncp_conn *ncp;
+/* struct ucred *cred = req->p->p_ucred;*/
+
+ error = 0;
+ ncp_conn_locklist(LK_SHARED, req->p);
+ error = SYSCTL_OUT(req, &ncp_conn_cnt, sizeof(ncp_conn_cnt));
+ SLIST_FOREACH(ncp, &conn_list, nc_next) {
+ if (error) break;
+ /* I can't do conn_lock while list is locked */
+ ncp->nc_lwant++;
+ if (!error) {
+ ncp_conn_getinfo(ncp, &ncs);
+ } else {
+ bzero(&ncs,sizeof(ncs));
+ ncs.connRef = ncp->nc_id;
+ strcpy(ncs.li.server,"***");
+ }
+ ncp->nc_lwant--;
+ error = SYSCTL_OUT(req, &ncs, sizeof(ncs));
+ }
+ ncp_conn_unlocklist(req->p);
+ return(error);
+}
diff --git a/sys/netncp/ncp_conn.h b/sys/netncp/ncp_conn.h
new file mode 100644
index 0000000..8e7df8f
--- /dev/null
+++ b/sys/netncp/ncp_conn.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_CONN_H_
+#define _NCP_CONN_H_
+
+#ifdef INET
+#ifndef _NETINET_IN_H_
+#include <netinet/in.h>
+#endif
+#endif
+
+#ifdef IPX
+#ifndef _NETIPX_IPX_H_
+#include <netipx/ipx.h>
+#endif
+#endif
+
+#ifndef _SYS_SOCKET_H_
+#include <sys/socket.h>
+#endif
+
+/* type of transport we use */
+/*#define NCP_ON_IPX 0
+#define NCP_ON_TCP 1*/
+
+/* flags field in conn structure */
+#define NCPFL_SOCONN 0x01 /* socket layer is up */
+#define NCPFL_ATTACHED 0x02 /* ncp layer is up */
+#define NCPFL_LOGGED 0x04 /* logged in to server */
+#define NCPFL_INVALID 0x08 /* last request was not completed */
+#define NCPFL_INTR 0x10 /* interrupted call */
+#define NCPFL_RESTORING 0x20 /* trying to reconnect */
+#define NCPFL_PERMANENT 0x40 /* no way to kill conn, when this set */
+#define NCPFL_PRIMARY 0x80 /* have meaning only for owner */
+#define NCPFL_SIGNACTIVE 0x1000 /* packet signing active */
+#define NCPFL_SIGNWANTED 0x2000 /* signing should start */
+
+/* access mode for connection */
+#define NCPM_READ 0400 /* able to fetch conn params */
+#define NCPM_WRITE 0200 /* modify/close */
+#define NCPM_EXECUTE 0100 /* run requests */
+
+#define NCP_DEFAULT_OWNER ((uid_t)-1)
+#define NCP_DEFAULT_GROUP ((uid_t)-1)
+
+
+/* args used to create connection */
+#define ncp_conn_loginfo ncp_conn_args
+struct ncp_conn_args {
+ int opt;
+#define NCP_OPT_WDOG 1 /* need watch dog socket */
+#define NCP_OPT_MSG 2 /* need message socket */
+#define NCP_OPT_SIGN 4 /* signatures wanted */
+#define NCP_OPT_BIND 8 /* force bindery login */
+#define NCP_OPT_PERMANENT 0x10 /* only for refernce, completly ignored */
+#define NCP_OPT_NOUPCASEPASS 0x20 /* leave password as is */
+ int sig_level; /* wanted signature level */
+ char server[NCP_BINDERY_NAME_LEN+1];
+ char *user;
+ char *password;
+ u_int32_t objtype;
+ union {
+ struct sockaddr addr;
+#ifdef IPX
+ struct sockaddr_ipx ipxaddr;
+#endif
+#ifdef INET
+ struct sockaddr_in inaddr;
+#endif
+ } addr;
+ int timeout; /* ncp rq timeout */
+ int retry_count; /* counts to give an error */
+ uid_t owner; /* proposed owner of connection */
+ gid_t group; /* proposed group of connection */
+ mode_t access_mode; /* R/W - can do rq's, X - can see the conn */
+};
+
+#define ipxaddr addr.ipxaddr
+#define inaddr addr.inaddr
+#define saddr addr.addr
+
+/* user side structure to issue ncp calls */
+struct ncp_buf {
+ int rqsize; /* request size without ncp header */
+ int rpsize; /* reply size minus ncp header */
+ int cc; /* completion code */
+ int cs; /* connection state */
+ char packet[NCP_MAX_PACKET_SIZE];/* Here we prepare requests and receive replies */
+};
+
+/*
+ * Connection status, returned via sysctl(vfs.nwfs.connstat)
+ */
+struct ncp_conn_stat {
+ struct ncp_conn_args li;
+ int connRef;
+ int ref_cnt;
+ int connid;
+ int buffer_size;
+ int flags;
+ int sign_active;
+ uid_t owner;
+ gid_t group;
+ char user[NCP_MAXUSERNAMELEN+1];
+};
+
+#ifdef KERNEL
+
+#ifndef LK_SHARED
+#include <sys/lock.h>
+#endif
+
+struct socket;
+struct u_cred;
+
+SLIST_HEAD(ncp_conn_head,ncp_conn);
+
+struct ncp_rq;
+struct ncp_conn;
+
+/*
+ * External and internal processes can reference connection only by handle.
+ * This gives us a freedom in maintance of underlying connections.
+ */
+struct ncp_handle {
+ SLIST_ENTRY(ncp_handle) nh_next;
+ int nh_id; /* handle id */
+ struct ncp_conn*nh_conn; /* which conn we are refernce */
+ struct proc * nh_proc; /* who owns the handle */
+ int nh_ref; /* one process can asquire many handles, but we return the one */
+};
+
+/*
+ * Describes any connection to server
+ */
+struct ncp_conn {
+ SLIST_ENTRY(ncp_conn) nc_next;
+ struct ncp_conn_args li;
+ struct ucred *nc_owner;
+ gid_t nc_group;
+ int flags;
+ int nc_id;
+ struct socket *ncp_so;
+ struct socket *wdg_so;
+ struct socket *msg_so;
+ struct socket *bc_so;
+ int ref_cnt; /* how many handles leased */
+ SLIST_HEAD(ncp_ref_hd,ncp_ref) ref_list;/* list of handles */
+ struct lock nc_lock; /* excl locks */
+ int nc_lwant; /* number of wanted locks */
+ struct proc *procp; /* pid currently operates */
+ struct ucred *ucred; /* usr currently operates */
+ struct ncp_rq *nc_rq; /* current request */
+ /* Fields used to process ncp requests */
+ int connid; /* assigned by server */
+ u_int8_t seq;
+ int buffer_size; /* Negotiated bufsize */
+ /* Fields used to make packet signatures */
+ u_int32_t sign_root[2];
+ u_int32_t sign_state[4]; /* md4 state */
+#ifdef NCPBURST
+ /* Fields used for packet bursting */
+ u_long bc_pktseq; /* raw packet sequence */
+ u_short bc_seq; /* burst sequence */
+ u_long bc_locid; /* local connection id */
+ u_long bc_remid; /* remote connection id */
+ u_long bc_pktsize; /* negotiated burst packet size */
+#endif
+};
+
+#define ncp_conn_signwanted(conn) ((conn)->flags & NCPFL_SIGNWANTED)
+#define ncp_conn_valid(conn) ((conn->flags & NCPFL_INVALID) == 0)
+#define ncp_conn_invalidate(conn) {conn->flags |= NCPFL_INVALID;}
+
+int ncp_conn_init(void);
+int ncp_conn_alloc(struct proc *p,struct ucred *cred, struct ncp_conn **connid);
+int ncp_conn_free(struct ncp_conn *conn);
+int ncp_conn_access(struct ncp_conn *conn,struct ucred *cred,mode_t mode);
+int ncp_conn_lock(struct ncp_conn *conn,struct proc *p,struct ucred *cred,int mode);
+void ncp_conn_unlock(struct ncp_conn *conn,struct proc *p);
+int ncp_conn_assert_locked(struct ncp_conn *conn,char *checker,struct proc *p);
+/*int ncp_conn_ref(struct ncp_conn *conn, pid_t pid);
+int ncp_conn_rm_ref(struct ncp_conn *conn, pid_t pid, int force);
+void ncp_conn_list_rm_ref(pid_t pid);*/
+int ncp_conn_getbyref(int connRef,struct proc *p,struct ucred *cred, int mode,
+ struct ncp_conn **connpp);
+int ncp_conn_getbyli(struct ncp_conn_loginfo *li,struct proc *p,struct ucred *cred,
+ int mode, struct ncp_conn **connpp);
+int ncp_conn_setprimary(struct ncp_conn *conn, int on);
+int ncp_conn_locklist(int flags, struct proc *p);
+void ncp_conn_unlocklist(struct proc *p);
+int ncp_conn_gethandle(struct ncp_conn *conn, struct proc *p, struct ncp_handle **handle);
+int ncp_conn_puthandle(struct ncp_handle *handle, struct proc *p, int force);
+int ncp_conn_findhandle(int connHandle, struct proc *p, struct ncp_handle **handle);
+int ncp_conn_getattached(struct ncp_conn_args *li,struct proc *p,struct ucred *cred,int mode, struct ncp_conn **connpp);
+int ncp_conn_putprochandles(struct proc *p);
+int ncp_conn_getinfo(struct ncp_conn *ncp, struct ncp_conn_stat *ncs);
+
+extern struct ncp_conn_head conn_list;
+extern int ncp_burst_enabled;
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_NCPDATA);
+#endif
+
+#endif /* KERNEL */
+#endif /* _NCP_CONN_H_ */
diff --git a/sys/netncp/ncp_crypt.c b/sys/netncp/ncp_crypt.c
new file mode 100644
index 0000000..9ee0665
--- /dev/null
+++ b/sys/netncp/ncp_crypt.c
@@ -0,0 +1,278 @@
+/*
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <netncp/ncp.h>
+#include <netncp/ncp_subr.h>
+
+/*
+ * Routines in this file based on work of Volker Lendecke
+ */
+/*$*********************************************************
+ $*
+ $* This code has been taken from DDJ 11/93, from an
+ $* article by Pawel Szczerbina.
+ $*
+ $* Password encryption routines follow.
+ $* Converted to C from Barry Nance's Pascal
+ $* prog published in the March -93 issue of Byte.
+ $*
+ $* Adapted to be useable for ncpfs by
+ $* Volker Lendecke <lendecke@namu01.gwdg.de> in
+ $* October 1995.
+ $*
+ $********************************************************* */
+
+
+
+typedef unsigned char buf32[32];
+
+static unsigned char encrypttable[256] = {
+0x7, 0x8, 0x0, 0x8, 0x6, 0x4, 0xE, 0x4, 0x5, 0xC, 0x1, 0x7, 0xB, 0xF, 0xA, 0x8,
+0xF, 0x8, 0xC, 0xC, 0x9, 0x4, 0x1, 0xE, 0x4, 0x6, 0x2, 0x4, 0x0, 0xA, 0xB, 0x9,
+0x2, 0xF, 0xB, 0x1, 0xD, 0x2, 0x1, 0x9, 0x5, 0xE, 0x7, 0x0, 0x0, 0x2, 0x6, 0x6,
+0x0, 0x7, 0x3, 0x8, 0x2, 0x9, 0x3, 0xF, 0x7, 0xF, 0xC, 0xF, 0x6, 0x4, 0xA, 0x0,
+0x2, 0x3, 0xA, 0xB, 0xD, 0x8, 0x3, 0xA, 0x1, 0x7, 0xC, 0xF, 0x1, 0x8, 0x9, 0xD,
+0x9, 0x1, 0x9, 0x4, 0xE, 0x4, 0xC, 0x5, 0x5, 0xC, 0x8, 0xB, 0x2, 0x3, 0x9, 0xE,
+0x7, 0x7, 0x6, 0x9, 0xE, 0xF, 0xC, 0x8, 0xD, 0x1, 0xA, 0x6, 0xE, 0xD, 0x0, 0x7,
+0x7, 0xA, 0x0, 0x1, 0xF, 0x5, 0x4, 0xB, 0x7, 0xB, 0xE, 0xC, 0x9, 0x5, 0xD, 0x1,
+0xB, 0xD, 0x1, 0x3, 0x5, 0xD, 0xE, 0x6, 0x3, 0x0, 0xB, 0xB, 0xF, 0x3, 0x6, 0x4,
+0x9, 0xD, 0xA, 0x3, 0x1, 0x4, 0x9, 0x4, 0x8, 0x3, 0xB, 0xE, 0x5, 0x0, 0x5, 0x2,
+0xC, 0xB, 0xD, 0x5, 0xD, 0x5, 0xD, 0x2, 0xD, 0x9, 0xA, 0xC, 0xA, 0x0, 0xB, 0x3,
+0x5, 0x3, 0x6, 0x9, 0x5, 0x1, 0xE, 0xE, 0x0, 0xE, 0x8, 0x2, 0xD, 0x2, 0x2, 0x0,
+0x4, 0xF, 0x8, 0x5, 0x9, 0x6, 0x8, 0x6, 0xB, 0xA, 0xB, 0xF, 0x0, 0x7, 0x2, 0x8,
+0xC, 0x7, 0x3, 0xA, 0x1, 0x4, 0x2, 0x5, 0xF, 0x7, 0xA, 0xC, 0xE, 0x5, 0x9, 0x3,
+0xE, 0x7, 0x1, 0x2, 0xE, 0x1, 0xF, 0x4, 0xA, 0x6, 0xC, 0x6, 0xF, 0x4, 0x3, 0x0,
+0xC, 0x0, 0x3, 0x6, 0xF, 0x8, 0x7, 0xB, 0x2, 0xD, 0xC, 0x6, 0xA, 0xA, 0x8, 0xD
+};
+
+static buf32 encryptkeys = {
+ 0x48, 0x93, 0x46, 0x67, 0x98, 0x3D, 0xE6, 0x8D,
+ 0xB7, 0x10, 0x7A, 0x26, 0x5A, 0xB9, 0xB1, 0x35,
+ 0x6B, 0x0F, 0xD5, 0x70, 0xAE, 0xFB, 0xAD, 0x11,
+ 0xF4, 0x47, 0xDC, 0xA7, 0xEC, 0xCF, 0x50, 0xC0
+};
+
+/*
+ * Create table-based 16-bytes hash from a 32-bytes array
+ */
+static void
+nw_hash(buf32 temp, unsigned char *target) {
+ short sum;
+ unsigned char b3;
+ int s, b2, i;
+
+ sum = 0;
+
+ for (b2 = 0; b2 <= 1; ++b2) {
+ for (s = 0; s <= 31; ++s) {
+ b3 = (temp[s] + sum) ^ (temp[(s + sum) & 31] - encryptkeys[s]);
+ sum += b3;
+ temp[s] = b3;
+ }
+ }
+
+ for (i = 0; i <= 15; ++i) {
+ target[i] = encrypttable[temp[2 * i]]
+ | (encrypttable[temp[2 * i + 1]] << 4);
+ }
+}
+
+
+/*
+ * Create a 16-bytes pattern from given buffer based on a four bytes key
+ */
+void
+nw_keyhash(const u_char *key, const u_char *buf, int buflen, u_char *target) {
+ int b2, d, s;
+ buf32 temp;
+
+ while (buflen > 0 && buf[buflen - 1] == 0)
+ buflen--;
+
+ bzero(temp, sizeof(temp));
+
+ d = 0;
+ while (buflen >= 32) {
+ for (s = 0; s <= 31; ++s)
+ temp[s] ^= buf[d++];
+ buflen -= 32;
+ }
+ b2 = d;
+ if (buflen > 0) {
+ for (s = 0; s <= 31; ++s) {
+ if (d + buflen == b2) {
+ temp[s] ^= encryptkeys[s];
+ b2 = d;
+ } else
+ temp[s] ^= buf[b2++];
+ }
+ }
+ for (s = 0; s <= 31; ++s)
+ temp[s] ^= key[s & 3];
+
+ nw_hash(temp, target);
+}
+
+/*
+ * Create an 8-bytes pattern from an 8-bytes key and 16-bytes of data
+ */
+void
+nw_encrypt(const u_char *fra, const u_char *buf, u_char *target) {
+ buf32 k;
+ int s;
+
+ nw_keyhash(fra, buf, 16, k);
+ nw_keyhash(fra + 4, buf, 16, k + 16);
+
+ for (s = 0; s < 16; s++)
+ k[s] ^= k[31 - s];
+
+ for (s = 0; s < 8; s++)
+ *target++ = k[s] ^ k[15 - s];
+}
+
+#ifdef KERNEL
+/*
+ * MD4 routine taken from libmd sources
+ */
+typedef u_int32_t UINT4;
+typedef unsigned char *POINTER;
+
+#define PROTO_LIST(list) list
+
+static void Decode PROTO_LIST
+ ((UINT4 *, const unsigned char *, unsigned int));
+
+/* Constants for MD4Transform routine.
+ */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+/* F, G and H are basic MD4 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) { \
+ (a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define GG(a, b, c, d, x, s) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define HH(a, b, c, d, x, s) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+
+void
+ncp_sign(const u_int32_t *state, const char *block, u_int32_t *ostate) {
+ UINT4 a, b, c, d, x[16];
+
+ Decode (x, block, 64);
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11); /* 1 */
+ FF (d, a, b, c, x[ 1], S12); /* 2 */
+ FF (c, d, a, b, x[ 2], S13); /* 3 */
+ FF (b, c, d, a, x[ 3], S14); /* 4 */
+ FF (a, b, c, d, x[ 4], S11); /* 5 */
+ FF (d, a, b, c, x[ 5], S12); /* 6 */
+ FF (c, d, a, b, x[ 6], S13); /* 7 */
+ FF (b, c, d, a, x[ 7], S14); /* 8 */
+ FF (a, b, c, d, x[ 8], S11); /* 9 */
+ FF (d, a, b, c, x[ 9], S12); /* 10 */
+ FF (c, d, a, b, x[10], S13); /* 11 */
+ FF (b, c, d, a, x[11], S14); /* 12 */
+ FF (a, b, c, d, x[12], S11); /* 13 */
+ FF (d, a, b, c, x[13], S12); /* 14 */
+ FF (c, d, a, b, x[14], S13); /* 15 */
+ FF (b, c, d, a, x[15], S14); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 0], S21); /* 17 */
+ GG (d, a, b, c, x[ 4], S22); /* 18 */
+ GG (c, d, a, b, x[ 8], S23); /* 19 */
+ GG (b, c, d, a, x[12], S24); /* 20 */
+ GG (a, b, c, d, x[ 1], S21); /* 21 */
+ GG (d, a, b, c, x[ 5], S22); /* 22 */
+ GG (c, d, a, b, x[ 9], S23); /* 23 */
+ GG (b, c, d, a, x[13], S24); /* 24 */
+ GG (a, b, c, d, x[ 2], S21); /* 25 */
+ GG (d, a, b, c, x[ 6], S22); /* 26 */
+ GG (c, d, a, b, x[10], S23); /* 27 */
+ GG (b, c, d, a, x[14], S24); /* 28 */
+ GG (a, b, c, d, x[ 3], S21); /* 29 */
+ GG (d, a, b, c, x[ 7], S22); /* 30 */
+ GG (c, d, a, b, x[11], S23); /* 31 */
+ GG (b, c, d, a, x[15], S24); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 0], S31); /* 33 */
+ HH (d, a, b, c, x[ 8], S32); /* 34 */
+ HH (c, d, a, b, x[ 4], S33); /* 35 */
+ HH (b, c, d, a, x[12], S34); /* 36 */
+ HH (a, b, c, d, x[ 2], S31); /* 37 */
+ HH (d, a, b, c, x[10], S32); /* 38 */
+ HH (c, d, a, b, x[ 6], S33); /* 39 */
+ HH (b, c, d, a, x[14], S34); /* 40 */
+ HH (a, b, c, d, x[ 1], S31); /* 41 */
+ HH (d, a, b, c, x[ 9], S32); /* 42 */
+ HH (c, d, a, b, x[ 5], S33); /* 43 */
+ HH (b, c, d, a, x[13], S34); /* 44 */
+ HH (a, b, c, d, x[ 3], S31); /* 45 */
+ HH (d, a, b, c, x[11], S32); /* 46 */
+ HH (c, d, a, b, x[ 7], S33); /* 47 */
+ HH (b, c, d, a, x[15], S34); /* 48 */
+
+ ostate[0] = state[0] + a;
+ ostate[1] = state[1] + b;
+ ostate[2] = state[2] + c;
+ ostate[3] = state[3] + d;
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+
+UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif /* KERNEL */
diff --git a/sys/netncp/ncp_login.c b/sys/netncp/ncp_login.c
new file mode 100644
index 0000000..bac5ac5
--- /dev/null
+++ b/sys/netncp/ncp_login.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/ncp_nls.h>
+#include <netncp/nwerror.h>
+
+static int ncp_login_encrypted(struct ncp_conn *conn, struct ncp_bindery_object *object,
+ unsigned char *key, unsigned char *passwd,
+ struct proc *p, struct ucred *cred);
+static int ncp_login_unencrypted(struct ncp_conn *conn, u_int16_t object_type,
+ char *object_name, unsigned char *passwd,
+ struct proc *p, struct ucred *cred);
+static int ncp_sign_start(struct ncp_conn *conn, char *logindata);
+static int ncp_get_encryption_key(struct ncp_conn *conn, char *target);
+
+/*
+ * Initialize packet signatures. They a slightly modified MD4.
+ * The first 16 bytes of logindata are the shuffled password,
+ * the last 8 bytes the encryption key as received from the server.
+ */
+int
+ncp_sign_start(struct ncp_conn *conn, char *logindata) {
+ char msg[64];
+ u_int32_t state[4];
+
+ memcpy(msg, logindata, 24);
+ memcpy(msg + 24, "Authorized NetWare Client", 25);
+ bzero(msg + 24 + 25, sizeof(msg) - 24 - 25);
+
+ conn->sign_state[0] = 0x67452301;
+ conn->sign_state[1] = 0xefcdab89;
+ conn->sign_state[2] = 0x98badcfe;
+ conn->sign_state[3] = 0x10325476;
+ ncp_sign(conn->sign_state, msg, state);
+ conn->sign_root[0] = state[0];
+ conn->sign_root[1] = state[1];
+ conn->flags |= NCPFL_SIGNACTIVE;
+ return 0;
+}
+
+/*
+ * target is a 8-byte buffer
+ */
+int
+ncp_get_encryption_key(struct ncp_conn *conn, char *target) {
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD_S(23,23,conn->procp,conn->ucred);
+ checkbad(ncp_request(conn,rqp));
+ if (rqp->rpsize < 8) {
+ NCPFATAL("rpsize=%d < 8\n", rqp->rpsize);
+ return EIO;
+ }
+ ncp_rp_mem(rqp, target, 8);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_login_object(struct ncp_conn *conn, unsigned char *username,
+ int login_type, unsigned char *password,
+ struct proc *p,struct ucred *cred)
+{
+ int error;
+ unsigned char ncp_key[8];
+ struct ncp_bindery_object user;
+
+ if ((error = ncp_get_encryption_key(conn, ncp_key)) != 0) {
+ printf("%s: Warning: use unencrypted login\n", __FUNCTION__);
+ return ncp_login_unencrypted(conn, login_type, username, password,p,cred);
+ }
+ if ((error = ncp_get_bindery_object_id(conn, login_type, username, &user,p,cred)) != 0) {
+ return error;
+ }
+ error = ncp_login_encrypted(conn, &user, ncp_key, password,p,cred);
+ return error;
+}
+
+int
+ncp_login_encrypted(struct ncp_conn *conn, struct ncp_bindery_object *object,
+ unsigned char *key, unsigned char *passwd,
+ struct proc *p,struct ucred *cred) {
+ u_int32_t tmpID = htonl(object->object_id);
+ u_char buf[16 + 8];
+ u_char encrypted[8];
+ int error;
+ DECLARE_RQ;
+
+ nw_keyhash((u_char*)&tmpID, passwd, strlen(passwd), buf);
+ nw_encrypt(key, buf, encrypted);
+
+ NCP_RQ_HEAD_S(23,24,p,cred);
+ ncp_rq_mem(rqp, encrypted, 8);
+ ncp_rq_word_hl(rqp, object->object_type);
+ ncp_rq_pstring(rqp, object->object_name);
+ error = ncp_request(conn, rqp);
+ NCP_RQ_EXIT_NB;
+ if (conn->flags & NCPFL_SIGNWANTED) {
+ if (error == 0 || error == NWE_PASSWORD_EXPIRED) {
+ memcpy(buf + 16, key, 8);
+ error = ncp_sign_start(conn, buf);
+ }
+ }
+ return error;
+}
+
+int
+ncp_login_unencrypted(struct ncp_conn *conn, u_int16_t object_type,
+ char *object_name, unsigned char *passwd,
+ struct proc *p, struct ucred *cred)
+{
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD_S(23,20,conn->procp,conn->ucred);
+ ncp_rq_word_hl(rqp, object_type);
+ ncp_rq_pstring(rqp, object_name);
+ ncp_rq_pstring(rqp, passwd);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+/*
+ * Login to specified server with username and password.
+ * conn should be locked.
+ */
+int
+ncp_login(struct ncp_conn *conn, char *user, int objtype, char *password,
+ struct proc *p, struct ucred *cred) {
+ int error;
+
+ if (ncp_suser(cred) != 0 && cred->cr_uid != conn->nc_owner->cr_uid)
+ return EACCES;
+ if (conn->flags & NCPFL_LOGGED) return EALREADY;
+ if ((conn->flags & NCPFL_ATTACHED) == 0) return ENOTCONN;
+ conn->li.user = ncp_str_dup(user);
+ conn->li.password = ncp_str_dup(password);
+ if (conn->li.user == NULL || conn->li.password == NULL) {
+ error = EINVAL;
+ goto bad;
+ }
+ ncp_str_upper(conn->li.user);
+ if ((conn->li.opt & NCP_OPT_NOUPCASEPASS) == 0)
+ ncp_str_upper(conn->li.password);
+ checkbad(ncp_login_object(conn, conn->li.user, objtype, conn->li.password,p,cred));
+ conn->li.objtype = objtype;
+ conn->flags |= NCPFL_LOGGED;
+ return 0;
+bad:
+ if (conn->li.user) free(conn->li.user, M_NCPDATA);
+ if (conn->li.password) free(conn->li.password, M_NCPDATA);
+ conn->li.user = conn->li.password = NULL;
+ return error;
+}
diff --git a/sys/netncp/ncp_mod.c b/sys/netncp/ncp_mod.c
new file mode 100644
index 0000000..59325ba
--- /dev/null
+++ b/sys/netncp/ncp_mod.c
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_user.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/ncp_nls.h>
+
+int ncp_version = NCP_VERSION;
+
+static int ncp_sysent;
+
+SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
+SYSCTL_INT(_net_ncp, OID_AUTO, sysent, CTLFLAG_RD, &ncp_sysent, 0, "");
+SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
+
+static int
+ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp);
+
+/*
+ * Attach to NCP server
+ */
+struct sncp_connect_args {
+ struct ncp_conn_args *li;
+ int *connHandle;
+};
+
+static int
+__P(sncp_connect(struct proc *p, struct sncp_connect_args *uap)){
+ int connHandle = 0, error;
+ struct ncp_conn *conn;
+ struct ncp_handle *handle;
+ struct ncp_conn_args li;
+
+ checkbad(copyin(uap->li,&li,sizeof(li)));
+ checkbad(copyout(&connHandle,uap->connHandle,sizeof(connHandle))); /* check before */
+ li.password = li.user = NULL;
+ error = ncp_conn_getattached(&li, p, p->p_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
+ if (error) {
+ error = ncp_connect(&li, p, p->p_ucred, &conn);
+ }
+ if (!error) {
+ error = ncp_conn_gethandle(conn, p, &handle);
+ copyout(&handle->nh_id, uap->connHandle, sizeof(uap->connHandle));
+ ncp_conn_unlock(conn,p);
+ }
+bad:
+ p->p_retval[0]=error;
+ return error;
+}
+
+struct sncp_request_args {
+ int connHandle;
+ int fn;
+ struct ncp_buf *ncpbuf;
+};
+
+static int ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
+ struct ncp_conn *conn, struct ncp_handle *handle);
+
+static int
+__P(sncp_request(struct proc *p, struct sncp_request_args *uap)){
+ int error = 0, rqsize;
+ struct ncp_conn *conn;
+ struct ncp_handle *handle;
+ DECLARE_RQ;
+
+ error = ncp_conn_findhandle(uap->connHandle,p,&handle);
+ if (error) return error;
+ conn = handle->nh_conn;
+ if (uap->fn == NCP_CONN)
+ return ncp_conn_handler(p, uap, conn, handle);
+ error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
+ if (error) return(error);
+ error = ncp_conn_lock(conn,p,p->p_ucred,NCPM_EXECUTE);
+ if (error) return(error);
+ ncp_rq_head(rqp,NCP_REQUEST,uap->fn,p,p->p_ucred);
+ if (rqsize)
+ error = ncp_rq_usermem(rqp,(caddr_t)uap->ncpbuf->packet, rqsize);
+ if (!error) {
+ error = ncp_request(conn, rqp);
+ if (error == 0 && rqp->rpsize)
+ ncp_rp_usermem(rqp, (caddr_t)uap->ncpbuf->packet,
+ rqp->rpsize);
+ copyout(&rqp->cs, &uap->ncpbuf->cs, sizeof(rqp->cs));
+ copyout(&rqp->cc, &uap->ncpbuf->cc, sizeof(rqp->cc));
+ copyout(&rqp->rpsize, &uap->ncpbuf->rpsize, sizeof(rqp->rpsize));
+ }
+ ncp_rq_done(rqp);
+ ncp_conn_unlock(conn,p);
+ return error;
+}
+
+static int
+ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
+ struct ncp_conn *conn, struct ncp_handle *hp)
+{
+ int error=0, rqsize, subfn;
+ struct ucred *cred;
+
+ char *pdata;
+
+ cred = p->p_ucred;
+ error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
+ if (error) return(error);
+ error = 0;
+ pdata = uap->ncpbuf->packet;
+ subfn = *(pdata++) & 0xff;
+ rqsize--;
+ switch (subfn) {
+ case NCP_CONN_READ: case NCP_CONN_WRITE: {
+ struct ncp_rw rwrq;
+ struct uio auio;
+ struct iovec iov;
+
+ if (rqsize != sizeof(rwrq)) return (EBADRPC);
+ error = copyin(pdata,&rwrq,rqsize);
+ if (error) return (error);
+ iov.iov_base = rwrq.nrw_base;
+ iov.iov_len = rwrq.nrw_cnt;
+ auio.uio_iov = &iov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = rwrq.nrw_offset;
+ auio.uio_resid = rwrq.nrw_cnt;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
+ auio.uio_procp = p;
+ error = ncp_conn_lock(conn,p,cred,NCPM_EXECUTE);
+ if (error) return(error);
+ if (subfn == NCP_CONN_READ)
+ error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
+ else
+ error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
+ rwrq.nrw_cnt -= auio.uio_resid;
+ ncp_conn_unlock(conn,p);
+ p->p_retval[0] = rwrq.nrw_cnt;
+ break;
+ } /* case int_read/write */
+ case NCP_CONN_SETFLAGS: {
+ u_int16_t mask, flags;
+
+ error = copyin(pdata,&mask, sizeof(mask));
+ if (error) return error;
+ pdata += sizeof(mask);
+ error = copyin(pdata,&flags,sizeof(flags));
+ if (error) return error;
+ error = ncp_conn_lock(conn,p,cred,NCPM_WRITE);
+ if (error) return error;
+ if (mask & NCPFL_PERMANENT) {
+ conn->flags &= ~NCPFL_PERMANENT;
+ conn->flags |= (flags & NCPFL_PERMANENT);
+ }
+ if (mask & NCPFL_PRIMARY) {
+ error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY);
+ if (error) {
+ ncp_conn_unlock(conn,p);
+ break;
+ }
+ }
+ ncp_conn_unlock(conn,p);
+ break;
+ }
+ case NCP_CONN_LOGIN: {
+ struct ncp_conn_login la;
+
+ if (rqsize != sizeof(la)) return (EBADRPC);
+ if ((error = copyin(pdata,&la,rqsize)) != 0) break;
+ error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE | NCPM_WRITE);
+ if (error) return error;
+ error = ncp_login(conn, la.username, la.objtype, la.password, p, p->p_ucred);
+ ncp_conn_unlock(conn, p);
+ p->p_retval[0] = error;
+ break;
+ }
+ case NCP_CONN_GETINFO: {
+ struct ncp_conn_stat ncs;
+ int len = sizeof(ncs);
+
+ error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
+ if (error) return error;
+ ncp_conn_getinfo(conn, &ncs);
+ copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
+ error = copyout(&ncs, &uap->ncpbuf->packet, len);
+ ncp_conn_unlock(conn, p);
+ break;
+ }
+ case NCP_CONN_GETUSER: {
+ int len;
+
+ error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
+ if (error) return error;
+ len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
+ copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
+ if (len) {
+ error = copyout(conn->li.user, &uap->ncpbuf->packet, len);
+ }
+ ncp_conn_unlock(conn, p);
+ break;
+ }
+ case NCP_CONN_CONN2REF: {
+ int len = sizeof(int);
+
+ error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
+ if (error) return error;
+ copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
+ if (len) {
+ error = copyout(&conn->nc_id, &uap->ncpbuf->packet, len);
+ }
+ ncp_conn_unlock(conn, p);
+ break;
+ }
+ case NCP_CONN_FRAG: {
+ struct ncp_conn_frag nf;
+
+ if (rqsize != sizeof(nf)) return (EBADRPC);
+ if ((error = copyin(pdata, &nf, rqsize)) != 0) break;
+ error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
+ if (error) return error;
+ error = ncp_conn_frag_rq(conn, p, &nf);
+ ncp_conn_unlock(conn, p);
+ copyout(&nf, &pdata, sizeof(nf));
+ p->p_retval[0] = error;
+ break;
+ }
+ case NCP_CONN_DUP: {
+ struct ncp_handle *newhp;
+ int len = sizeof(NWCONN_HANDLE);
+
+ error = ncp_conn_lock(conn, p, cred, NCPM_READ);
+ if (error) break;
+ copyout(&len, &uap->ncpbuf->rpsize, len);
+ error = ncp_conn_gethandle(conn, p, &newhp);
+ if (!error)
+ error = copyout(&newhp->nh_id, uap->ncpbuf->packet, len);
+ ncp_conn_unlock(conn,p);
+ break;
+ }
+ case NCP_CONN_CONNCLOSE: {
+ error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
+ if (error) break;
+ ncp_conn_puthandle(hp, p, 0);
+ error = ncp_disconnect(conn);
+ if (error)
+ ncp_conn_unlock(conn, p);
+ break;
+ }
+ default:
+ error = EOPNOTSUPP;
+ }
+ return error;
+}
+
+struct sncp_conn_scan_args {
+ struct ncp_conn_args *li;
+ int *connHandle;
+};
+
+static int
+__P(sncp_conn_scan(struct proc *p, struct sncp_conn_scan_args *uap)){
+ int connHandle = 0, error;
+ struct ncp_conn_args li, *lip;
+ struct ncp_conn *conn;
+ struct ncp_handle *hp;
+ char *user = NULL, *password = NULL;
+
+ if (uap->li) {
+ if (copyin(uap->li,&li,sizeof(li))) return EFAULT;
+ lip = &li;
+ } else {
+ lip = NULL;
+ }
+
+ if (lip != NULL) {
+ lip->server[sizeof(lip->server)-1]=0; /* just to make sure */
+ ncp_str_upper(lip->server);
+ if (lip->user) {
+ user = ncp_str_dup(lip->user);
+ if (user == NULL) return EINVAL;
+ ncp_str_upper(user);
+ }
+ if (lip->password) {
+ password = ncp_str_dup(lip->password);
+ if (password == NULL) {
+ if (user)
+ free(user, M_NCPDATA);
+ return EINVAL;
+ }
+ ncp_str_upper(password);
+ }
+ lip->user = user;
+ lip->password = password;
+ }
+ error = ncp_conn_getbyli(lip,p,p->p_ucred,NCPM_EXECUTE,&conn);
+ if (!error) { /* already have this login */
+ ncp_conn_gethandle(conn, p, &hp);
+ connHandle = hp->nh_id;
+ ncp_conn_unlock(conn,p);
+ copyout(&connHandle,uap->connHandle,sizeof(connHandle));
+ }
+ if (user) free(user, M_NCPDATA);
+ if (password) free(password, M_NCPDATA);
+ p->p_retval[0] = error;
+ return error;
+
+}
+
+int
+ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp){
+ int error = 0, i, rpsize;
+ u_int32_t fsize;
+ NW_FRAGMENT *fp;
+ DECLARE_RQ;
+
+ ncp_rq_head(rqp,NCP_REQUEST,nfp->fn,p,p->p_ucred);
+ if (nfp->rqfcnt) {
+ for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
+ checkbad(ncp_rq_usermem(rqp,(caddr_t)fp->fragAddress, fp->fragSize));
+ }
+ }
+ checkbad(ncp_request(conn, rqp));
+ rpsize = rqp->rpsize;
+ if (rpsize && nfp->rpfcnt) {
+ for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
+ checkbad(copyin(&fp->fragSize, &fsize, sizeof (fsize)));
+ fsize = min(fsize, rpsize);
+ checkbad(ncp_rp_usermem(rqp,(caddr_t)fp->fragAddress, fsize));
+ rpsize -= fsize;
+ checkbad(copyout(&fsize, &fp->fragSize, sizeof (fsize)));
+ }
+ }
+ nfp->cs = rqp->cs;
+ nfp->cc = rqp->cc;
+ NCP_RQ_EXIT;
+ return error;
+}
+
+/*
+ * Internal functions, here should be all calls that do not require connection.
+ * To simplify possible future movement to cdev, we use IOCTL macros.
+ * Pretty much of this stolen from ioctl() function.
+ */
+struct sncp_intfn_args {
+ u_long com;
+ caddr_t data;
+};
+
+static int
+sncp_intfn(struct proc *p, struct sncp_intfn_args *uap)
+{
+ return ENOSYS;
+}
+/*
+ * define our new system calls
+ */
+static struct sysent newent[] = {
+ {2, (sy_call_t*)sncp_conn_scan},
+ {2, (sy_call_t*)sncp_connect},
+ {2, (sy_call_t*)sncp_intfn},
+ {3, (sy_call_t*)sncp_request}
+};
+
+#define SC_SIZE sizeof(newent)/sizeof(struct sysent)
+/*
+ * Miscellaneous modules must have their own save areas...
+ */
+static struct sysent oldent[SC_SIZE]; /* save are for old callslot entry*/
+
+/*
+ * Number of syscall entries for a.out executables
+ */
+/*#define nsysent SYS_MAXSYSCALL*/
+#define nsysent (aout_sysvec.sv_size)
+
+
+static int
+ncp_load(void) {
+ int i, ff, scnt, err=0;
+
+ while(1) {
+ /* Search the table looking for an enough number of slots... */
+ for (scnt=0, ff = -1, i = 0; i < nsysent; i++) {
+ if (sysent[i].sy_call == (sy_call_t *)lkmnosys) {
+ if (ff == -1) {
+ ff = i;
+ scnt = 1;
+ } else {
+ scnt++;
+ if (scnt == SC_SIZE) break;
+ }
+ } else {
+ ff = -1;
+ }
+ }
+ /* out of allocable slots?*/
+ if(i == nsysent || ff == -1) {
+ err = ENFILE;
+ break;
+ }
+ err = ncp_init();
+ if (err) break;
+ bcopy(&sysent[ff], &oldent, sizeof(struct sysent)*SC_SIZE);
+ bcopy(&newent, &sysent[ff], sizeof(struct sysent)*SC_SIZE);
+ ncp_sysent = ff; /* slot in sysent[]*/
+ printf("ncp_load: [%d-%d]\n",ff,i);
+ break;
+ }
+
+ return( err);
+}
+
+static int
+ncp_unload(void) {
+ ncp_done();
+ bcopy(&oldent, &sysent[ncp_sysent], sizeof(struct sysent) * SC_SIZE);
+ printf( "ncp_unload: unloaded\n");
+ return 0;
+}
+
+static int
+ncp_mod_handler(module_t mod, int type, void *data)
+{
+ int error;
+
+ switch (type) {
+ case MOD_LOAD:
+ error = ncp_load();
+ break;
+ case MOD_UNLOAD:
+ error = ncp_unload();
+ break;
+ default:
+ error = EINVAL;
+ }
+ return error;
+}
+ \
+static moduledata_t ncp_mod = {
+ "ncp",
+ ncp_mod_handler,
+ NULL
+};
+DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
diff --git a/sys/netncp/ncp_ncp.c b/sys/netncp/ncp_ncp.c
new file mode 100644
index 0000000..943c0ca
--- /dev/null
+++ b/sys/netncp/ncp_ncp.c
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Core of NCP protocol
+ */
+#include "opt_inet.h"
+#include "opt_ipx.h"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/signalvar.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_var.h>
+#endif
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/nwerror.h>
+
+static int ncp_do_request(struct ncp_conn *,struct ncp_rq *rqp);
+static int ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target);
+static int ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options);
+static void ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size);
+
+
+#ifdef NCP_DATA_DEBUG
+static
+void m_dumpm(struct mbuf *m) {
+ char *p;
+ int len;
+ printf("d=");
+ while(m) {
+ p=mtod(m,char *);
+ len=m->m_len;
+ printf("(%d)",len);
+ while(len--){
+ printf("%02x ",((int)*(p++)) & 0xff);
+ }
+ m=m->m_next;
+ };
+ printf("\n");
+}
+#endif /* NCP_DATA_DEBUG */
+
+int
+ncp_chkintr(struct ncp_conn *conn, struct proc *p)
+{
+ sigset_t tmpset;
+
+ if (p == NULL)
+ return 0;
+ tmpset = p->p_siglist;
+ SIGSETNAND(tmpset, p->p_sigmask);
+ SIGSETNAND(tmpset, p->p_sigignore);
+ if (SIGNOTEMPTY(p->p_siglist) && NCP_SIGMASK(tmpset))
+ return EINTR;
+ return 0;
+}
+
+/*
+ * Process initial NCP handshake (attach)
+ * NOTE: Since all functions below may change conn attributes, they
+ * should be called with LOCKED connection, also they use procp & ucred
+ */
+int
+ncp_ncp_connect(struct ncp_conn *conn) {
+ int error;
+ struct ncp_rphdr *rp;
+ DECLARE_RQ;
+
+ conn->flags &= ~(NCPFL_INVALID | NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED);
+ conn->seq = 0;
+ checkbad(ncp_rq_head(rqp,NCP_ALLOC_SLOT,0,conn->procp,conn->ucred));
+ error=ncp_do_request(conn,rqp);
+ if (!error) {
+ rp = mtod(rqp->rp, struct ncp_rphdr*);
+ conn->connid = rp->conn_low + (rp->conn_high << 8);
+ }
+ ncp_rq_done(rqp);
+ if (error) return error;
+ conn->flags |= NCPFL_ATTACHED;
+
+ error = ncp_renegotiate_connparam(conn, NCP_DEFAULT_BUFSIZE, 0);
+ if (error == NWE_SIGNATURE_LEVEL_CONFLICT) {
+ printf("Unable to negotiate requested security level\n");
+ error = EOPNOTSUPP;
+ }
+ if (error) {
+ ncp_ncp_disconnect(conn);
+ return error;
+ }
+#ifdef NCPBURST
+ ncp_burst_connect(conn);
+#endif
+bad:
+ return error;
+}
+
+int
+ncp_ncp_disconnect(struct ncp_conn *conn) {
+ int error;
+ struct ncp_rqhdr *ncprq;
+ DECLARE_RQ;
+
+ NCPSDEBUG("for connid=%d\n",conn->nc_id);
+#ifdef NCPBURST
+ ncp_burst_disconnect(conn);
+#endif
+ error=ncp_rq_head(rqp,NCP_FREE_SLOT,0,conn->procp,conn->ucred);
+ ncprq = mtod(rqp->rq,struct ncp_rqhdr*);
+ error=ncp_do_request(conn,rqp);
+ ncp_rq_done(rqp);
+ ncp_conn_invalidate(conn);
+ ncp_sock_disconnect(conn);
+ return 0;
+}
+/*
+ * Make a signature for the current packet and add it at the end of the
+ * packet.
+ */
+static void
+ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size) {
+ u_char data[64];
+
+ bzero(data, sizeof(data));
+ bcopy(conn->sign_root, data, 8);
+ setdle(data, 8, *size);
+ m_copydata(rqp->rq, sizeof(struct ncp_rqhdr)-1,
+ min((*size) - sizeof(struct ncp_rqhdr)+1, 52),data+12);
+ ncp_sign(conn->sign_state, data, conn->sign_state);
+ ncp_rq_mem(rqp, (void*)conn->sign_state, 8);
+ (*size) += 8;
+}
+
+/*
+ * Low level send rpc, here we do not attempt to restore any connection,
+ * Connection expected to be locked
+ */
+static int
+ncp_do_request(struct ncp_conn *conn, struct ncp_rq *rqp) {
+ int error=EIO,len, dosend, plen = 0, gotpacket, s;
+ struct socket *so;
+ struct proc *p = conn->procp;
+ struct ncp_rqhdr *rq;
+ struct ncp_rphdr *rp=NULL;
+ struct timeval tv;
+ struct mbuf *m, *mreply = NULL;
+
+ conn->nc_rq = rqp;
+ if (p == NULL)
+ p = curproc; /* XXX maybe procpage ? */
+ if (!ncp_conn_valid(conn)) {
+ printf("%s: conn not valid\n",__FUNCTION__);
+ return (error);
+ }
+ so = conn->ncp_so;
+ if (!so) {
+ printf("%s: ncp_so is NULL !\n",__FUNCTION__);
+ ncp_conn_invalidate(conn); /* wow ! how we do that ? */
+ return EBADF;
+ }
+ /*
+ * Flush out replies on previous reqs
+ */
+ s = splnet();
+ while (1/*so->so_rcv.sb_cc*/) {
+ if (ncp_poll(so,POLLIN) == 0) break;
+ if (ncp_sock_recv(so,&m,&len) != 0) break;
+ m_freem(m);
+ }
+ rq = mtod(rqp->rq,struct ncp_rqhdr *);
+ rq->seq = conn->seq;
+ m = rqp->rq;
+ len = 0;
+ while (m) {
+ len += m->m_len;
+ m = m->m_next;
+ }
+ rqp->rq->m_pkthdr.len = len;
+ switch(rq->fn) {
+ case 0x15: case 0x16: case 0x17: case 0x23:
+ m = rqp->rq;
+ *((u_int16_t*)(mtod(m,u_int8_t*)+sizeof(*rq))) = htons(len-2-sizeof(*rq));
+ break;
+ }
+ if (conn->flags & NCPFL_SIGNACTIVE) {
+ ncp_sign_packet(conn, rqp, &len);
+ rqp->rq->m_pkthdr.len = len;
+ }
+ rq->conn_low = conn->connid & 0xff;
+ /* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/
+ /* XXX: this is temporary fix till I find a better solution */
+ rq->task = rq->conn_low;
+ rq->conn_high = conn->connid >> 8;
+ rqp->rexmit = conn->li.retry_count;
+ for(dosend = 1;;) {
+ if (rqp->rexmit-- == 0) {
+ error = ETIMEDOUT;
+ break;
+ }
+ error = 0;
+ if (dosend) {
+ NCPSDEBUG("send:%04x f=%02x c=%d l=%d s=%d t=%d\n",rq->type, rq->fn, (rq->conn_high << 8) + rq->conn_low,
+ rqp->rq->m_pkthdr.len, rq->seq, rq->task
+ );
+ error = ncp_sock_send(so, rqp->rq, rqp);
+ if (error) break;
+ }
+ tv.tv_sec = conn->li.timeout;
+ tv.tv_usec = 0;
+ error = ncp_sock_rselect(so, p, &tv, POLLIN);
+ if (error == EWOULDBLOCK ) /* timeout expired */
+ continue;
+ error = ncp_chkintr(conn, p);
+ if (error == EINTR) /* we dont restart */
+ break;
+ if (error) break;
+ /*
+ * At this point it is possible to get more than one
+ * reply from server. In general, last reply should be for
+ * current request, but not always. So, we loop through
+ * all replies to find the right answer and flush others.
+ */
+ gotpacket = 0; /* nothing good found */
+ dosend = 1; /* resend rq if error */
+ for (;;) {
+ error = 0;
+ if (ncp_poll(so,POLLIN) == 0) break;
+/* if (so->so_rcv.sb_cc == 0) {
+ break;
+ }*/
+ error = ncp_sock_recv(so,&m,&len);
+ if (error) break; /* must be more checks !!! */
+ if (m->m_len < sizeof(*rp)) {
+ m = m_pullup(m, sizeof(*rp));
+ if (m == NULL) {
+ printf("%s: reply too short\n",__FUNCTION__);
+ continue;
+ }
+ }
+ rp = mtod(m, struct ncp_rphdr*);
+ if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) {
+ NCPSDEBUG("got positive acknowledge\n");
+ m_freem(m);
+ rqp->rexmit = conn->li.retry_count;
+ dosend = 0; /* server just busy and will reply ASAP */
+ continue;
+ }
+ NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type,
+ (rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task,
+ rp->completion_code, rp->connection_state);
+ NCPDDEBUG(m);
+ if ( (rp->type == NCP_REPLY) &&
+ ((rq->type == NCP_ALLOC_SLOT) ||
+ ((rp->conn_low == rq->conn_low) &&
+ (rp->conn_high == rq->conn_high)
+ ))) {
+ if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) {
+ dosend = 1;
+ }
+ if (rp->seq == rq->seq) {
+ if (gotpacket) {
+ m_freem(m);
+ } else {
+ gotpacket = 1;
+ mreply = m;
+ plen = len;
+ }
+ continue; /* look up other for other packets */
+ }
+ }
+ m_freem(m);
+ NCPSDEBUG("reply mismatch\n");
+ } /* for receive */
+ if (error) break;
+ if (gotpacket) break;
+ /* try to resend, or just wait */
+ }
+ splx(s);
+ conn->seq++;
+ if (error) {
+ NCPSDEBUG("error=%d\n",error);
+ if (error != EINTR) /* if not just interrupt */
+ ncp_conn_invalidate(conn); /* only reconnect to restore */
+ return(error);
+ }
+ if (conn->flags & NCPFL_SIGNACTIVE) {
+ /* XXX: check reply signature */
+ m_adj(mreply, -8);
+ plen -= 8;
+ }
+ len = plen;
+ m = mreply;
+ rp = mtod(m, struct ncp_rphdr*);
+ len -= sizeof(*rp);
+ rqp->rpsize = len;
+ rqp->cc = error = rp->completion_code;
+ if (error) error |= 0x8900; /* server error */
+ rqp->cs = rp->connection_state;
+ if (rqp->cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) {
+ NCPSDEBUG("server drop us\n");
+ ncp_conn_invalidate(conn);
+ error = ECONNRESET;
+ }
+ rqp->rp = m;
+ rqp->mrp = m;
+ rqp->bpos = mtod(m, caddr_t) + sizeof(*rp);
+ return error;
+}
+
+/*
+ * Here we will try to restore any loggedin & dropped connection,
+ * connection should be locked on entry
+ */
+int ncp_restore_login(struct ncp_conn *conn);
+int
+ncp_restore_login(struct ncp_conn *conn) {
+ int error, oldflags;
+
+ if (conn->flags & NCPFL_RESTORING) {
+ printf("Hey, ncp_restore_login called twise !!!\n");
+ return 0;
+ }
+ oldflags = conn->flags;
+ printf("Restoring connection, flags = %d\n",oldflags);
+ if ((oldflags & NCPFL_LOGGED) == 0) {
+ return ECONNRESET; /* no need to restore empty conn */
+ }
+ conn->flags &= ~(NCPFL_LOGGED | NCPFL_ATTACHED);
+ conn->flags |= NCPFL_RESTORING;
+ do { /* not a loop */
+ error = ncp_reconnect(conn);
+ if (error) break;
+ if (conn->li.user)
+ error = ncp_login_object(conn, conn->li.user, conn->li.objtype, conn->li.password,conn->procp,conn->ucred);
+ if (error) break;
+ conn->flags |= NCPFL_LOGGED;
+ } while(0);
+ if (error) {
+ conn->flags = oldflags | NCPFL_INVALID;
+ }
+ conn->flags &= ~NCPFL_RESTORING;
+ return error;
+}
+
+int
+ncp_request(struct ncp_conn *conn, struct ncp_rq *rqp) {
+ int error, rcnt;
+/* struct ncp_rqhdr *rq = mtod(rqp->rq,struct ncp_rqhdr*);*/
+
+ error = ncp_conn_lock(conn,rqp->p,rqp->cred,NCPM_EXECUTE);
+ if (error) return error;
+ rcnt = NCP_RESTORE_COUNT;
+ for(;;) {
+ if (!ncp_conn_valid(conn)) {
+ if (rcnt==0) {
+ error = ECONNRESET;
+ break;
+ }
+ rcnt--;
+ error = ncp_restore_login(conn);
+ if (error)
+ continue;
+ }
+ error=ncp_do_request(conn, rqp);
+ if (ncp_conn_valid(conn)) /* not just error ! */
+ break;
+ }
+ ncp_conn_unlock(conn,rqp->p);
+ return error;
+}
+
+/*
+ * All negotiation functions expect a locked connection
+ */
+static int
+ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) {
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(0x21,conn->procp,conn->ucred);
+ ncp_rq_word_hl(rqp, size);
+ checkbad(ncp_request(conn,rqp));
+ *target = min(ncp_rp_word_hl(rqp), size);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+static int
+ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options,
+ int *ret_size, int *ret_options) {
+ int error;
+ int rs;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(0x61,conn->procp,conn->ucred);
+ ncp_rq_word_hl(rqp, size);
+ ncp_rq_byte(rqp, options);
+ checkbad(ncp_request(conn, rqp));
+ rs = ncp_rp_word_hl(rqp);
+ *ret_size = (rs == 0) ? size : min(rs, size);
+ ncp_rp_word_hl(rqp); /* skip echo socket */
+ *ret_options = ncp_rp_byte(rqp);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+static int
+ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options)
+{
+ int neg_buffsize, error, options, sl;
+
+ sl = conn->li.sig_level;
+ if (sl >= 2)
+ in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
+#ifdef IPX
+ if (ipxcksum == 2)
+ in_options |= NCP_IPX_CHECKSUM;
+#endif
+ error = ncp_negotiate_size_and_options(conn, buffsize, in_options,
+ &neg_buffsize, &options);
+ if (!error) {
+#ifdef IPX
+ if ((options ^ in_options) & NCP_IPX_CHECKSUM) {
+ if (ipxcksum == 2) {
+ printf("Server refuses to support IPX checksums\n");
+ return NWE_REQUESTER_FAILURE;
+ }
+ in_options |= NCP_IPX_CHECKSUM;
+ error = 1;
+ }
+#endif /* IPX */
+ if ((options ^ in_options) & 2) {
+ if (sl == 0 || sl == 3)
+ return NWE_SIGNATURE_LEVEL_CONFLICT;
+ if (sl == 1) {
+ in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
+ error = 1;
+ }
+ }
+ if (error) {
+ error = ncp_negotiate_size_and_options(conn,
+ buffsize, in_options, &neg_buffsize, &options);
+ if ((options ^ in_options) & 3) {
+ return NWE_SIGNATURE_LEVEL_CONFLICT;
+ }
+ }
+ } else {
+ in_options &= ~NCP_SECURITY_LEVEL_SIGN_HEADERS;
+ error = ncp_negotiate_buffersize(conn, NCP_DEFAULT_BUFSIZE,
+ &neg_buffsize);
+ }
+ if (error) return error;
+ if ((neg_buffsize < 512) || (neg_buffsize > NCP_MAX_BUFSIZE))
+ return EINVAL;
+ conn->buffer_size = neg_buffsize;
+ if (in_options & NCP_SECURITY_LEVEL_SIGN_HEADERS)
+ conn->flags |= NCPFL_SIGNWANTED;
+#ifdef IPX
+ ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM);
+#endif
+ return 0;
+}
+
+int
+ncp_reconnect(struct ncp_conn *conn) {
+ int error;
+
+ /* close any open sockets */
+ ncp_sock_disconnect(conn);
+ switch( conn->li.saddr.sa_family ) {
+#ifdef IPX
+ case AF_IPX:
+ error = ncp_sock_connect_ipx(conn);
+ break;
+#endif
+#ifdef INET
+ case AF_INET:
+ error = ncp_sock_connect_in(conn);
+ break;
+#endif
+ default:
+ return EPROTONOSUPPORT;
+ }
+ if (!error)
+ error = ncp_ncp_connect(conn);
+ return error;
+}
+
+/*
+ * Create conn structure and try to do low level connect
+ * Server addr should be filled in.
+ */
+int
+ncp_connect(struct ncp_conn_args *li, struct proc *p, struct ucred *cred,
+ struct ncp_conn **aconn)
+{
+ struct ncp_conn *conn;
+ struct ucred *owner;
+ int error, isroot;
+
+ if (li->saddr.sa_family != AF_INET && li->saddr.sa_family != AF_IPX)
+ return EPROTONOSUPPORT;
+ isroot = ncp_suser(cred) == 0;
+ /*
+ * Only root can change ownership
+ */
+ if (li->owner != NCP_DEFAULT_OWNER && !isroot)
+ return EPERM;
+ if (li->group != NCP_DEFAULT_GROUP &&
+ !groupmember(li->group, cred) && !isroot)
+ return EPERM;
+ if (li->owner != NCP_DEFAULT_OWNER) {
+ owner = crget();
+ owner->cr_uid = li->owner;
+ } else {
+ owner = cred;
+ crhold(owner);
+ }
+ error = ncp_conn_alloc(p, owner, &conn);
+ if (error)
+ return (error);
+ if (error) {
+ ncp_conn_free(conn);
+ return error;
+ }
+ conn->li = *li;
+ conn->nc_group = (li->group != NCP_DEFAULT_GROUP) ?
+ li->group : cred->cr_groups[0];
+
+ if (li->retry_count == 0)
+ conn->li.retry_count = NCP_RETRY_COUNT;
+ if (li->timeout == 0)
+ conn->li.timeout = NCP_RETRY_TIMEOUT;
+ error = ncp_reconnect(conn);
+ if (error) {
+ ncp_disconnect(conn);
+ } else {
+ *aconn=conn;
+ }
+ return error;
+}
+/*
+ * Break connection and deallocate memory
+ */
+int
+ncp_disconnect(struct ncp_conn *conn) {
+
+ if (ncp_conn_access(conn,conn->ucred,NCPM_WRITE))
+ return EACCES;
+ if (conn->ref_cnt != 0) return EBUSY;
+ if (conn->flags & NCPFL_PERMANENT) return EBUSY;
+ if (ncp_conn_valid(conn)) {
+ ncp_ncp_disconnect(conn);
+ }
+ ncp_sock_disconnect(conn);
+ ncp_conn_free(conn);
+ return 0;
+}
+
+void
+ncp_check_rq(struct ncp_conn *conn){
+ return;
+ if (conn->flags & NCPFL_INTR) return;
+ /* first, check for signals */
+ if (ncp_chkintr(conn,conn->procp)) {
+ conn->flags |= NCPFL_INTR;
+ }
+ return;
+}
diff --git a/sys/netncp/ncp_ncp.h b/sys/netncp/ncp_ncp.h
new file mode 100644
index 0000000..1d5b479
--- /dev/null
+++ b/sys/netncp/ncp_ncp.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_NCP_H_
+#define _NCP_NCP_H_
+
+#define NCP_ALLOC_SLOT 0x1111
+#define NCP_REQUEST 0x2222
+#define NCP_REPLY 0x3333
+#define NCP_FREE_SLOT 0x5555
+#define NCP_PACKET_BURST 0x7777
+#define NCP_POSITIVE_ACK 0x9999
+
+/*
+ * Bits for connection state field in ncp_rphdr
+ */
+#define NCP_CS_BAD_CONN 0x01 /* no such connection */
+#define NCP_CS_NO_SLOTS 0x04 /* no connection slots available */
+#define NCP_CS_SERVER_DOWN 0x10 /* server in down state */
+#define NCP_CS_HAVE_BROADCAST 0x40 /* server holds broadcast for us */
+
+#define NCP_RETRY_COUNT 5
+#define NCP_RETRY_TIMEOUT 10
+#define NCP_RESTORE_COUNT 2 /* how many times try to restore per
+ * single request, should be an _even_ */
+
+struct ncp_rqhdr {
+ u_int16_t type;
+ u_int8_t seq;
+ u_int8_t conn_low;
+ u_int8_t task;
+ u_int8_t conn_high;
+ u_int8_t fn;
+ u_int8_t data[0];
+} __attribute__((packed));
+
+
+struct ncp_rphdr {
+ u_int16_t type;
+ u_int8_t seq;
+ u_int8_t conn_low;
+ u_int8_t task;
+ u_int8_t conn_high;
+ u_int8_t completion_code;
+ u_int8_t connection_state;
+ u_int8_t data[0];
+}__attribute__((packed));
+
+#define BFL_ABT 0x04
+#define BFL_EOB 0x10
+#define BFL_SYS 0x80
+
+#define BOP_READ 1L
+#define BOP_WRITE 2L
+
+#define BERR_NONE 0
+#define BERR_INIT 1
+#define BERR_IO 2
+#define BERR_NODATA 3
+#define BERR_WRITE 4
+
+struct ncp_bursthdr {
+ u_short bh_type;
+ u_char bh_flags;
+ u_char bh_streamtype;
+ u_long bh_srcid;
+ u_long bh_dstid;
+ u_long bh_seq; /* HL */
+ u_long bh_send_delay; /* HL */
+ u_short bh_bseq; /* HL */
+ u_short bh_aseq; /* HL */
+ u_long bh_blen; /* HL */
+ u_long bh_dofs; /* HL */
+ u_short bh_dlen; /* HL */
+ u_short bh_misfrags; /* HL */
+} __attribute__((packed));
+
+
+int ncp_request(struct ncp_conn *conn,struct ncp_rq *rqp);
+int ncp_ncp_connect(struct ncp_conn *conn);
+int ncp_ncp_disconnect(struct ncp_conn *conn);
+int ncp_reconnect(struct ncp_conn *conn);
+int ncp_connect(struct ncp_conn_args *li,struct proc *p, struct ucred *cred,struct ncp_conn **aconn);
+int ncp_disconnect(struct ncp_conn *conn);
+int ncp_login(struct ncp_conn *conn, char *user, int objtype, char *password,
+ struct proc *p, struct ucred *cred);
+
+#endif /* _NCP_NCP_H_ */
diff --git a/sys/netncp/ncp_nls.c b/sys/netncp/ncp_nls.c
new file mode 100644
index 0000000..5606030
--- /dev/null
+++ b/sys/netncp/ncp_nls.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Character conversion routines
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/time.h>
+#include <sys/lock.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_nls.h>
+
+/*
+ * 0 - character disallowed in NetWare file name.
+ */
+static u_char ncp_u2n[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x00, 0x00, 0x00, 0x2d, 0x2e, 0x00,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x5e, 0x5f,
+ 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x00, 0x7d, 0x7e, 0x00,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xbf, 0xbf, 0xbf, 0xbf, 0xb1, 0xb2, 0xb7, /* 0xb0 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static u_char ncp_n2u[256] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xbf, 0xbf, 0xbf, 0xbf, 0xb1, 0xb2, 0xb7, /* 0xb0 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static u_char ncp_u2l[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50 */
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static u_char ncp_l2u[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 60-67 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 70-77 */
+ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+struct ncp_nlstables ncp_defnls = {
+ ncp_u2l, ncp_l2u, ncp_n2u, ncp_u2n, 0
+};
+
+void ncp_str_upper(char *name) {
+ while (*name) {
+ *name = ncp_defnls.toupper[(u_char)*name];
+ name++;
+ }
+}
+
+void ncp_str_lower(char *name) {
+ while (*name) {
+ *name = ncp_defnls.tolower[(u_char)*name];
+ name++;
+ }
+}
+
+/*
+ * Check if pathname is valid under given conditions.
+ */
+int
+ncp_pathcheck(char *s, int len, struct ncp_nlstables *nt, int strict) {
+ u_char *tbl = NULL, sc;
+ int opt = nt->opt;
+
+ if (opt & (NWHP_UPPER | NWHP_LOWER))
+ tbl = (opt & NWHP_UPPER) ? nt->toupper : nt->tolower;
+ if ((opt & NWHP_DOS) == 0) {
+ while (len--) {
+ sc = (u_char)*(s++);
+ if (nt->u2n[sc] == 0) /* illegal char */
+ return EINVAL;
+ if (tbl && strict && tbl[sc] != sc)
+ return EINVAL;
+ }
+ return 0;
+ }
+ while (len--) {
+ sc = (u_char)*(s++);
+ if (nt->u2n[sc] == 0) /* illegal char */
+ return EINVAL;
+ if (sc == ' ') return EINVAL;
+ if (tbl && strict && tbl[sc] != sc) {
+ return EINVAL;
+ }
+ }
+ return 0;
+}
+/*
+ * Convert name from Unix to NetWare representation.
+ * XXX: it should be complementary with path2unix, but for now
+ * leave it as is.
+ */
+void
+ncp_pathcopy(char *src, char *dst, int len, struct ncp_nlstables *nt) {
+ int donls;
+ u_char c;
+/* char *d = dst, *s = src;*/
+
+ donls = (nt && (nt->opt & NWHP_NLS));
+ if ((nt->opt & (NWHP_UPPER | NWHP_LOWER)) == 0) {
+ while (len--) {
+ *dst = donls ? nt->u2n[(u_char)*src] : *src;
+ dst++;
+ src++;
+ }
+ } else if (nt->opt & NWHP_DOS) {
+ while (len--) {
+ c = nt->toupper[(u_char)*src];
+ *dst = donls ? nt->u2n[c] : c;
+ dst++;
+ src++;
+ }
+ return;
+ } else { /* probably incorrect... */
+ while (len--) {
+ *dst = donls ? nt->u2n[(u_char)*src] : *src;
+ dst++;
+ src++;
+ }
+ }
+/* printf("fromux: %s:%s\n", s, d);*/
+}
+
+/*
+ * Convert NetWare filename to Unix with optional conversions
+ */
+void
+ncp_path2unix(char *src, char *dst, int len, struct ncp_nlstables *nt) {
+ int donls;
+ u_char c, *tbl;
+/* char *d = dst, *s = src;*/
+
+/* printf("toux(%02x): %s:",nt->opt, s);*/
+ donls = (nt && (nt->opt & NWHP_NLS));
+ if ((nt->opt & (NWHP_UPPER | NWHP_LOWER)) == 0) {
+ while (len--) {
+ c = *src;
+ *dst = donls ? nt->n2u[c] : c;
+ dst++;
+ src++;
+ }
+ return;
+ }
+ tbl = (nt->opt & NWHP_LOWER) ? nt->tolower : nt->toupper;
+ while (len--) {
+ c = *src;
+ *dst = tbl[donls ? nt->n2u[c] : c];
+ dst++;
+ src++;
+ }
+/* printf("%s\n", d);*/
+}
diff --git a/sys/netncp/ncp_nls.h b/sys/netncp/ncp_nls.h
new file mode 100644
index 0000000..1bec4a7
--- /dev/null
+++ b/sys/netncp/ncp_nls.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_NCP_NLS_H_
+#define _NCP_NCP_NLS_H_
+
+/* options for handle path & caseopt in mount struct */
+#define NWHP_HDB 0x01 /* have dir base */
+#define NWHP_UPPER 0x02 /* local names has upper case */
+#define NWHP_LOWER 0x04 /* --"-- lower case */
+#define NWHP_DOS 0x08 /* using dos name space */
+#define NWHP_NLS 0x10 /* do name translation via tables, any nmspc */
+#define NWHP_NOSTRICT 0x20 /* pretend to be a case insensitive */
+
+struct ncp_nlstables {
+ u_char *tolower; /* local charset to lower case */
+ u_char *toupper; /* local charset to upper case */
+ u_char *n2u; /* NetWare to Unix */
+ u_char *u2n;
+ int opt; /* may depend on context */
+};
+
+#ifndef KERNEL
+/*
+ * NLS, supported character conversion schemes.
+ * NCP_NLS_UNIXCHARSET_NETWARECHARSET
+ */
+#define NCP_NLS_AS_IS 1
+#define NCP_NLS_AS_IS_NAME "asis"
+#define NCP_NLS_KOI_866 2
+#define NCP_NLS_KOI_866_NAME "koi2cp866"
+
+extern struct ncp_nlstables ncp_nls; /* active nls */
+
+int ncp_nls_setrecode(int scheme);
+int ncp_nls_setrecodebyname(char *name);
+int ncp_nls_setlocale(char *name);
+char* ncp_nls_str_n2u(char *dst, const char *src);
+char* ncp_nls_str_u2n(char *dst, const char *src);
+char* ncp_nls_mem_n2u(char *dst, const char *src, int size);
+char* ncp_nls_mem_u2n(char *dst, const char *src, int size);
+
+#else /* !KERNEL */
+
+
+extern struct ncp_nlstables ncp_defnls;
+
+void ncp_str_upper(char *name);
+void ncp_str_lower(char *name);
+void ncp_pathcopy(char *src, char *dst, int len, struct ncp_nlstables *nt);
+int ncp_pathcheck(char *s, int len, struct ncp_nlstables *nt, int strict);
+void ncp_path2unix(char *src, char *dst, int len, struct ncp_nlstables *nt);
+
+#endif /* !KERNEL */
+
+#endif /* _NCP_NCP_NLS_H_ */ \ No newline at end of file
diff --git a/sys/netncp/ncp_rq.c b/sys/netncp/ncp_rq.c
new file mode 100644
index 0000000..8cef7d2
--- /dev/null
+++ b/sys/netncp/ncp_rq.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Routines to prepare request and fetch reply
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+#include <sys/uio.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_nls.h>
+
+static struct mbuf* m_getm(struct mbuf *top, int len);
+
+int
+ncp_rq_head(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,struct proc *p,
+ struct ucred *cred)
+{
+ struct mbuf *m;
+ struct ncp_rqhdr *rq;
+ struct ncp_bursthdr *brq;
+ caddr_t pstart;
+
+ bzero(rqp, sizeof(*rqp));
+ rqp->p = p;
+ rqp->cred = cred;
+ m = m_gethdr(M_WAIT, MT_DATA);
+ if (m == NULL)
+ return ENOBUFS; /* if M_WAIT ? */
+ m->m_pkthdr.rcvif = NULL;
+ rqp->rq = rqp->mrq = m;
+ rqp->rp = NULL;
+ switch(ptype) {
+ case NCP_PACKET_BURST:
+ MH_ALIGN(m, sizeof(*brq) + 24);
+ m->m_len = sizeof(*brq);
+ brq = mtod(m, struct ncp_bursthdr *);
+ brq->bh_type = ptype;
+ brq->bh_streamtype = 0x2;
+ pstart = (caddr_t)brq;
+ break;
+ default:
+ MH_ALIGN(m, sizeof(*rq) + 2); /* possible len field in some functions */
+ m->m_len = sizeof(*rq);
+ rq = mtod(m, struct ncp_rqhdr *);
+ rq->type = ptype;
+ rq->seq = 0; /* filled later */
+ rq->fn = fn;
+ pstart = (caddr_t)rq;
+ break;
+ }
+ rqp->bpos = pstart + m->m_len;
+ return 0;
+}
+
+int
+ncp_rq_done(struct ncp_rq *rqp) {
+ m_freem(rqp->rq);
+ rqp->rq=NULL;
+ if (rqp->rp) m_freem(rqp->rp);
+ rqp->rp=NULL;
+ return (0);
+}
+
+static struct mbuf*
+m_getm(struct mbuf *top, int len) {
+ int rest = len, mlen;
+ struct mbuf *m=0,*mp;
+
+ mp = top;
+ while (rest > 0) {
+/* NCPSDEBUG("%d\n",rest);*/
+ m = m_get(M_WAIT, MT_DATA);
+ if (rest > MINCLSIZE) {
+ MCLGET(m,M_WAIT);
+ mlen = ( (m->m_flags & M_EXT) == 0) ? MLEN : MCLBYTES;
+ } else {
+ mlen = MLEN;
+ }
+ m->m_len = 0/*min(mlen,rest)*/;
+ mp->m_next = m;
+ mp = m;
+ rest -= mlen;
+ }
+ return top;
+}
+
+/*
+ * Routines to fill the request
+ */
+static caddr_t ncp_mchecksize(struct ncp_rq *rqp, int size);
+#define NCP_RQADD(t) ((t*)(ncp_mchecksize(rqp,sizeof(t))))
+
+caddr_t
+ncp_mchecksize(struct ncp_rq *rqp, int size) {
+ caddr_t bpos1;
+
+ if (size>MLEN)
+ panic("ncp_mchecksize\n");
+ if (M_TRAILINGSPACE(rqp->mrq)<(size)) {
+ struct mbuf *m;
+ m = m_get(M_WAIT, MT_DATA);
+ m->m_len = 0;
+ rqp->bpos = mtod(m, caddr_t);
+ rqp->mrq->m_next = m;
+ rqp->mrq = m;
+ }
+ rqp->mrq->m_len += size;
+ bpos1 = rqp->bpos;
+ rqp->bpos += size;
+ return bpos1;
+}
+
+void
+ncp_rq_byte(struct ncp_rq *rqp,u_int8_t x) {
+ *NCP_RQADD(u_int8_t)=x;
+}
+
+void
+ncp_rq_word_hl(struct ncp_rq *rqp, u_int16_t x) {
+ setwbe(NCP_RQADD(u_int16_t), 0, x);
+}
+
+void
+ncp_rq_word_lh(struct ncp_rq *rqp, u_int16_t x) {
+ setwle(NCP_RQADD(u_int16_t), 0, x);
+}
+
+void
+ncp_rq_dword_lh(struct ncp_rq *rqp, u_int32_t x) {
+ setdle(NCP_RQADD(u_int32_t), 0, x);
+}
+
+void
+ncp_rq_pathstring(struct ncp_rq *rqp, int size, char *name, struct ncp_nlstables *nt) {
+ struct mbuf *m;
+ int cplen;
+
+ ncp_rq_byte(rqp, size);
+ m = rqp->mrq;
+ cplen = min(size, M_TRAILINGSPACE(m));
+ if (cplen) {
+ ncp_pathcopy(name, rqp->bpos, cplen, nt);
+ size -= cplen;
+ name += cplen;
+ m->m_len += cplen;
+ }
+ if (size) {
+ m_getm(m, size);
+ while (size > 0){
+ m = m->m_next;
+ cplen = min(size, M_TRAILINGSPACE(m));
+ ncp_pathcopy(name, mtod(m, caddr_t) + m->m_len, cplen, nt);
+ size -= cplen;
+ name += cplen;
+ m->m_len += cplen;
+ }
+ }
+ rqp->bpos = mtod(m,caddr_t) + m->m_len;
+ rqp->mrq = m;
+ return;
+}
+
+int
+ncp_rq_putanymem(struct ncp_rq *rqp, caddr_t source, int size, int type) {
+ struct mbuf *m;
+ int cplen, error;
+
+ m = rqp->mrq;
+ cplen = min(size, M_TRAILINGSPACE(m));
+ if (cplen) {
+ if (type==1) {
+ error = copyin(source, rqp->bpos, cplen);
+ if (error) return error;
+ } else
+ bcopy(source, rqp->bpos, cplen);
+ size -= cplen;
+ source += cplen;
+ m->m_len += cplen;
+ }
+ if (size) {
+ m_getm(m, size);
+ while (size > 0){
+ m = m->m_next;
+ cplen = min(size, M_TRAILINGSPACE(m));
+ if (type==1) {
+ error = copyin(source, mtod(m, caddr_t) + m->m_len, cplen);
+ if (error) return error;
+ } else
+ bcopy(source, mtod(m, caddr_t) + m->m_len, cplen);
+ size -= cplen;
+ source += cplen;
+ m->m_len += cplen;
+ }
+ }
+ rqp->bpos = mtod(m,caddr_t) + m->m_len;
+ rqp->mrq = m;
+ return 0;
+}
+
+int
+ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size) {
+
+ rqp->mrq->m_next = m;
+ m->m_next = NULL;
+ if (size != M_COPYALL) m->m_len = size;
+ rqp->bpos = mtod(m,caddr_t) + m->m_len;
+ rqp->mrq = m;
+ return 0;
+}
+
+void
+ncp_rq_pstring(struct ncp_rq *rqp, char *s) {
+ int len = strlen(s);
+ if (len > 255) {
+ nwfs_printf("string too long: %s\n", s);
+ len = 255;
+ }
+ ncp_rq_byte(rqp, len);
+ ncp_rq_mem(rqp, s, len);
+ return;
+}
+
+void
+ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base,
+ int namelen, u_char *path, struct ncp_nlstables *nt)
+{
+ int complen;
+
+ ncp_rq_byte(rqp, vol_num);
+ ncp_rq_dword(rqp, dir_base);
+ ncp_rq_byte(rqp, 1); /* with dirbase */
+ if (path != NULL && path[0]) {
+ if (namelen < 0) {
+ namelen = *path++;
+ ncp_rq_byte(rqp, namelen);
+ for(; namelen; namelen--) {
+ complen = *path++;
+ ncp_rq_byte(rqp, complen);
+ ncp_rq_mem(rqp, path, complen);
+ path += complen;
+ }
+ } else {
+ ncp_rq_byte(rqp, 1); /* 1 component */
+ ncp_rq_pathstring(rqp, namelen, path, nt);
+ }
+ } else {
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_byte(rqp, 0);
+ }
+}
+/*
+ * fetch reply routines
+ */
+#define ncp_mspaceleft (mtod(rqp->mrp,caddr_t)+rqp->mrp->m_len-rqp->bpos)
+
+u_int8_t
+ncp_rp_byte(struct ncp_rq *rqp) {
+ if (rqp->mrp == NULL) return 0;
+ if (ncp_mspaceleft < 1) {
+ rqp->mrp = rqp->mrp->m_next;
+ if (rqp->mrp == NULL) return 0;
+ rqp->bpos = mtod(rqp->mrp, caddr_t);
+ }
+ rqp->bpos += 1;
+ return rqp->bpos[-1];
+}
+
+u_int16_t
+ncp_rp_word_lh(struct ncp_rq *rqp) {
+ caddr_t prev = rqp->bpos;
+ u_int16_t t;
+
+ if (rqp->mrp == NULL) return 0;
+ if (ncp_mspaceleft >= 2) {
+ rqp->bpos += 2;
+ return getwle(prev,0);
+ }
+ t = *((u_int8_t*)(rqp->bpos));
+ rqp->mrp = rqp->mrp->m_next;
+ if (rqp->mrp == NULL) return 0;
+ ((u_int8_t *)&t)[1] = *((u_int8_t*)(rqp->bpos = mtod(rqp->mrp, caddr_t)));
+ rqp->bpos += 2;
+ return t;
+}
+
+u_int16_t
+ncp_rp_word_hl(struct ncp_rq *rqp) {
+ return (ntohs(ncp_rp_word_lh(rqp)));
+}
+
+u_int32_t
+ncp_rp_dword_hl(struct ncp_rq *rqp) {
+ int togo, rest;
+ caddr_t prev = rqp->bpos;
+ u_int32_t t;
+
+ if (rqp->mrp == NULL) return 0;
+ rest = ncp_mspaceleft;
+ if (rest >= 4) {
+ rqp->bpos += 4;
+ return getdbe(prev,0);
+ }
+ togo = 0;
+ while (rest--) {
+ ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
+ }
+ rqp->mrp = rqp->mrp->m_next;
+ if (rqp->mrp == NULL) return 0;
+ prev = mtod(rqp->mrp, caddr_t);
+ rqp->bpos = prev + 4 - togo; /* XXX possible low than togo bytes in next mbuf */
+ while (togo < 4) {
+ ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
+ }
+ return getdbe(&t,0);
+}
+
+u_int32_t
+ncp_rp_dword_lh(struct ncp_rq *rqp) {
+ int rest, togo;
+ caddr_t prev = rqp->bpos;
+ u_int32_t t;
+
+ if (rqp->mrp == NULL) return 0;
+ rest = ncp_mspaceleft;
+ if (rest >= 4) {
+ rqp->bpos += 4;
+ return getdle(prev,0);
+ }
+ togo = 0;
+ while (rest--) {
+ ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
+ }
+ rqp->mrp = rqp->mrp->m_next;
+ if (rqp->mrp == NULL) return 0;
+ prev = mtod(rqp->mrp, caddr_t);
+ rqp->bpos = prev + 4 - togo; /* XXX possible low than togo bytes in next mbuf */
+ while (togo < 4) {
+ ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
+ }
+ return getdle(&t,0);
+}
+void
+ncp_rp_mem(struct ncp_rq *rqp,caddr_t target, int size) {
+ register struct mbuf *m=rqp->mrp;
+ register unsigned count;
+
+ while (size > 0) {
+ if (m==0) { /* should be panic */
+ printf("ncp_rp_mem: incomplete copy\n");
+ return;
+ }
+ count = mtod(m,caddr_t)+m->m_len-rqp->bpos;
+ if (count == 0) {
+ m=m->m_next;
+ rqp->bpos=mtod(m,caddr_t);
+ continue;
+ }
+ count = min(count,size);
+ bcopy(rqp->bpos, target, count);
+ size -= count;
+ target += count;
+ rqp->bpos += count;
+ }
+ rqp->mrp=m;
+ return;
+}
+
+int
+ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size) {
+ register struct mbuf *m=rqp->mrp;
+ register unsigned count;
+ int error;
+
+ while (size>0) {
+ if (m==0) { /* should be panic */
+ printf("ncp_rp_mem: incomplete copy\n");
+ return EFAULT;
+ }
+ count = mtod(m,caddr_t)+m->m_len-rqp->bpos;
+ if (count == 0) {
+ m=m->m_next;
+ rqp->bpos=mtod(m,caddr_t);
+ continue;
+ }
+ count = min(count,size);
+ error=copyout(rqp->bpos, target, count);
+ if (error) return error;
+ size -= count;
+ target += count;
+ rqp->bpos += count;
+ }
+ rqp->mrp=m;
+ return 0;
+}
+
+struct mbuf*
+ncp_rp_mbuf(struct ncp_rq *rqp, int size) {
+ register struct mbuf *m=rqp->mrp, *rm;
+ register unsigned count;
+
+ rm = m_copym(m, rqp->bpos - mtod(m,caddr_t), size, M_WAIT);
+ while (size > 0) {
+ if (m == 0) {
+ printf("ncp_rp_mbuf: can't advance\n");
+ return rm;
+ }
+ count = mtod(m,caddr_t)+ m->m_len - rqp->bpos;
+ if (count == 0) {
+ m = m->m_next;
+ rqp->bpos = mtod(m, caddr_t);
+ continue;
+ }
+ count = min(count, size);
+ size -= count;
+ rqp->bpos += count;
+ }
+ rqp->mrp=m;
+ return rm;
+}
+
+int
+nwfs_mbuftouio(mrep, uiop, siz, dpos)
+ struct mbuf **mrep;
+ register struct uio *uiop;
+ int siz;
+ caddr_t *dpos;
+{
+ register char *mbufcp, *uiocp;
+ register int xfer, left, len;
+ register struct mbuf *mp;
+ long uiosiz;
+ int error = 0;
+
+ mp = *mrep;
+ if (!mp) return 0;
+ mbufcp = *dpos;
+ len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
+ while (siz > 0) {
+ if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
+ return (EFBIG);
+ left = uiop->uio_iov->iov_len;
+ uiocp = uiop->uio_iov->iov_base;
+ if (left > siz)
+ left = siz;
+ uiosiz = left;
+ while (left > 0) {
+ while (len == 0) {
+ mp = mp->m_next;
+ if (mp == NULL)
+ return (EBADRPC);
+ mbufcp = mtod(mp, caddr_t);
+ len = mp->m_len;
+ }
+ xfer = (left > len) ? len : left;
+#ifdef notdef
+ /* Not Yet.. */
+ if (uiop->uio_iov->iov_op != NULL)
+ (*(uiop->uio_iov->iov_op))
+ (mbufcp, uiocp, xfer);
+ else
+#endif
+ if (uiop->uio_segflg == UIO_SYSSPACE)
+ bcopy(mbufcp, uiocp, xfer);
+ else
+ copyout(mbufcp, uiocp, xfer);
+ left -= xfer;
+ len -= xfer;
+ mbufcp += xfer;
+ uiocp += xfer;
+ uiop->uio_offset += xfer;
+ uiop->uio_resid -= xfer;
+ }
+ if (uiop->uio_iov->iov_len <= siz) {
+ uiop->uio_iovcnt--;
+ uiop->uio_iov++;
+ } else {
+ uiop->uio_iov->iov_base += uiosiz;
+ uiop->uio_iov->iov_len -= uiosiz;
+ }
+ siz -= uiosiz;
+ }
+ *dpos = mbufcp;
+ *mrep = mp;
+ return (error);
+}
+/*
+ * copies a uio scatter/gather list to an mbuf chain.
+ * NOTE: can ony handle iovcnt == 1
+ */
+int
+nwfs_uiotombuf(uiop, mq, siz, bpos)
+ register struct uio *uiop;
+ struct mbuf **mq;
+ int siz;
+ caddr_t *bpos;
+{
+ register char *uiocp;
+ register struct mbuf *mp, *mp2;
+ register int xfer, left, mlen;
+ int uiosiz, clflg;
+
+#ifdef DIAGNOSTIC
+ if (uiop->uio_iovcnt != 1)
+ panic("nfsm_uiotombuf: iovcnt != 1");
+#endif
+
+ if (siz > MLEN) /* or should it >= MCLBYTES ?? */
+ clflg = 1;
+ else
+ clflg = 0;
+ mp = mp2 = *mq;
+ while (siz > 0) {
+ left = uiop->uio_iov->iov_len;
+ uiocp = uiop->uio_iov->iov_base;
+ if (left > siz)
+ left = siz;
+ uiosiz = left;
+ while (left > 0) {
+ mlen = M_TRAILINGSPACE(mp);
+ if (mlen == 0) {
+ MGET(mp, M_WAIT, MT_DATA);
+ if (clflg)
+ MCLGET(mp, M_WAIT);
+ mp->m_len = 0;
+ mp2->m_next = mp;
+ mp2 = mp;
+ mlen = M_TRAILINGSPACE(mp);
+ }
+ xfer = (left > mlen) ? mlen : left;
+#ifdef notdef
+ /* Not Yet.. */
+ if (uiop->uio_iov->iov_op != NULL)
+ (*(uiop->uio_iov->iov_op))
+ (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
+ else
+#endif
+ if (uiop->uio_segflg == UIO_SYSSPACE)
+ bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
+ else
+ copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
+ mp->m_len += xfer;
+ left -= xfer;
+ uiocp += xfer;
+ uiop->uio_offset += xfer;
+ uiop->uio_resid -= xfer;
+ }
+ uiop->uio_iov->iov_base += uiosiz;
+ uiop->uio_iov->iov_len -= uiosiz;
+ siz -= uiosiz;
+ }
+ *bpos = mtod(mp, caddr_t)+mp->m_len;
+ *mq = mp;
+ return (0);
+}
diff --git a/sys/netncp/ncp_rq.h b/sys/netncp/ncp_rq.h
new file mode 100644
index 0000000..259fed2
--- /dev/null
+++ b/sys/netncp/ncp_rq.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_NCP_RQ_H_
+#define _NCP_NCP_RQ_H_
+
+#include <machine/endian.h>
+
+#define getb(buf,ofs) (((const u_int8_t *)(buf))[ofs])
+#define setb(buf,ofs,val) (((u_int8_t*)(buf))[ofs])=val
+#define getbw(buf,ofs) ((u_int16_t)(getb(buf,ofs)))
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+
+#define getwle(buf,ofs) (*((u_int16_t*)(&((u_int8_t*)(buf))[ofs])))
+#define getdle(buf,ofs) (*((u_int32_t*)(&((u_int8_t*)(buf))[ofs])))
+#define getwbe(buf,ofs) (ntohs(getwle(buf,ofs)))
+#define getdbe(buf,ofs) (ntohl(getdle(buf,ofs)))
+
+#define setwle(buf,ofs,val) getwle(buf,ofs)=val
+#define setwbe(buf,ofs,val) getwle(buf,ofs)=htons(val)
+#define setdle(buf,ofs,val) getdle(buf,ofs)=val
+#define setdbe(buf,ofs,val) getdle(buf,ofs)=htonl(val)
+
+#define htoles(x) ((u_int16_t)(x))
+#define letohs(x) ((u_int16_t)(x))
+#define htolel(x) ((u_int32_t)(x))
+#define letohl(x) ((u_int32_t)(x))
+
+#else
+#error "Macros for Big-Endians are incomplete"
+#define getwle(buf,ofs) ((u_int16_t)(getb(buf, ofs) | (getb(buf, ofs + 1) << 8)))
+#define getdle(buf,ofs) ((u_int32_t)(getb(buf, ofs) | \
+ (getb(buf, ofs + 1) << 8) | \
+ (getb(buf, ofs + 2) << 16) | \
+ (getb(buf, ofs + 3) << 24)))
+#define getwbe(buf,ofs) (*((u_int16_t*)(&((u_int8_t*)(buf))[ofs])))
+#define getdbe(buf,ofs) (*((u_int32_t*)(&((u_int8_t*)(buf))[ofs])))
+/*
+#define setwle(buf,ofs,val) getwle(buf,ofs)=val
+#define setdle(buf,ofs,val) getdle(buf,ofs)=val
+*/
+#define setwbe(buf,ofs,val) getwle(buf,ofs)=val
+#define setdbe(buf,ofs,val) getdle(buf,ofs)=val
+/*
+#define htoles(x) ((u_int16_t)(x))
+#define letohs(x) ((u_int16_t)(x))
+#define htolel(x) ((u_int32_t)(x))
+#define letohl(x) ((u_int32_t)(x))
+*/
+#endif
+
+
+#ifdef KERNEL
+struct ncp_nlstables;
+/*
+ * Structure to prepare ncp request and receive reply
+ */
+struct ncp_rq {
+ struct ncp_conn *conn; /* back link */
+ struct mbuf *rq;
+ struct mbuf *mrq;
+ struct mbuf *rp;
+ struct mbuf *mrp;
+ caddr_t bpos;
+/* int rqsize;*/ /* request size without ncp header */
+ int rpsize; /* reply size minus ncp header */
+ int cc; /* completion code */
+ int cs; /* connection state */
+ struct proc *p; /* proc that did rq */
+ struct ucred *cred; /* user that did rq */
+ int rexmit;
+};
+
+#define DECLARE_RQ struct ncp_rq rq;struct ncp_rq *rqp=&rq
+
+
+int ncp_rq_head(struct ncp_rq *rqp,u_int32_t ptype, u_int8_t fn,struct proc *p,
+ struct ucred *cred);
+int ncp_rq_done(struct ncp_rq *rqp);
+
+/* common case for normal request */
+#define ncp_rq_init(rqp,fn,p,c) ncp_rq_head((rqp),NCP_REQUEST,(fn),(p),(c))
+#define ncp_rq_close(rqp) ncp_rq_done((rqp))
+
+#define NCP_RQ_HEAD(fn,p,c) ncp_rq_init(rqp,fn,p,c)
+#define NCP_RQ_HEAD_S(fn,sfn,p,c) NCP_RQ_HEAD(fn,p,c);ncp_rq_word(rqp,0);ncp_rq_byte(rqp,(sfn))
+#define NCP_RQ_EXIT bad: ncp_rq_close(rqp)
+#define NCP_RQ_EXIT_NB ncp_rq_close(rqp)
+#define ncp_rq_word ncp_rq_word_lh
+#define ncp_rq_dword ncp_rq_dword_lh
+
+/*void ncp_init_request(struct ncp_rq *rqp, int fn);
+void ncp_close_request(struct ncp_rq *rqp);*/
+void ncp_rq_byte(struct ncp_rq *rqp, u_int8_t x);
+void ncp_rq_word_hl(struct ncp_rq *rqp, u_int16_t x);
+void ncp_rq_word_lh(struct ncp_rq *rqp, u_int16_t x);
+void ncp_rq_dword_lh(struct ncp_rq *rqp, u_int32_t x);
+static void ncp_rq_mem(struct ncp_rq *rqp, caddr_t source, int size);
+static int ncp_rq_usermem(struct ncp_rq *rqp, caddr_t source, int size);
+int ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size);
+int ncp_rq_putanymem(struct ncp_rq *rqp, caddr_t source, int size,int type);
+void ncp_rq_pathstring(struct ncp_rq *rqp, int size, char *name, struct ncp_nlstables*);
+void ncp_rq_dbase_path(struct ncp_rq *, u_int8_t vol_num,
+ u_int32_t dir_base, int namelen, u_char *name, struct ncp_nlstables *nt);
+void ncp_rq_pstring(struct ncp_rq *rqp, char *s);
+
+u_int8_t ncp_rp_byte(struct ncp_rq *rqp);
+u_int16_t ncp_rp_word_hl(struct ncp_rq *rqp);
+u_int16_t ncp_rp_word_lh(struct ncp_rq *rqp);
+u_int32_t ncp_rp_dword_hl(struct ncp_rq *rqp);
+u_int32_t ncp_rp_dword_lh(struct ncp_rq *rqp);
+void ncp_rp_mem(struct ncp_rq *rqp,caddr_t target, int size);
+int ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size);
+int nwfs_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos);
+int nwfs_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos);
+struct mbuf* ncp_rp_mbuf(struct ncp_rq *rqp, int size);
+
+static void __inline ncp_rq_mem(struct ncp_rq *rqp, caddr_t source, int size) {
+ ncp_rq_putanymem(rqp,source,size,0);
+}
+static int __inline ncp_rq_usermem(struct ncp_rq *rqp, caddr_t source, int size) {
+ return ncp_rq_putanymem(rqp,source,size,1);
+}
+void ncp_sign_init(const char *logindata, char *sign_root);
+
+#else /* ifdef KERNEL */
+
+#define DECLARE_RQ struct ncp_buf conn1, *conn=&conn1
+
+#define ncp_add_byte(conn,x) (conn)->packet[(conn)->rqsize++]=x
+
+void ncp_init_request(struct ncp_buf *conn);
+void ncp_init_request_s(struct ncp_buf *conn, int subfn);
+void ncp_add_word_lh(struct ncp_buf *conn, u_int16_t x);
+void ncp_add_dword_lh(struct ncp_buf *conn, u_int32_t x);
+void ncp_add_word_hl(struct ncp_buf *conn, u_int16_t x);
+void ncp_add_dword_hl(struct ncp_buf *conn, u_int32_t x);
+void ncp_add_mem(struct ncp_buf *conn, const void *source, int size);
+void ncp_add_mem_nls(struct ncp_buf *conn, const void *source, int size);
+void ncp_add_pstring(struct ncp_buf *conn, const char *s);
+void ncp_add_handle_path(struct ncp_buf *conn, nuint32 volNumber, nuint32 dirNumber,
+ int handleFlag, const char *path);
+
+#define ncp_reply_data(conn,offset) ((conn)->packet+offset)
+#define ncp_reply_byte(conn,offset) (*(u_int8_t*)(ncp_reply_data(conn, offset)))
+
+u_int16_t ncp_reply_word_hl(struct ncp_buf *conn, int offset);
+u_int16_t ncp_reply_word_lh(struct ncp_buf *conn, int offset);
+u_int32_t ncp_reply_dword_hl(struct ncp_buf *conn, int offset);
+u_int32_t ncp_reply_dword_lh(struct ncp_buf *conn, int offset);
+
+static __inline void
+ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
+ fh->val1 = (fh->val.val32 = sfd);
+ return;
+}
+
+#endif /* ifdef KERNEL */
+
+#endif /* _NCP_NCP_RQ_H_ */
diff --git a/sys/netncp/ncp_sock.c b/sys/netncp/ncp_sock.c
new file mode 100644
index 0000000..bd3c4f0
--- /dev/null
+++ b/sys/netncp/ncp_sock.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Low level socket routines
+ */
+
+#include "opt_inet.h"
+#include "opt_ipx.h"
+
+#if !defined(INET) && !defined(IPX)
+#error "NCP requeires either INET of IPX protocol family"
+#endif
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/syslog.h>
+#include <sys/mbuf.h>
+#include <net/route.h>
+
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_pcb.h>
+#endif
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+
+#ifdef IPX
+#define ipx_setnullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0);
+#define ipx_setnullhost(x) ((x).x_host.s_host[0] = 0); \
+ ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0);
+#endif
+
+/*int ncp_poll(struct socket *so, int events);*/
+/*static int ncp_getsockname(struct socket *so, caddr_t asa, int *alen);*/
+static int ncp_soconnect(struct socket *so,struct sockaddr *target, struct proc *p);
+
+
+/* This will need only if native IP used, or (unlikely) NCP will be
+ * implemented on the socket level
+ */
+static int
+ncp_soconnect(struct socket *so,struct sockaddr *target, struct proc *p) {
+ int error,s;
+
+ error = soconnect(so, (struct sockaddr*)target, p);
+ if (error)
+ return error;
+ /*
+ * Wait for the connection to complete. Cribbed from the
+ * connect system call but with the wait timing out so
+ * that interruptible mounts don't hang here for a long time.
+ */
+ error = EIO;
+ s = splnet();
+ while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
+ (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ncpcon", 2 * hz);
+ if ((so->so_state & SS_ISCONNECTING) &&
+ so->so_error == 0 /*&& rep &&*/) {
+ so->so_state &= ~SS_ISCONNECTING;
+ splx(s);
+ goto bad;
+ }
+ }
+ if (so->so_error) {
+ error = so->so_error;
+ so->so_error = 0;
+ splx(s);
+ goto bad;
+ }
+ splx(s);
+ error=0;
+bad:
+ return error;
+}
+#ifdef notyet
+static int
+ncp_getsockname(struct socket *so, caddr_t asa, int *alen) {
+ struct sockaddr *sa;
+ int len=0, error;
+
+ sa = 0;
+ error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
+ if (error==0) {
+ if (sa) {
+ len = min(len, sa->sa_len);
+ bcopy(sa, (caddr_t)asa, (u_int)len);
+ }
+ *alen=len;
+ }
+ if (sa)
+ FREE(sa, M_SONAME);
+ return (error);
+}
+#endif
+int ncp_sock_recv(struct socket *so, struct mbuf **mp, int *rlen)
+{
+ struct uio auio;
+ struct proc *p=curproc; /* XXX */
+ int error,flags,len;
+
+ auio.uio_resid = len = 1000000;
+ auio.uio_procp = p;
+ flags = MSG_DONTWAIT;
+
+/* error = so->so_proto->pr_usrreqs->pru_soreceive(so, 0, &auio,
+ (struct mbuf **)0, (struct mbuf **)0, &flags);*/
+ error = so->so_proto->pr_usrreqs->pru_soreceive(so, 0, &auio,
+ mp, (struct mbuf **)0, &flags);
+ *rlen = len - auio.uio_resid;
+/* if (!error) {
+ *rlen=iov.iov_len;
+ } else
+ *rlen=0;*/
+#ifdef NCP_SOCKET_DEBUG
+ if (error)
+ printf("ncp_recv: err=%d\n", error);
+#endif
+ return (error);
+}
+
+int
+ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
+{
+ struct proc *p = curproc; /* XXX */
+ struct sockaddr *to = 0;
+ struct ncp_conn *conn = rqp->conn;
+ struct mbuf *m;
+ int error, flags=0;
+ int sendwait;
+
+ for(;;) {
+ m = m_copym(top, 0, M_COPYALL, M_WAIT);
+/* NCPDDEBUG(m);*/
+ error = so->so_proto->pr_usrreqs->pru_sosend(so, to, 0, m, 0, flags, p);
+ if (error == 0 || error == EINTR || error == ENETDOWN)
+ break;
+ if (rqp->rexmit == 0) break;
+ rqp->rexmit--;
+ tsleep(&sendwait, PWAIT, "ncprsn", conn->li.timeout * hz);
+ error = ncp_chkintr(conn, p);
+ if (error == EINTR) break;
+ }
+ if (error) {
+ log(LOG_INFO, "ncp_send: error %d for server %s", error, conn->li.server);
+ }
+ return error;
+}
+
+int
+ncp_poll(struct socket *so, int events){
+ struct proc *p = curproc;
+ struct ucred *cred=NULL;
+ return so->so_proto->pr_usrreqs->pru_sopoll(so, events, cred, p);
+}
+
+int
+ncp_sock_rselect(struct socket *so,struct proc *p, struct timeval *tv, int events)
+{
+ struct timeval atv,rtv,ttv;
+ int s,timo,error=0;
+
+ if (tv) {
+ atv=*tv;
+ if (itimerfix(&atv)) {
+ error = EINVAL;
+ goto done;
+ }
+ getmicrouptime(&rtv);
+ timevaladd(&atv, &rtv);
+ }
+ timo = 0;
+retry:
+ p->p_flag |= P_SELECT;
+ error = ncp_poll(so, events);
+ if (error) {
+ error = 0;
+ goto done;
+ }
+ if (tv) {
+ getmicrouptime(&rtv);
+ if (timevalcmp(&rtv, &atv, >=))
+ goto done;
+ ttv=atv;
+ timevalsub(&ttv, &rtv);
+ timo = tvtohz(&ttv);
+ }
+ s = splhigh();
+ if ((p->p_flag & P_SELECT) == 0) {
+ splx(s);
+ goto retry;
+ }
+ p->p_flag &= ~P_SELECT;
+ error = tsleep((caddr_t)&selwait, PSOCK, "ncpslt", timo);
+ splx(s);
+done:
+ p->p_flag &= ~P_SELECT;
+ if (error == ERESTART) {
+/* printf("Signal: %x", CURSIG(p));*/
+ error = 0;
+ }
+ return (error);
+}
+
+#ifdef IPX
+/*
+ * Connect to specified server via IPX
+ */
+int
+ncp_sock_connect_ipx(struct ncp_conn *conn) {
+ struct sockaddr_ipx sipx;
+ struct ipxpcb *npcb;
+ struct proc *p = conn->procp;
+ int addrlen, error, count;
+
+ sipx.sipx_port = htons(0);
+
+ for (count = 0;;count++) {
+ if (count > (IPXPORT_WELLKNOWN-IPXPORT_RESERVED)*2) {
+ error = EADDRINUSE;
+ goto bad;
+ }
+ conn->ncp_so = conn->wdg_so = NULL;
+ checkbad(socreate(AF_IPX, &conn->ncp_so, SOCK_DGRAM, 0, p));
+ if (conn->li.opt & NCP_OPT_WDOG)
+ checkbad(socreate(AF_IPX, &conn->wdg_so, SOCK_DGRAM,0,p));
+ addrlen = sizeof(sipx);
+ sipx.sipx_family = AF_IPX;
+ ipx_setnullnet(sipx.sipx_addr);
+ ipx_setnullhost(sipx.sipx_addr);
+ sipx.sipx_len = addrlen;
+ error = sobind(conn->ncp_so, (struct sockaddr *)&sipx, p);
+ if (error == 0) {
+ if ((conn->li.opt & NCP_OPT_WDOG) == 0)
+ break;
+ sipx.sipx_addr = sotoipxpcb(conn->ncp_so)->ipxp_laddr;
+ sipx.sipx_port = htons(ntohs(sipx.sipx_port) + 1);
+ ipx_setnullnet(sipx.sipx_addr);
+ ipx_setnullhost(sipx.sipx_addr);
+ error = sobind(conn->wdg_so, (struct sockaddr *)&sipx, p);
+ }
+ if (!error) break;
+ if (error != EADDRINUSE) goto bad;
+ sipx.sipx_port = htons((ntohs(sipx.sipx_port)+4) & 0xfff8);
+ soclose(conn->ncp_so);
+ if (conn->wdg_so)
+ soclose(conn->wdg_so);
+ }
+ npcb = sotoipxpcb(conn->ncp_so);
+ npcb->ipxp_dpt = IPXPROTO_NCP;
+ /* IPXrouted must be running, i.e. route must be presented */
+ conn->li.ipxaddr.sipx_len = sizeof(struct sockaddr_ipx);
+ checkbad(ncp_soconnect(conn->ncp_so, &conn->li.saddr, p));
+ if (conn->wdg_so) {
+ sotoipxpcb(conn->wdg_so)->ipxp_laddr.x_net = npcb->ipxp_laddr.x_net;
+ sotoipxpcb(conn->wdg_so)->ipxp_laddr.x_host= npcb->ipxp_laddr.x_host;
+ }
+ if (!error) {
+ conn->flags |= NCPFL_SOCONN;
+ }
+#ifdef NCPBURST
+ if (ncp_burst_enabled) {
+ checkbad(socreate(AF_IPX, &conn->bc_so, SOCK_DGRAM, 0, p));
+ bzero(&sipx, sizeof(sipx));
+ sipx.sipx_len = sizeof(sipx);
+ checkbad(sobind(conn->bc_so, (struct sockaddr *)&sipx, p));
+ checkbad(ncp_soconnect(conn->bc_so, &conn->li.saddr, p));
+ }
+#endif
+ if (!error) {
+ conn->flags |= NCPFL_SOCONN;
+ ncp_sock_checksum(conn, 0);
+ }
+ return error;
+bad:
+ ncp_sock_disconnect(conn);
+ return (error);
+}
+
+int
+ncp_sock_checksum(struct ncp_conn *conn, int enable) {
+
+#ifdef SO_IPX_CHECKSUM
+ if (enable) {
+ sotoipxpcb(conn->ncp_so)->ipxp_flags |= IPXP_CHECKSUM;
+ } else {
+ sotoipxpcb(conn->ncp_so)->ipxp_flags &= ~IPXP_CHECKSUM;
+ }
+#endif
+ return 0;
+}
+#endif
+
+#ifdef INET
+/*
+ * Connect to specified server via IP
+ */
+int
+ncp_sock_connect_in(struct ncp_conn *conn) {
+ struct sockaddr_in sin;
+ struct proc *p=conn->procp;
+ int addrlen=sizeof(sin), error;
+
+ conn->flags = 0;
+ bzero(&sin,addrlen);
+ conn->ncp_so = conn->wdg_so = NULL;
+ checkbad(socreate(AF_INET, &conn->ncp_so, SOCK_DGRAM, IPPROTO_UDP, p));
+ sin.sin_family = AF_INET;
+ sin.sin_len = addrlen;
+ checkbad(sobind(conn->ncp_so, (struct sockaddr *)&sin, p));
+ checkbad(ncp_soconnect(conn->ncp_so,(struct sockaddr*)&conn->li.addr, p));
+ if (!error)
+ conn->flags |= NCPFL_SOCONN;
+ return error;
+bad:
+ ncp_sock_disconnect(conn);
+ return (error);
+}
+#endif
+
+
+/*
+ * Connection expected to be locked
+ */
+int
+ncp_sock_disconnect(struct ncp_conn *conn) {
+ register struct socket *so;
+ conn->flags &= ~(NCPFL_SOCONN | NCPFL_ATTACHED | NCPFL_LOGGED);
+ if (conn->ncp_so) {
+ so = conn->ncp_so;
+ conn->ncp_so = (struct socket *)0;
+ soshutdown(so, 2);
+ soclose(so);
+ }
+ if (conn->wdg_so) {
+ so = conn->wdg_so;
+ conn->wdg_so = (struct socket *)0;
+ soshutdown(so, 2);
+ soclose(so);
+ }
+#ifdef NCPBURST
+ if (conn->bc_so) {
+ so = conn->bc_so;
+ conn->bc_so = (struct socket *)NULL;
+ soshutdown(so, 2);
+ soclose(so);
+ }
+#endif
+ return 0;
+}
+
+#ifdef IPX
+static void
+ncp_watchdog(struct ncp_conn *conn) {
+ char *buf;
+ struct mbuf *m;
+ int error, len, flags;
+ struct socket *so;
+ struct sockaddr *sa;
+ struct uio auio;
+
+ sa = NULL;
+ while (conn->wdg_so) { /* not a loop */
+ so = conn->wdg_so;
+ auio.uio_resid = len = 1000000;
+ auio.uio_procp = curproc;
+ flags = MSG_DONTWAIT;
+ error = so->so_proto->pr_usrreqs->pru_soreceive(so,
+ (struct sockaddr**)&sa, &auio, &m, (struct mbuf**)0, &flags);
+ if (error) break;
+ len -= auio.uio_resid;
+ NCPSDEBUG("got watch dog %d\n",len);
+ if (len != 2) break;
+ buf = mtod(m, char*);
+ if (buf[1] != '?') break;
+ buf[1] = 'Y';
+ error = so->so_proto->pr_usrreqs->pru_sosend(so, (struct sockaddr*)sa, 0, m, 0, 0, curproc);
+ NCPSDEBUG("send watch dog %d\n",error);
+ break;
+ }
+ if (sa) FREE(sa, M_SONAME);
+ return;
+}
+#endif /* IPX */
+
+void
+ncp_check_conn(struct ncp_conn *conn) {
+ int s;
+
+ if (conn == NULL || !(conn->flags & NCPFL_ATTACHED))
+ return;
+ s = splnet();
+ ncp_check_rq(conn);
+ splx(s);
+#ifdef IPX
+ ncp_watchdog(conn);
+#endif
+}
diff --git a/sys/netncp/ncp_sock.h b/sys/netncp/ncp_sock.h
new file mode 100644
index 0000000..37aa712
--- /dev/null
+++ b/sys/netncp/ncp_sock.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_SOCK_H_
+#define _NCP_SOCK_H_
+
+int ncp_sock_connect_ipx(struct ncp_conn *);
+int ncp_sock_connect_in(struct ncp_conn *);
+int ncp_sock_recv(struct socket *so, struct mbuf **mp, int *rlen);
+int ncp_sock_send(struct socket *so, struct mbuf *data, struct ncp_rq *rqp);
+int ncp_sock_disconnect(struct ncp_conn *conn);
+int ncp_poll(struct socket *so, int events);
+int ncp_sock_rselect(struct socket *so,struct proc *p, struct timeval *tv,int events);
+int ncp_sock_checksum(struct ncp_conn *conn, int enable);
+
+void ncp_check_rq(struct ncp_conn *conn);
+void ncp_check_conn(struct ncp_conn *conn);
+
+void ncp_check_wd(struct ncp_conn *conn);
+
+#endif /* _NCP_SOCK_H_ */
diff --git a/sys/netncp/ncp_subr.c b/sys/netncp/ncp_subr.c
new file mode 100644
index 0000000..b26d638
--- /dev/null
+++ b/sys/netncp/ncp_subr.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/mbuf.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_user.h>
+#include <netncp/nwerror.h>
+
+int ncp_debuglevel = 0;
+
+struct callout_handle ncp_timer_handle;
+
+static void ncp_at_exit(struct proc *p);
+static void ncp_timer(void *arg);
+
+/*
+ * duplicate string from user space. It should be very-very slow.
+ */
+char *
+ncp_str_dup(char *s) {
+ char *p, bt;
+ int len = 0;
+
+ for (p = s;;p++) {
+ if (copyin(p, &bt, 1)) return NULL;
+ len++;
+ if (bt == 0) break;
+ }
+ MALLOC(p, char*, len, M_NCPDATA, M_WAITOK);
+ copyin(s, p, len);
+ return p;
+}
+
+
+void
+ncp_at_exit(struct proc *p) {
+ struct ncp_conn *ncp, *nncp;
+
+ if (ncp_conn_putprochandles(p) == 0) return;
+
+ ncp_conn_locklist(LK_EXCLUSIVE, p);
+ for (ncp = conn_list.slh_first; ncp; ncp = nncp) {
+ nncp = ncp->nc_next.sle_next;
+ if (ncp->ref_cnt != 0) continue;
+ if (ncp_conn_lock(ncp, p, p->p_ucred,NCPM_READ|NCPM_EXECUTE|NCPM_WRITE))
+ continue;
+ if (ncp_disconnect(ncp) != 0)
+ ncp_conn_unlock(ncp,p);
+ }
+ ncp_conn_unlocklist(p);
+ return;
+}
+
+int
+ncp_init(void) {
+ ncp_conn_init();
+ if (at_exit(ncp_at_exit)) {
+ NCPFATAL("can't register at_exit handler\n");
+ return ENOMEM;
+ }
+ ncp_timer_handle = timeout(ncp_timer,NULL,NCP_TIMER_TICK);
+ return 0;
+}
+
+void
+ncp_done(void) {
+ struct ncp_conn *ncp, *nncp;
+ struct proc *p = curproc;
+
+ untimeout(ncp_timer,NULL,ncp_timer_handle);
+ rm_at_exit(ncp_at_exit);
+ ncp_conn_locklist(LK_EXCLUSIVE, p);
+ for (ncp = conn_list.slh_first; ncp; ncp = nncp) {
+ nncp = ncp->nc_next.sle_next;
+ ncp->ref_cnt = 0;
+ if (ncp_conn_lock(ncp, p, p->p_ucred,NCPM_READ|NCPM_EXECUTE|NCPM_WRITE)) {
+ NCPFATAL("Can't lock connection !\n");
+ continue;
+ }
+ if (ncp_disconnect(ncp) != 0)
+ ncp_conn_unlock(ncp,p);
+ }
+ ncp_conn_unlocklist(p);
+}
+
+
+/* tick every second and check for watch dog packets and lost connections */
+static void
+ncp_timer(void *arg){
+ struct ncp_conn *conn;
+
+ if(ncp_conn_locklist(LK_SHARED | LK_NOWAIT, NULL) == 0) {
+ SLIST_FOREACH(conn, &conn_list, nc_next)
+ ncp_check_conn(conn);
+ ncp_conn_unlocklist(NULL);
+ }
+ ncp_timer_handle = timeout(ncp_timer,NULL,NCP_TIMER_TICK);
+}
+
+int
+ncp_get_bindery_object_id(struct ncp_conn *conn,
+ u_int16_t object_type, char *object_name,
+ struct ncp_bindery_object *target,
+ struct proc *p,struct ucred *cred)
+{
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD_S(23,53,p,cred);
+ ncp_rq_word_hl(rqp, object_type);
+ ncp_rq_pstring(rqp, object_name);
+ checkbad(ncp_request(conn,rqp));
+ if (rqp->rpsize < 54) {
+ printf("ncp_rp_size %d < 54\n", rqp->rpsize);
+ error = EINVAL;
+ goto bad;
+ }
+ target->object_id = ncp_rp_dword_hl(rqp);
+ target->object_type = ncp_rp_word_hl(rqp);
+ ncp_rp_mem(rqp,(caddr_t)target->object_name, 48);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) {
+ int error = 0, len = 0, retlen=0, tsiz, burstio;
+ DECLARE_RQ;
+
+ tsiz = uiop->uio_resid;
+#ifdef NCPBURST
+ burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
+#else
+ burstio = 0;
+#endif
+
+ while (tsiz > 0) {
+ if (!burstio) {
+ len = min(4096 - (uiop->uio_offset % 4096), tsiz);
+ len = min(len, conn->buffer_size);
+ NCP_RQ_HEAD(72,uiop->uio_procp,cred);
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_mem(rqp, (caddr_t)file, 6);
+ ncp_rq_dword(rqp, htonl(uiop->uio_offset));
+ ncp_rq_word(rqp, htons(len));
+ checkbad(ncp_request(conn,rqp));
+ retlen = ncp_rp_word_hl(rqp);
+ if (uiop->uio_offset & 1)
+ ncp_rp_byte(rqp);
+ error = nwfs_mbuftouio(&rqp->mrp,uiop,retlen,&rqp->bpos);
+ NCP_RQ_EXIT;
+ } else {
+#ifdef NCPBURST
+ error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
+#endif
+ }
+ if (error) break;
+ tsiz -= retlen;
+ if (retlen < len)
+ break;
+ }
+ return (error);
+}
+
+int
+ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
+{
+ int error = 0, len, tsiz, backup;
+ DECLARE_RQ;
+
+ if (uiop->uio_iovcnt != 1) {
+ printf("%s: can't handle iovcnt>1 !!!\n", __FUNCTION__);
+ return EIO;
+ }
+ tsiz = uiop->uio_resid;
+ while (tsiz > 0) {
+ len = min(4096 - (uiop->uio_offset % 4096), tsiz);
+ len = min(len, conn->buffer_size);
+ if (len == 0) {
+ printf("gotcha!\n");
+ }
+ /* rq head */
+ NCP_RQ_HEAD(73,uiop->uio_procp,cred);
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_mem(rqp, (caddr_t)file, 6);
+ ncp_rq_dword(rqp, htonl(uiop->uio_offset));
+ ncp_rq_word_hl(rqp, len);
+ nwfs_uiotombuf(uiop,&rqp->mrq,len,&rqp->bpos);
+ checkbad(ncp_request(conn,rqp));
+ if (len == 0)
+ break;
+ NCP_RQ_EXIT;
+ if (error) {
+ backup = len;
+ uiop->uio_iov->iov_base -= backup;
+ uiop->uio_iov->iov_len += backup;
+ uiop->uio_offset -= backup;
+ uiop->uio_resid += backup;
+ break;
+ }
+ tsiz -= len;
+ }
+ if (error)
+ uiop->uio_resid = tsiz;
+ switch (error) {
+ case NWE_INSUFFICIENT_SPACE:
+ error = ENOSPC;
+ break;
+ }
+ return (error);
+}
diff --git a/sys/netncp/ncp_subr.h b/sys/netncp/ncp_subr.h
new file mode 100644
index 0000000..af3c784
--- /dev/null
+++ b/sys/netncp/ncp_subr.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_SUBR_H_
+#define _NCP_SUBR_H_
+
+#define NCP_TIMER_TICK 2*hz /* 1sec */
+#define NCP_SIGMASK(set) \
+ (SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \
+ SIGISMEMBER(set, SIGHUP) || SIGISMEMBER(set, SIGKILL) || \
+ SIGISMEMBER(set, SIGQUIT))
+
+
+#define NCP_PRINT(format, args...) printf("FATAL: %s: "format, __FUNCTION__ ,## args)
+#define nwfs_printf NCP_PRINT
+/* Maybe this should panic, but I dont like that */
+#define NCPFATAL NCP_PRINT
+
+/* socket debugging */
+#ifdef NCP_SOCKET_DEBUG
+#define NCPSDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
+#else
+#define NCPSDEBUG(format, args...)
+#endif
+
+/* NCP calls debug */
+#ifdef NCP_NCP_DEBUG
+#define NCPNDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
+#else
+#define NCPNDEBUG(format, args...)
+#endif
+
+/* NCP data dump */
+#ifdef NCP_DATA_DEBUG
+#define NCPDDEBUG(m) m_dumpm(m)
+#else
+#define NCPDDEBUG(m)
+#endif
+
+/* FS VOPS debug */
+#ifdef NWFS_VOPS_DEBUG
+#define NCPVODEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
+#else
+#define NCPVODEBUG(format, args...)
+#endif
+
+/* FS VNOPS debug */
+#ifdef NWFS_VNOPS_DEBUG
+#define NCPVNDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
+#else
+#define NCPVNDEBUG(format, args...)
+#endif
+
+#define checkbad(fn) {error=(fn);if(error) goto bad;}
+
+#define ncp_suser(cred) suser_xxx(cred, NULL, 0)
+
+#define ncp_isowner(conn,cred) ((cred)->cr_uid == (conn)->nc_owner->cr_uid)
+
+struct ncp_conn;
+
+struct nwmount;
+struct vnode;
+struct nwnode;
+struct vattr;
+struct uio;
+struct ncp_nlstables;
+
+struct ncp_open_info {
+ u_int32_t origfh;
+ ncp_fh fh;
+ u_int8_t action;
+ struct nw_entry_info fattr;
+};
+
+extern int ncp_debuglevel;
+
+int ncp_init(void);
+void ncp_done(void);
+int ncp_chkintr(struct ncp_conn *conn, struct proc *p);
+char*ncp_str_dup(char *s);
+
+/* ncp_crypt.c */
+void nw_keyhash(const u_char *key, const u_char *buf, int buflen, u_char *target);
+void nw_encrypt(const u_char *fra, const u_char *buf, u_char *target);
+void ncp_sign(const u_int32_t *state, const char *x, u_int32_t *ostate);
+
+/* ncp calls */
+int ncp_get_bindery_object_id(struct ncp_conn *conn,
+ u_int16_t object_type, char *object_name,
+ struct ncp_bindery_object *target,
+ struct proc *p,struct ucred *cred);
+int ncp_login_object(struct ncp_conn *conn, unsigned char *username,
+ int login_type, unsigned char *password,
+ struct proc *p,struct ucred *cred);
+int ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred);
+int ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred);
+
+
+#endif /* _NCP_SUBR_H_ */
diff --git a/sys/netncp/ncp_user.h b/sys/netncp/ncp_user.h
new file mode 100644
index 0000000..4f430b0
--- /dev/null
+++ b/sys/netncp/ncp_user.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_USER_H_
+#define _NCP_USER_H_
+
+/*
+ * "ncp" interface to kernel, this can be done via syscalls but may eat
+ * a lot of them, so we select internal code, define req's and replays
+ * as necessary. Structure for call is simple:
+ * byte=NCP_CONN
+ * byte=NCP_CONN_SUBFN
+ * ....=data
+ */
+#define NCP_CONN 0xF5 /* change if that will occupied */
+#define NCP_CONN_READ 0x01 /* read from file handle */
+#define NCP_CONN_WRITE 0x02 /* write to file handle */
+#define NCP_CONN_SETFLAGS 0x03 /* word mask, word flags */
+#define NCP_CONN_LOGIN 0x04 /* bind login on handle */
+#define NCP_CONN_GETINFO 0x05 /* get information about connection */
+#define NCP_CONN_GETUSER 0x06 /* get user name for connection */
+#define NCP_CONN_CONN2REF 0x07 /* convert handle to reference */
+#define NCP_CONN_CONNCLOSE 0x08 /* release connection handle */
+#define NCP_CONN_FRAG 0x09 /* ncp fragmented request */
+#define NCP_CONN_DUP 0x0A /* get an additional handle */
+#define NCP_CONN_GETDATA 0x0B /* retrieve NCP_CD_* vals */
+#define NCP_CONN_SETDATA 0x0C /* store NCP_CD_* vals */
+
+/*
+ * Internal connection data can be set by owner or superuser and retrieved
+ * only by superuser
+ */
+#define NCP_CD_NDSLOGINKEY 0x01
+#define NCP_CD_NDSPRIVATEKEY 0x02
+#define NCP_CD_NDSUFLAGS 0x03
+
+/* user side structures to issue fragmented ncp calls */
+typedef struct {
+ char *fragAddress;
+ u_int32_t fragSize;
+} NW_FRAGMENT;
+
+
+struct ncp_rw {
+ ncp_fh nrw_fh;
+ char *nrw_base;
+ off_t nrw_offset;
+ int nrw_cnt;
+};
+
+struct ncp_conn_login {
+ char *username;
+ int objtype;
+ char *password;
+};
+
+struct ncp_conn_frag {
+ int cc; /* completion code */
+ int cs; /* connection state */
+ int fn;
+ int rqfcnt;
+ NW_FRAGMENT *rqf;
+ int rpfcnt;
+ NW_FRAGMENT *rpf;
+};
+
+#endif
diff --git a/sys/netncp/nwerror.h b/sys/netncp/nwerror.h
new file mode 100644
index 0000000..6a5b09e
--- /dev/null
+++ b/sys/netncp/nwerror.h
@@ -0,0 +1,634 @@
+/*
+ * NetWare requestor error codes, they taken from NDK
+ *
+ * $FreeBSD$
+ */
+#if !defined (_NWERROR_H_)
+#define _NWERROR_H_
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif
+
+#define SHELL_ERROR 0x8800
+#define VLM_ERROR 0x8800
+#define ALREADY_ATTACHED 0x8800 /* 0 - Attach attempted to server with valid, existing connection */
+#define INVALID_CONNECTION 0x8801 /* 1 - Request attempted with invalid or non-attached connection handle */
+#define DRIVE_IN_USE 0x8802 /* 2 - OS/2 only (NOT USED) */
+#define CANT_ADD_CDS 0x8803 /* 3 - Map drive attempted but unable to add new current directory structure */
+#define DRIVE_CANNOT_MAP 0x8803
+#define BAD_DRIVE_BASE 0x8804 /* 4 - Map drive attempted with invalid path specification */
+#define NET_READ_ERROR 0x8805 /* 5 - Attempt to receive from the selected transport failed */
+#define NET_RECV_ERROR 0x8805 /* 5 */
+#define UNKNOWN_NET_ERROR 0x8806 /* 6 - Network send attempted with an un-specific network error */
+#define SERVER_INVALID_SLOT 0x8807 /* 7 - Server request attempted with invalid server connection slot */
+#define BAD_SERVER_SLOT 0x8807 /* 7 */
+#define NO_SERVER_SLOTS 0x8808 /* 8 - Attach attempted to server with no connection slots available */
+#define NET_WRITE_ERROR 0x8809 /* 9 - Attempt to send on the selected transport failed */
+#define CONNECTION_IN_ERROR_STATE 0x8809 /* Client-32 */
+#define NET_SEND_ERROR 0x8809 /* 9 */
+#define SERVER_NO_ROUTE 0x880A /* 10 - Attempted to find route to server where no route exists */
+#define BAD_LOCAL_TARGET 0x880B /* 11 - OS/2 only */
+#define TOO_MANY_REQ_FRAGS 0x880C /* 12 - Attempted request with too many request fragments specified */
+#define CONNECT_LIST_OVERFLOW 0x880D /* 13 */
+#define BUFFER_OVERFLOW 0x880E /* 14 - Attempt to receive more data than the reply buffer had room for */
+#define MORE_DATA_ERROR 0x880E /* Client-32 */
+#define NO_CONN_TO_SERVER 0x880F /* 15 */
+#define NO_CONNECTION_TO_SERVER 0x880F /* 15 - Attempt to get connection for a server not connected */
+#define NO_ROUTER_FOUND 0x8810 /* 16 - OS/2 only */
+#define BAD_FUNC_ERROR 0x8811 /* 17 */
+#define INVALID_SHELL_CALL 0x8811 /* 17 - Attempted function call to non- existent or illegal function */
+#define SCAN_COMPLETE 0x8812
+#define LIP_RESIZE_ERROR 0x8812 /* Client-32 */
+#define UNSUPPORTED_NAME_FORMAT_TYPE 0x8813
+#define INVALID_DIR_HANDLE 0x8813 /* Client-32 */
+#define HANDLE_ALREADY_LICENSED 0x8814
+#define OUT_OF_CLIENT_MEMORY 0x8814 /* Client-32 */
+#define HANDLE_ALREADY_UNLICENSED 0x8815
+#define PATH_NOT_OURS 0x8815 /* Client-32 */
+#define INVALID_NCP_PACKET_LENGTH 0x8816
+#define PATH_IS_PRINT_DEVICE 0x8816 /* Client-32 */
+#define SETTING_UP_TIMEOUT 0x8817
+#define PATH_IS_EXCLUDED_DEVICE 0x8817 /* Client-32 */
+#define SETTING_SIGNALS 0x8818
+#define PATH_IS_INVALID 0x8818 /* Client-32 */
+#define SERVER_CONNECTION_LOST 0x8819
+#define NOT_SAME_DEVICE 0x8819 /* Client-32 */
+#define OUT_OF_HEAP_SPACE 0x881A
+#define INVALID_SERVICE_REQUEST 0x881B
+#define INVALID_SEARCH_HANDLE 0x881B /* Client-32 */
+#define INVALID_TASK_NUMBER 0x881C
+#define INVALID_DEVICE_HANDLE 0x881C /* Client-32 */
+#define INVALID_MESSAGE_LENGTH 0x881D
+#define INVALID_SEM_HANDLE 0x881D /* Client-32 */
+#define EA_SCAN_DONE 0x881E
+#define INVALID_CFG_HANDLE 0x881E /* Client-32 */
+#define BAD_CONNECTION_NUMBER 0x881F
+#define INVALID_MOD_HANDLE 0x881F /* Client-32 */
+#define ASYN_FIRST_PASS 0x8820
+#define INVALID_DEVICE_INDEX 0x8821
+#define INVALID_CONN_HANDLE 0x8822
+#define INVALID_QUEUE_ID 0x8823
+#define INVALID_PDEVICE_HANDLE 0x8824
+#define INVALID_JOB_HANDLE 0x8825
+#define INVALID_ELEMENT_ID 0x8826
+#define ALIAS_NOT_FOUND 0x8827
+#define RESOURCE_SUSPENDED 0x8828
+#define INVALID_QUEUE_SPECIFIED 0x8829
+#define DEVICE_ALREADY_OPEN 0x882A
+#define JOB_ALREADY_OPEN 0x882B
+#define QUEUE_NAME_ID_MISMATCH 0x882C
+#define JOB_ALREADY_STARTED 0x882D
+#define SPECT_DAA_TYPE_NOT_SUPPORTED 0x882E
+#define INVALID_ENVIR_HANDLE 0x882F
+#define NOT_SAME_CONNECTION 0x8830 /* 48 - Internal server request attempted accross different server connections */
+#define PRIMARY_CONNECTION_NOT_SET 0x8831 /* 49 - Attempt to retrieve default connection with no primary connection set */
+#define NO_PRIMARY_SET 0x8831 /* 49 */
+#define KEYWORD_NOT_FOUND 0x8832 /* Client-32 */
+#define PRINT_CAPTURE_NOT_IN_PROGRESS 0x8832 /* Client-32 */
+#define NO_CAPTURE_SET 0x8832 /* 50 */
+#define NO_CAPTURE_IN_PROGRESS 0x8832 /* 50 - Capture information requested on port with no capture in progress */
+#define BAD_BUFFER_LENGTH 0x8833 /* 51 */
+#define INVALID_BUFFER_LENGTH 0x8833 /* 51 - Used to indicate length which caller requested on a GetDNC or SetDNC was too large */
+#define NO_USER_NAME 0x8834 /* 52 */
+#define NO_NETWARE_PRINT_SPOOLER 0x8835 /* 53 - Capture requested without having the local print spooler installed */
+#define INVALID_PARAMETER 0x8836 /* 54 - Attempted function with an invalid function parameter specified */
+#define CONFIG_FILE_OPEN_FAILED 0x8837 /* 55 - OS/2 only */
+#define NO_CONFIG_FILE 0x8838 /* 56 - OS/2 only */
+#define CONFIG_FILE_READ_FAILED 0x8839 /* 57 - OS/2 only */
+#define CONFIG_LINE_TOO_LONG 0x883A /* 58 - OS/2 only */
+#define CONFIG_LINES_IGNORED 0x883B /* 59 - OS/2 only */
+#define NOT_MY_RESOURCE 0x883C /* 60 - Attempted request made with a parameter using foriegn resource */
+#define DAEMON_INSTALLED 0x883D /* 61 - OS/2 only */
+#define SPOOLER_INSTALLED 0x883E /* 62 - Attempted load of print spooler with print spooler already installed */
+#define CONN_TABLE_FULL 0x883F /* 63 */
+#define CONNECTION_TABLE_FULL 0x883F /* 63 - Attempted to allocate a connection handle with no more local connection table entries */
+#define CONFIG_SECTION_NOT_FOUND 0x8840 /* 64 - OS/2 only */
+#define BAD_TRAN_TYPE 0x8841 /* 65 */
+#define INVALID_TRANSPORT_TYPE 0x8841 /* 65 - Attempted function on a connection with an invalid transport selected */
+#define TDS_TAG_IN_USE 0x8842 /* 66 - OS/2 only */
+#define TDS_OUT_OF_MEMORY 0x8843 /* 67 - OS/2 only */
+#define TDS_INVALID_TAG 0x8844 /* 68 - Attempted TDS function with invalid tag */
+#define TDS_WRITE_TRUNCATED 0x8845 /* 69 - Attempted TDS write with buffer that exceeded buffer */
+#define NO_CONNECTION_TO_DS 0x8846 /* Client-32 */
+#define NO_DIRECTORY_SERVICE_CONNECTION 0x8846 /* 70 */
+#define SERVICE_BUSY 0x8846 /* 70 - Attempted request made to partially asynchronous function in busy state */
+#define NO_SERVER_ERROR 0x8847 /* 71 - Attempted connect failed to find any servers responding */
+#define BAD_VLM_ERROR 0x8848 /* 72 - Attempted function call to non-existant or not-loaded overlay */
+#define NETWORK_DRIVE_IN_USE 0x8849 /* 73 - Attempted map to network drive that was already mapped */
+#define LOCAL_DRIVE_IN_USE 0x884A /* 74 - Attempted map to local drive that was in use */
+#define NO_DRIVES_AVAILABLE 0x884B /* 75 - Attempted map to next available drive when none were available */
+#define DEVICE_NOT_REDIRECTED 0x884C /* 76 - The device is not redirected */
+#define NO_MORE_SFT_ENTRIES 0x884D /* 77 - Maximum number of files was reached */
+#define UNLOAD_ERROR 0x884E /* 78 - Attempted unload failed */
+#define IN_USE_ERROR 0x884F /* 79 - Attempted re-use of already in use connection entry */
+#define TOO_MANY_REP_FRAGS 0x8850 /* 80 - Attempted request with too many reply fragments specified */
+#define TABLE_FULL 0x8851 /* 81 - Attempted to add a name into the name table after it was full */
+#ifndef SOCKET_NOT_OPEN
+#define SOCKET_NOT_OPEN 0x8852 /* 82 - Listen was posted on unopened socket */
+#endif
+#define MEM_MGR_ERROR 0x8853 /* 83 - Attempted enhanced memory operation failed */
+#define SFT3_ERROR 0x8854 /* 84 - An SFT3 switch occured mid-transfer */
+#define PREFERRED_NOT_FOUND 0x8855 /* 85 - the preferred directory server was not established but another directory server was returned */
+#define DEVICE_NOT_RECOGNIZED 0x8856 /* 86 - used to determine if the device is not used by VISE so pass it on to the next redirector, if any. */
+#define BAD_NET_TYPE 0x8857 /* 87 - the network type (Bind/NDS) does not match the server version */
+#define ERROR_OPENING_FILE 0x8858 /* 88 - generic open failure error, invalid path, access denied, etc.. */
+#define NO_PREFERRED_SPECIFIED 0x8859 /* 89 - no preferred name specified */
+#define ERROR_OPENING_SOCKET 0x885A /* 90 - error opening a socket */
+#define REQUESTER_FAILURE 0x885A /* Client-32 */
+#define RESOURCE_ACCESS_DENIED 0x885B /* Client-32 */
+#define SIGNATURE_LEVEL_CONFLICT 0x8861
+#define NO_LOCK_FOUND 0x8862 /* OS/2 - process lock on conn handle failed, process ID not recognized */
+#define LOCK_TABLE_FULL 0x8863 /* OS/2 - process lock on conn handle failed, process lock table full */
+#define INVALID_MATCH_DATA 0x8864
+#define MATCH_FAILED 0x8865
+#define NO_MORE_ENTRIES 0x8866
+#define INSUFFICIENT_RESOURCES 0x8867
+#define STRING_TRANSLATION 0x8868
+#define STRING_TRANSLATION_NEEDED 0x8868 /* Client-32 */
+#define ACCESS_VIOLATION 0x8869
+#define NOT_AUTHENTICATED 0x886A
+#define INVALID_LEVEL 0x886B
+#define RESOURCE_LOCK_ERROR 0x886C
+#define INVALID_NAME_FORMAT 0x886D
+#define OBJECT_EXISTS 0x886E
+#define OBJECT_NOT_FOUND 0x886F
+#define UNSUPPORTED_TRAN_TYPE 0x8870
+#define INVALID_STRING_TYPE 0x8871
+#define INVALID_OWNER 0x8872
+#define UNSUPPORTED_AUTHENTICATOR 0x8873
+#define IO_PENDING 0x8874
+#define INVALID_DRIVE_NUM 0x8875
+#define SHELL_FAILURE 0x88FF
+#define VLM_FAILURE 0x88FF
+
+#define SVC_ALREADY_REGISTERED 0x8880 /* Client-32 */
+#define SVC_REGISTRY_FULL 0x8881 /* Client-32 */
+#define SVC_NOT_REGISTERED 0x8882 /* Client-32 */
+#define OUT_OF_RESOURCES 0x8883 /* Client-32 */
+#define RESOLVE_SVC_FAILED 0x8884 /* Client-32 */
+#define CONNECT_FAILED 0x8885 /* Client-32 */
+#define PROTOCOL_NOT_BOUND 0x8886 /* Client-32 */
+#define AUTHENTICATION_FAILED 0x8887 /* Client-32 */
+#define INVALID_AUTHEN_HANDLE 0x8888 /* Client-32 */
+#define AUTHEN_HANDLE_ALREADY_EXISTS 0x8889 /* Client-32 */
+
+#define DIFF_OBJECT_ALREADY_AUTHEN 0x8890 /* Client-32 */
+#define REQUEST_NOT_SERVICEABLE 0x8891 /* Client-32 */
+#define AUTO_RECONNECT_SO_REBUILD 0x8892 /* Client-32 */
+#define AUTO_RECONNECT_RETRY_REQUEST 0x8893 /* Client-32 */
+#define ASYNC_REQUEST_IN_USE 0x8894 /* Client-32 */
+#define ASYNC_REQUEST_CANCELED 0x8895 /* Client-32 */
+#define SESS_SVC_ALREADY_REGISTERED 0x8896 /* Client-32 */
+#define SESS_SVC_NOT_REGISTERED 0x8897 /* Client-32 */
+#define PREVIOUSLY_AUTHENTICATED 0x8899 /* Client-32 */
+#define RESOLVE_SVC_PARTIAL 0x889A /* Client-32 */
+#define NO_DEFAULT_SPECIFIED 0x889B /* Client-32 */
+#define HOOK_REQUEST_NOT_HANDLED 0x889C /* Client-32 */
+#define HOOK_REQUEST_BUSY 0x889D /* Client-32 */
+#define HOOK_REQUEST_QUEUED 0x889D /* Client-32 */
+#define AUTO_RECONNECT_SO_IGNORE 0x889E /* Client-32 */
+#define ASYNC_REQUEST_NOT_IN_USE 0x889F /* Client-32 */
+#define AUTO_RECONNECT_FAILURE 0x88A0 /* Client-32 */
+#define NET_ERROR_ABORT_APPLICATION 0x88A1 /* Client-32 */
+#define NET_ERROR_SUSPEND_APPLICATION 0x88A2 /* Client-32 */
+#define NET_ERROR_ABORTED_PROCESS_GROUP 0x88A3 /* Client-32 */
+#define NET_ERROR_PASSWORD_HAS_EXPIRED 0x88A5 /* Client-32 */
+#define NET_ERROR_NETWORK_INACTIVE 0x88A6 /* Client-32 */
+#define REPLY_TRUNCATED 0x88e6 /* 230 NLM */
+
+
+/* Server Errors */
+
+#define ERR_INSUFFICIENT_SPACE 0x8901 /* 001 */
+#define ERR_NO_MORE_ENTRY 0x8914 /* 020 */
+#define NLM_INVALID_CONNECTION 0x890a /* 010 */
+#define ERR_BUFFER_TOO_SMALL 0x8977 /* 119 */
+#define ERR_VOLUME_FLAG_NOT_SET 0x8978 /* 120 the service requested, not avail. on the selected vol. */
+#define ERR_NO_ITEMS_FOUND 0x8979 /* 121 */
+#define ERR_CONN_ALREADY_TEMP 0x897a /* 122 */
+#define ERR_CONN_ALREADY_LOGGED_IN 0x897b /* 123 */
+#define ERR_CONN_NOT_AUTHENTICATED 0x897c /* 124 */
+#define ERR_CONN_NOT_LOGGED_IN 0x897d /* 125 */
+#define NCP_BOUNDARY_CHECK_FAILED 0x897e /* 126 */
+#define ERR_LOCK_WAITING 0x897f /* 127 */
+#define ERR_LOCK_FAIL 0x8980 /* 128 */
+#define FILE_IN_USE_ERROR 0x8980 /* 128 */
+#define NO_MORE_FILE_HANDLES 0x8981 /* 129 */
+#define NO_OPEN_PRIVILEGES 0x8982 /* 130 */
+#define IO_ERROR_NETWORK_DISK 0x8983 /* 131 */
+#define ERR_AUDITING_HARD_IO_ERROR 0x8983 /* 131 */
+#define NO_CREATE_PRIVILEGES 0x8984 /* 132 */
+#define ERR_AUDITING_NOT_SUPV 0x8984 /* 132 */
+#define NO_CREATE_DELETE_PRIVILEGES 0x8985 /* 133 */
+#define CREATE_FILE_EXISTS_READ_ONLY 0x8986 /* 134 */
+#define WILD_CARDS_IN_CREATE_FILE_NAME 0x8987 /* 135 */
+#define CREATE_FILENAME_ERROR 0x8987 /* 135 */
+#define INVALID_FILE_HANDLE 0x8988 /* 136 */
+#define NO_SEARCH_PRIVILEGES 0x8989 /* 137 */
+#define NO_DELETE_PRIVILEGES 0x898A /* 138 */
+#define NO_RENAME_PRIVILEGES 0x898B /* 139 */
+#define NO_MODIFY_PRIVILEGES 0x898C /* 140 */
+#define SOME_FILES_AFFECTED_IN_USE 0x898D /* 141 */
+#define NO_FILES_AFFECTED_IN_USE 0x898E /* 142 */
+#define SOME_FILES_AFFECTED_READ_ONLY 0x898F /* 143 */
+#define NO_FILES_AFFECTED_READ_ONLY 0x8990 /* 144 */
+#define SOME_FILES_RENAMED_NAME_EXISTS 0x8991 /* 145 */
+#define NO_FILES_RENAMED_NAME_EXISTS 0x8992 /* 146 */
+#define NO_READ_PRIVILEGES 0x8993 /* 147 */
+#define NO_WRITE_PRIVILEGES_OR_READONLY 0x8994 /* 148 */
+#define FILE_DETACHED 0x8995 /* 149 */
+#define SERVER_OUT_OF_MEMORY 0x8996 /* 150 */
+#define ERR_TARGET_NOT_A_SUBDIRECTORY 0x8996 /* 150 can be changed later (note written by server people). */
+#define NO_DISK_SPACE_FOR_SPOOL_FILE 0x8997 /* 151 */
+#define ERR_AUDITING_NOT_ENABLED 0x8997 /* 151 */
+#define VOLUME_DOES_NOT_EXIST 0x8998 /* 152 */
+#define DIRECTORY_FULL 0x8999 /* 153 */
+#define RENAMING_ACROSS_VOLUMES 0x899A /* 154 */
+#define BAD_DIRECTORY_HANDLE 0x899B /* 155 */
+#define INVALID_PATH 0x899C /* 156 */
+#define NO_MORE_TRUSTEES 0x899C /* 156 */
+#define NO_MORE_DIRECTORY_HANDLES 0x899D /* 157 */
+#define INVALID_FILENAME 0x899E /* 158 */
+#define DIRECTORY_ACTIVE 0x899F /* 159 */
+#define DIRECTORY_NOT_EMPTY 0x89A0 /* 160 */
+#define DIRECTORY_IO_ERROR 0x89A1 /* 161 */
+#define READ_FILE_WITH_RECORD_LOCKED 0x89A2 /* 162 */
+#define ERR_TRANSACTION_RESTARTED 0x89A3 /* 163 */
+#define ERR_RENAME_DIR_INVALID 0x89A4 /* 164 */
+#define ERR_INVALID_OPENCREATE_MODE 0x89A5 /* 165 */
+#define ERR_ALREADY_IN_USE 0x89A6 /* 166 */
+#define ERR_AUDITING_ACTIVE 0x89A6 /* 166 */
+#define ERR_INVALID_RESOURCE_TAG 0x89A7 /* 167 */
+#define ERR_ACCESS_DENIED 0x89A8 /* 168 */
+#define ERR_AUDITING_NO_RIGHTS 0x89A8 /* 168 */
+#define INVALID_DATA_STREAM 0x89BE /* 190 */
+#define INVALID_NAME_SPACE 0x89BF /* 191 */
+#define NO_ACCOUNTING_PRIVILEGES 0x89C0 /* 192 */
+#define LOGIN_DENIED_NO_ACCOUNT_BALANCE 0x89C1 /* 193 */
+#define LOGIN_DENIED_NO_CREDIT 0x89C2 /* 194 */
+#define ERR_AUDITING_RECORD_SIZE 0x89C2 /* 194 */
+#define ERR_TOO_MANY_HOLDS 0x89C3 /* 195 */
+#define ACCOUNTING_DISABLED 0x89C4 /* 196 */
+#define INTRUDER_DETECTION_LOCK 0x89C5 /* 197 */
+#define NO_CONSOLE_OPERATOR 0x89C6 /* 198 */
+#define NO_CONSOLE_PRIVILEGES 0x89C6 /* 198 */
+#define ERR_Q_IO_FAILURE 0x89D0 /* 208 */
+#define ERR_NO_QUEUE 0x89D1 /* 209 */
+#define ERR_NO_Q_SERVER 0x89D2 /* 210 */
+#define ERR_NO_Q_RIGHTS 0x89D3 /* 211 */
+#define ERR_Q_FULL 0x89D4 /* 212 */
+#define ERR_NO_Q_JOB 0x89D5 /* 213 */
+#define ERR_NO_Q_JOB_RIGHTS 0x89D6 /* 214 */
+#define ERR_Q_IN_SERVICE 0x89D7 /* 215 */
+#define PASSWORD_NOT_UNIQUE 0x89D7 /* 215 */
+#define ERR_Q_NOT_ACTIVE 0x89D8 /* 216 */
+#define PASSWORD_TOO_SHORT 0x89D8 /* 216 */
+#define ERR_Q_STN_NOT_SERVER 0x89D9 /* 217 */
+#define LOGIN_DENIED_NO_CONNECTION 0x89D9 /* 217 */
+#define ERR_MAXIMUM_LOGINS_EXCEEDED 0x89D9 /* 217 */
+#define ERR_Q_HALTED 0x89DA /* 218 */
+#define UNAUTHORIZED_LOGIN_TIME 0x89DA /* 218 */
+#define UNAUTHORIZED_LOGIN_STATION 0x89DB /* 219 */
+#define ERR_Q_MAX_SERVERS 0x89DB /* 219 */
+#define ACCOUNT_DISABLED 0x89DC /* 220 */
+#define PASSWORD_HAS_EXPIRED_NO_GRACE 0x89DE /* 222 */
+#define PASSWORD_HAS_EXPIRED 0x89DF /* 223 */
+#define E_NO_MORE_USERS 0x89E7 /* 231 */
+#define NOT_ITEM_PROPERTY 0x89E8 /* 232 */
+#define WRITE_PROPERTY_TO_GROUP 0x89E8 /* 232 */
+#define MEMBER_ALREADY_EXISTS 0x89E9 /* 233 */
+#define NO_SUCH_MEMBER 0x89EA /* 234 */
+#define NOT_GROUP_PROPERTY 0x89EB /* 235 */
+#define NO_SUCH_SEGMENT 0x89EC /* 236 */
+#define PROPERTY_ALREADY_EXISTS 0x89ED /* 237 */
+#define OBJECT_ALREADY_EXISTS 0x89EE /* 238 */
+#define INVALID_NAME 0x89EF /* 239 */
+#define WILD_CARD_NOT_ALLOWED 0x89F0 /* 240 */
+#define INVALID_BINDERY_SECURITY 0x89F1 /* 241 */
+#define NO_OBJECT_READ_PRIVILEGE 0x89F2 /* 242 */
+#define NO_OBJECT_RENAME_PRIVILEGE 0x89F3 /* 243 */
+#define NO_OBJECT_DELETE_PRIVILEGE 0x89F4 /* 244 */
+#define NO_OBJECT_CREATE_PRIVILEGE 0x89F5 /* 245 */
+#define NO_PROPERTY_DELETE_PRIVILEGE 0x89F6 /* 246 */
+#define NO_PROPERTY_CREATE_PRIVILEGE 0x89F7 /* 247 */
+#define NO_PROPERTY_WRITE_PRIVILEGE 0x89F8 /* 248 */
+#define NO_FREE_CONNECTION_SLOTS 0x89F9 /* 249 */
+#define NO_PROPERTY_READ_PRIVILEGE 0x89F9 /* 249 */
+#define NO_MORE_SERVER_SLOTS 0x89FA /* 250 */
+#define TEMP_REMAP_ERROR 0x89FA /* 250 */
+#define INVALID_PARAMETERS 0x89FB /* 251 */
+#define NO_SUCH_PROPERTY 0x89FB /* 251 */
+#define ERR_NCP_NOT_SUPPORTED 0x89FB /* 251 */
+#define INTERNET_PACKET_REQT_CANCELED 0x89FC /* 252 */
+#define UNKNOWN_FILE_SERVER 0x89FC /* 252 */
+#define MESSAGE_QUEUE_FULL 0x89FC /* 252 */
+#define NO_SUCH_OBJECT 0x89FC /* 252 */
+#define LOCK_COLLISION 0x89FD /* 253 */
+#define BAD_STATION_NUMBER 0x89FD /* 253 */
+#define INVALID_PACKET_LENGTH 0x89FD /* 253 */
+#define UNKNOWN_REQUEST 0x89FD /* 253 */
+#define BINDERY_LOCKED 0x89FE /* 254 */
+#define TRUSTEE_NOT_FOUND 0x89FE /* 254 */
+#define DIRECTORY_LOCKED 0x89FE /* 254 */
+#define INVALID_SEMAPHORE_NAME_LENGTH 0x89FE /* 254 */
+#define PACKET_NOT_DELIVERABLE 0x89FE /* 254 */
+#define SERVER_BINDERY_LOCKED 0x89FE /* 254 */
+#define SOCKET_TABLE_FULL 0x89FE /* 254 */
+#define SPOOL_DIRECTORY_ERROR 0x89FE /* 254 */
+#define SUPERVISOR_HAS_DISABLED_LOGIN 0x89FE /* 254 */
+#define TIMEOUT_FAILURE 0x89FE /* 254 */
+#define BAD_PRINTER_ERROR 0x89FF /* 255 */
+#define BAD_RECORD_OFFSET 0x89FF /* 255 */
+#define CLOSE_FCB_ERROR 0x89FF /* 255 */
+#define FILE_EXTENSION_ERROR 0x89FF /* 255 */
+#define FILE_NAME_ERROR 0x89FF /* 255 */
+#define HARDWARE_FAILURE 0x89FF /* 255 */
+#define INVALID_DRIVE_NUMBER 0x89FF /* 255 */
+#define DOS_INVALID_DRIVE 0x000F /* 255 */
+#define INVALID_INITIAL_SEMAPHORE_VALUE 0x89FF /* 255 */
+#define INVALID_SEMAPHORE_HANDLE 0x89FF /* 255 */
+#define IO_BOUND_ERROR 0x89FF /* 255 */
+#define NO_FILES_FOUND_ERROR 0x89FF /* 255 */
+#define NO_RESPONSE_FROM_SERVER 0x89FF /* 255 */
+#define NO_SUCH_OBJECT_OR_BAD_PASSWORD 0x89FF /* 255 */
+#define PATH_NOT_LOCATABLE 0x89FF /* 255 */
+#define QUEUE_FULL_ERROR 0x89FF /* 255 */
+#define REQUEST_NOT_OUTSTANDING 0x89FF /* 255 */
+#ifndef SOCKET_ALREADY_OPEN
+#define SOCKET_ALREADY_OPEN 0x89FF /* 255 */
+#endif
+#define LOCK_ERROR 0x89FF /* 255 */
+#ifndef FAILURE
+#define FAILURE 0x89FF /* 255 Generic Failure */
+#endif
+
+/* #define NOT_SAME_LOCAL_DRIVE 0x89F6 */
+/* #define TARGET_DRIVE_NOT_LOCAL 0x89F7 */
+/* #define ALREADY_ATTACHED_TO_SERVER 0x89F8 */ /* 248 */
+/* #define NOT_ATTACHED_TO_SERVER 0x89F8 */
+
+/**** Network errors ****/
+/* Decimal values at end of line are 32768 lower than actual */
+
+#define NWE_ALREADY_ATTACHED 0x8800 /* 0 - Attach attempted to server with valid, existing connection */
+#define NWE_CONN_INVALID 0x8801 /* 1 - Request attempted with invalid or non-attached connection handle */
+#define NWE_DRIVE_IN_USE 0x8802 /* 2 - OS/2 only (NOT USED) */
+#define NWE_DRIVE_CANNOT_MAP 0x8803 /* 3 - Map drive attempted but unable to add new current directory structure */
+#define NWE_DRIVE_BAD_PATH 0x8804 /* 4 - Map drive attempted with invalid path specification */
+#define NWE_NET_RECEIVE 0x8805 /* 5 - Attempt to receive from the selected transport failed */
+#define NWE_NET_UNKNOWN 0x8806 /* 6 - Network send attempted with an un-specific network error */
+#define NWE_SERVER_BAD_SLOT 0x8807 /* 7 - Server request attempted with invalid server connection slot */
+#define NWE_SERVER_NO_SLOTS 0x8808 /* 8 - Attach attempted to server with no connection slots available */
+#define NWE_NET_SEND 0x8809 /* 9 - Attempt to send on the selected transport failed */
+#define NWE_SERVER_NO_ROUTE 0x880A /* 10 - Attempted to find route to server where no route exists */
+#define NWE_BAD_LOCAL_TARGET 0x880B /* 11 - OS/2 only */
+#define NWE_REQ_TOO_MANY_REQ_FRAGS 0x880C /* 12 - Attempted request with too many request fragments specified */
+#define NWE_CONN_LIST_OVERFLOW 0x880D /* 13 */
+#define NWE_BUFFER_OVERFLOW 0x880E /* 14 - Attempt to receive more data than the reply buffer had room for */
+#define NWE_SERVER_NO_CONN 0x880F /* 15 - Attempt to get connection for a server not connected */
+#define NWE_NO_ROUTER_FOUND 0x8810 /* 16 - OS/2 only */
+#define NWE_FUNCTION_INVALID 0x8811 /* 17 - Attempted function call to non- existent or illegal function */
+#define NWE_SCAN_COMPLETE 0x8812
+#define NWE_UNSUPPORTED_NAME_FORMAT_TYP 0x8813
+#define NWE_HANDLE_ALREADY_LICENSED 0x8814
+#define NWE_HANDLE_ALREADY_UNLICENSED 0x8815
+#define NWE_INVALID_NCP_PACKET_LENGTH 0x8816
+#define NWE_SETTING_UP_TIMEOUT 0x8817
+#define NWE_SETTING_SIGNALS 0x8818
+#define NWE_SERVER_CONNECTION_LOST 0x8819
+#define NWE_OUT_OF_HEAP_SPACE 0x881A
+#define NWE_INVALID_SERVICE_REQUEST 0x881B
+#define NWE_INVALID_TASK_NUMBER 0x881C
+#define NWE_INVALID_MESSAGE_LENGTH 0x881D
+#define NWE_EA_SCAN_DONE 0x881E
+#define NWE_BAD_CONNECTION_NUMBER 0x881F
+#define NWE_MULT_TREES_NOT_SUPPORTED 0x8820 /* 32 - Attempt to open a connection to a DS tree other than the default tree */
+#define NWE_CONN_NOT_SAME 0x8830 /* 48 - Internal server request attempted across different server connections */
+#define NWE_CONN_PRIMARY_NOT_SET 0x8831 /* 49 - Attempt to retrieve default connection with no primary connection set */
+#define NWE_PRN_CAPTURE_NOT_IN_PROGRESS 0x8832 /* 50 - Capture information requested on port with no capture in progress */
+#define NWE_BUFFER_INVALID_LEN 0x8833 /* 51 - Used to indicate length which caller requested on a GetDNC or SetDNC was too large */
+#define NWE_USER_NO_NAME 0x8834 /* 52 */
+#define NWE_PRN_NO_LOCAL_SPOOLER 0x8835 /* 53 - Capture requested without having the local print spooler installed */
+#define NWE_PARAM_INVALID 0x8836 /* 54 - Attempted function with an invalid function parameter specified */
+#define NWE_CFG_OPEN_FAILED 0x8837 /* 55 - OS/2 only */
+#define NWE_CFG_NO_FILE 0x8838 /* 56 - OS/2 only */
+#define NWE_CFG_READ_FAILED 0x8839 /* 57 - OS/2 only */
+#define NWE_CFG_LINE_TOO_LONG 0x883A /* 58 - OS/2 only */
+#define NWE_CFG_LINES_IGNORED 0x883B /* 59 - OS/2 only */
+#define NWE_RESOURCE_NOT_OWNED 0x883C /* 60 - Attempted request made with a parameter using foriegn resource */
+#define NWE_DAEMON_INSTALLED 0x883D /* 61 - OS/2 only */
+#define NWE_PRN_SPOOLER_INSTALLED 0x883E /* 62 - Attempted load of print spooler with print spooler already installed */
+#define NWE_CONN_TABLE_FULL 0x883F /* 63 - Attempted to allocate a connection handle with no more local connection table entries */
+#define NWE_CFG_SECTION_NOT_FOUND 0x8840 /* 64 - OS/2 only */
+#define NWE_TRAN_INVALID_TYPE 0x8841 /* 65 - Attempted function on a connection with an invalid transport selected */
+#define NWE_TDS_TAG_IN_USE 0x8842 /* 66 - OS/2 only */
+#define NWE_TDS_OUT_OF_MEMORY 0x8843 /* 67 - OS/2 only */
+#define NWE_TDS_INVALID_TAG 0x8844 /* 68 - Attempted TDS function with invalid tag */
+#define NWE_TDS_WRITE_TRUNCATED 0x8845 /* 69 - Attempted TDS write with buffer that exceeded buffer */
+#define NWE_DS_NO_CONN 0x8846 /* 70 */
+#define NWE_SERVICE_BUSY 0x8846 /* 70 - Attempted request made to partially asynchronous function in busy state */
+#define NWE_SERVER_NOT_FOUND 0x8847 /* 71 - Attempted connect failed to find any servers responding */
+#define NWE_VLM_INVALID 0x8848 /* 72 - Attempted function call to non-existant or not-loaded overlay */
+#define NWE_DRIVE_ALREADY_MAPPED 0x8849 /* 73 - Attempted map to network drive that was already mapped */
+#define NWE_DRIVE_LOCAL_IN_USE 0x884A /* 74 - Attempted map to local drive that was in use */
+#define NWE_DRIVE_NONE_AVAILABLE 0x884B /* 75 - Attempted map to next available drive when none were available */
+#define NWE_DEVICE_NOT_REDIRECTED 0x884C /* 76 - The device is not redirected */
+#define NWE_FILE_MAX_REACHED 0x884D /* 77 - Maximum number of files was reached */
+#define NWE_UNLOAD_FAILED 0x884E /* 78 - Attempted unload failed */
+#define NWE_CONN_IN_USE 0x884F /* 79 - Attempted re-use of already in use connection entry */
+#define NWE_REQ_TOO_MANY_REP_FRAGS 0x8850 /* 80 - Attempted request with too many reply fragments specified */
+#define NWE_NAME_TABLE_FULL 0x8851 /* 81 - Attempted to add a name into the name table after it was full */
+#define NWE_SOCKET_NOT_OPEN 0x8852 /* 82 - Listen was posted on unopened socket */
+#define NWE_MEMORY_MGR_ERROR 0x8853 /* 83 - Attempted enhanced memory operation failed */
+#define NWE_SFT3_ERROR 0x8854 /* 84 - An SFT3 switch occured mid-transfer */
+#define NWE_DS_PREFERRED_NOT_FOUND 0x8855 /* 85 - the preferred directory server was not established but another directory server was returned */
+#define NWE_DEVICE_NOT_RECOGNIZED 0x8856 /* 86 - used to determine if the device is not used by VISE so pass it on to the next redirector, if any. */
+#define NWE_NET_INVALID_TYPE 0x8857 /* 87 - the network type (Bind/NDS) does not match the server version */
+#define NWE_FILE_OPEN_FAILED 0x8858 /* 88 - generic open failure error, invalid path, access denied, etc.. */
+#define NWE_DS_PREFERRED_NOT_SPECIFIED 0x8859 /* 89 - no preferred name specified */
+#define NWE_SOCKET_OPEN_FAILED 0x885A /* 90 - error opening a socket */
+#define NWE_SIGNATURE_LEVEL_CONFLICT 0x8861
+#define NWE_NO_LOCK_FOUND 0x8862 /* OS/2 - process lock on conn handle failed, process ID not recognized */
+#define NWE_LOCK_TABLE_FULL 0x8863 /* OS/2 - process lock on conn handle failed, process lock table full */
+#define NWE_INVALID_MATCH_DATA 0x8864
+#define NWE_MATCH_FAILED 0x8865
+#define NWE_NO_MORE_ENTRIES 0x8866
+#define NWE_INSUFFICIENT_RESOURCES 0x8867
+#define NWE_STRING_TRANSLATION 0x8868
+#define NWE_ACCESS_VIOLATION 0x8869
+#define NWE_NOT_AUTHENTICATED 0x886A
+#define NWE_INVALID_LEVEL 0x886B
+#define NWE_RESOURCE_LOCK 0x886C
+#define NWE_INVALID_NAME_FORMAT 0x886D
+#define NWE_OBJECT_EXISTS 0x886E
+#define NWE_OBJECT_NOT_FOUND 0x886F
+#define NWE_UNSUPPORTED_TRAN_TYPE 0x8870
+#define NWE_INVALID_STRING_TYPE 0x8871
+#define NWE_INVALID_OWNER 0x8872
+#define NWE_UNSUPPORTED_AUTHENTICATOR 0x8873
+#define NWE_IO_PENDING 0x8874
+#define NWE_INVALID_DRIVE_NUMBER 0x8875
+#define NWE_REPLY_TRUNCATED 0x88e6 /* 230 NLM */
+#define NWE_REQUESTER_FAILURE 0x88FF
+
+/* Server Errors */
+
+#define NWE_INSUFFICIENT_SPACE 0x8901 /* 001 */
+#define NWE_BUFFER_TOO_SMALL 0x8977 /* 119 */
+#define NWE_VOL_FLAG_NOT_SET 0x8978 /* 120 the service requested, not avail. on the selected vol. */
+#define NWE_NO_ITEMS_FOUND 0x8979 /* 121 */
+#define NWE_CONN_ALREADY_TEMP 0x897a /* 122 */
+#define NWE_CONN_ALREADY_LOGGED_IN 0x897b /* 123 */
+#define NWE_CONN_NOT_AUTHENTICATED 0x897c /* 124 */
+#define NWE_CONN_NOT_LOGGED_IN 0x897d /* 125 */
+#define NWE_NCP_BOUNDARY_CHECK_FAILED 0x897e /* 126 */
+#define NWE_LOCK_WAITING 0x897f /* 127 */
+#define NWE_LOCK_FAIL 0x8980 /* 128 */
+#define NWE_FILE_IN_USE 0x8980 /* 128 */
+#define NWE_FILE_NO_HANDLES 0x8981 /* 129 */
+#define NWE_FILE_NO_OPEN_PRIV 0x8982 /* 130 */
+#define NWE_DISK_IO_ERROR 0x8983 /* 131 */
+#define NWE_AUDITING_HARD_IO_ERROR 0x8983 /* 131 */
+#define NWE_FILE_NO_CREATE_PRIV 0x8984 /* 132 */
+#define NWE_AUDITING_NOT_SUPV 0x8984 /* 132 */
+#define NWE_FILE_NO_CREATE_DEL_PRIV 0x8985 /* 133 */
+#define NWE_FILE_EXISTS_READ_ONLY 0x8986 /* 134 */
+#define NWE_FILE_WILD_CARDS_IN_NAME 0x8987 /* 135 */
+#define NWE_FILE_INVALID_HANDLE 0x8988 /* 136 */
+#define NWE_FILE_NO_SRCH_PRIV 0x8989 /* 137 */
+#define NWE_FILE_NO_DEL_PRIV 0x898A /* 138 */
+#define NWE_FILE_NO_RENAME_PRIV 0x898B /* 139 */
+#define NWE_FILE_NO_MOD_PRIV 0x898C /* 140 */
+#define NWE_FILE_SOME_IN_USE 0x898D /* 141 */
+#define NWE_FILE_NONE_IN_USE 0x898E /* 142 */
+#define NWE_FILE_SOME_READ_ONLY 0x898F /* 143 */
+#define NWE_FILE_NONE_READ_ONLY 0x8990 /* 144 */
+#define NWE_FILE_SOME_RENAMED_EXIST 0x8991 /* 145 */
+#define NWE_FILE_NONE_RENAMED_EXIST 0x8992 /* 146 */
+#define NWE_FILE_NO_READ_PRIV 0x8993 /* 147 */
+#define NWE_FILE_NO_WRITE_PRIV 0x8994 /* 148 */
+#define NWE_FILE_READ_ONLY 0x8994 /* 148 */
+#define NWE_FILE_DETACHED 0x8995 /* 149 */
+#define NWE_SERVER_OUT_OF_MEMORY 0x8996 /* 150 */
+#define NWE_DIR_TARGET_INVALID 0x8996 /* 150 */
+#define NWE_DISK_NO_SPOOL_SPACE 0x8997 /* 151 */
+#define NWE_AUDITING_NOT_ENABLED 0x8997 /* 151 */
+#define NWE_VOL_INVALID 0x8998 /* 152 */
+#define NWE_DIR_FULL 0x8999 /* 153 */
+#define NWE_VOL_RENAMING_ACROSS 0x899A /* 154 */
+#define NWE_DIRHANDLE_INVALID 0x899B /* 155 */
+#define NWE_PATH_INVALID 0x899C /* 156 */
+#define NWE_TRUSTEES_NO_MORE 0x899C /* 156 */
+#define NWE_DIRHANDLE_NO_MORE 0x899D /* 157 */
+#define NWE_FILE_NAME_INVALID 0x899E /* 158 */
+#define NWE_DIR_ACTIVE 0x899F /* 159 */
+#define NWE_DIR_NOT_EMPTY 0x89A0 /* 160 */
+#define NWE_DIR_IO_ERROR 0x89A1 /* 161 */
+#define NWE_FILE_IO_LOCKED 0x89A2 /* 162 */
+#define NWE_TTS_RANSACTION_RESTARTED 0x89A3 /* 163 */
+#define NWE_TTS_TRANSACTION_RESTARTED 0x89A3 /* 163 */
+#define NWE_DIR_RENAME_INVALID 0x89A4 /* 164 */
+#define NWE_FILE_OPENCREAT_MODE_INVALID 0x89A5 /* 165 */
+#define NWE_ALREADY_IN_USE 0x89A6 /* 166 */
+#define NWE_AUDITING_ACTIVE 0x89A6 /* 166 */
+#define NWE_RESOURCE_TAG_INVALID 0x89A7 /* 167 */
+#define NWE_ACCESS_DENIED 0x89A8 /* 168 */
+#define NWE_AUDITING_NO_RIGHTS 0x89A8 /* 168 */
+#define NWE_DATA_STREAM_INVALID 0x89BE /* 190 */
+#define NWE_NAME_SPACE_INVALID 0x89BF /* 191 */
+#define NWE_ACCTING_NO_PRIV 0x89C0 /* 192 */
+#define NWE_ACCTING_NO_BALANCE 0x89C1 /* 193 */
+#define NWE_ACCTING_NO_CREDIT 0x89C2 /* 194 */
+#define NWE_AUDITING_RECORD_SIZE 0x89C2 /* 194 */
+#define NWE_ACCTING_TOO_MANY_HOLDS 0x89C3 /* 195 */
+#define NWE_ACCTING_DISABLED 0x89C4 /* 196 */
+#define NWE_LOGIN_LOCKOUT 0x89C5 /* 197 */
+#define NWE_CONSOLE_NO_PRIV 0x89C6 /* 198 */
+#define NWE_Q_IO_FAILURE 0x89D0 /* 208 */
+#define NWE_Q_NONE 0x89D1 /* 209 */
+#define NWE_Q_NO_SERVER 0x89D2 /* 210 */
+#define NWE_Q_NO_RIGHTS 0x89D3 /* 211 */
+#define NWE_Q_FULL 0x89D4 /* 212 */
+#define NWE_Q_NO_JOB 0x89D5 /* 213 */
+#define NWE_Q_NO_JOB_RIGHTS 0x89D6 /* 214 */
+#define NWE_PASSWORD_UNENCRYPTED 0x89D6 /* 214 */
+#define NWE_Q_IN_SERVICE 0x89D7 /* 215 */
+#define NWE_PASSWORD_NOT_UNIQUE 0x89D7 /* 215 */
+#define NWE_Q_NOT_ACTIVE 0x89D8 /* 216 */
+#define NWE_PASSWORD_TOO_SHORT 0x89D8 /* 216 */
+#define NWE_Q_STN_NOT_SERVER 0x89D9 /* 217 */
+#define NWE_LOGIN_NO_CONN 0x89D9 /* 217 */
+#define NWE_LOGIN_MAX_EXCEEDED 0x89D9 /* 217 */
+#define NWE_Q_HALTED 0x89DA /* 218 */
+#define NWE_LOGIN_UNAUTHORIZED_TIME 0x89DA /* 218 */
+#define NWE_LOGIN_UNAUTHORIZED_STATION 0x89DB /* 219 */
+#define NWE_Q_MAX_SERVERS 0x89DB /* 219 */
+#define NWE_ACCT_DISABLED 0x89DC /* 220 */
+#define NWE_PASSWORD_INVALID 0x89DE /* 222 */
+#define NWE_PASSWORD_EXPIRED 0x89DF /* 223 */
+#define NWE_LOGIN_NO_CONN_AVAIL 0x89E0 /* 224 */
+#define NWE_E_NO_MORE_USERS 0x89E7 /* 231 */
+#define NWE_BIND_NOT_ITEM_PROP 0x89E8 /* 232 */
+#define NWE_BIND_WRITE_TO_GROUP_PROP 0x89E8 /* 232 */
+#define NWE_BIND_MEMBER_ALREADY_EXISTS 0x89E9 /* 233 */
+#define NWE_BIND_NO_SUCH_MEMBER 0x89EA /* 234 */
+#define NWE_BIND_NOT_GROUP_PROP 0x89EB /* 235 */
+#define NWE_BIND_NO_SUCH_SEGMENT 0x89EC /* 236 */
+#define NWE_BIND_PROP_ALREADY_EXISTS 0x89ED /* 237 */
+#define NWE_BIND_OBJ_ALREADY_EXISTS 0x89EE /* 238 */
+#define NWE_BIND_NAME_INVALID 0x89EF /* 239 */
+#define NWE_BIND_WILDCARD_INVALID 0x89F0 /* 240 */
+#define NWE_BIND_SECURITY_INVALID 0x89F1 /* 241 */
+#define NWE_BIND_OBJ_NO_READ_PRIV 0x89F2 /* 242 */
+#define NWE_BIND_OBJ_NO_RENAME_PRIV 0x89F3 /* 243 */
+#define NWE_BIND_OBJ_NO_DELETE_PRIV 0x89F4 /* 244 */
+#define NWE_BIND_OBJ_NO_CREATE_PRIV 0x89F5 /* 245 */
+#define NWE_BIND_PROP_NO_DELETE_PRIV 0x89F6 /* 246 */
+#define NWE_BIND_PROP_NO_CREATE_PRIV 0x89F7 /* 247 */
+#define NWE_BIND_PROP_NO_WRITE_PRIV 0x89F8 /* 248 */
+#define NWE_BIND_PROP_NO_READ_PRIV 0x89F9 /* 249 */
+#define NWE_NO_FREE_CONN_SLOTS 0x89F9 /* 249 */
+#define NWE_NO_MORE_SERVER_SLOTS 0x89FA /* 250 */
+#define NWE_TEMP_REMAP_ERROR 0x89FA /* 250 */
+#define NWE_PARAMETERS_INVALID 0x89FB /* 251 */
+#define NWE_BIND_NO_SUCH_PROP 0x89FB /* 251 */
+#define NWE_NCP_NOT_SUPPORTED 0x89FB /* 251 */
+#define NWE_INET_PACKET_REQ_CANCELED 0x89FC /* 252 */
+#define NWE_SERVER_UNKNOWN 0x89FC /* 252 */
+#define NWE_MSG_Q_FULL 0x89FC /* 252 */
+#define NWE_BIND_NO_SUCH_OBJ 0x89FC /* 252 */
+#define NWE_LOCK_COLLISION 0x89FD /* 253 */
+#define NWE_CONN_NUM_INVALID 0x89FD /* 253 */
+#define NWE_PACKET_LEN_INVALID 0x89FD /* 253 */
+#define NWE_UNKNOWN_REQ 0x89FD /* 253 */
+#define NWE_BIND_LOCKED 0x89FE /* 254 */
+#define NWE_TRUSTEE_NOT_FOUND 0x89FE /* 254 */
+#define NWE_DIR_LOCKED 0x89FE /* 254 */
+#define NWE_SEM_INVALID_NAME_LEN 0x89FE /* 254 */
+#define NWE_PACKET_NOT_DELIVERABLE 0x89FE /* 254 */
+#define NWE_SOCKET_TABLE_FULL 0x89FE /* 254 */
+#define NWE_SPOOL_DIR_ERROR 0x89FE /* 254 */
+#define NWE_LOGIN_DISABLED_BY_SUPER 0x89FE /* 254 */
+#define NWE_TIMEOUT_FAILURE 0x89FE /* 254 */
+#define NWE_FILE_EXT 0x89FF /* 255 */
+#define NWE_FILE_NAME 0x89FF /* 255 */
+#define NWE_HARD_FAILURE 0x89FF /* 255 */
+#define NWE_FCB_CLOSE 0x89FF /* 255 */
+#define NWE_IO_BOUND 0x89FF /* 255 */
+#define NWE_BAD_SPOOL_PRINTER 0x89FF /* 255 */
+#define NWE_BAD_RECORD_OFFSET 0x89FF /* 255 */
+#define NWE_DRIVE_INVALID_NUM 0x89FF /* 255 */
+#define NWE_SEM_INVALID_INIT_VAL 0x89FF /* 255 */
+#define NWE_SEM_INVALID_HANDLE 0x89FF /* 255 */
+#define NWE_NO_FILES_FOUND_ERROR 0x89FF /* 255 */
+#define NWE_NO_RESPONSE_FROM_SERVER 0x89FF /* 255 */
+#define NWE_NO_OBJ_OR_BAD_PASSWORD 0x89FF /* 255 */
+#define NWE_PATH_NOT_LOCATABLE 0x89FF /* 255 */
+#define NWE_Q_FULL_ERROR 0x89FF /* 255 */
+#define NWE_REQ_NOT_OUTSTANDING 0x89FF /* 255 */
+#define NWE_SOCKET_ALREADY_OPEN 0x89FF /* 255 */
+#define NWE_LOCK_ERROR 0x89FF /* 255 */
+#define NWE_FAILURE 0x89FF /* 255 Generic Failure */
+
+#endif /* !_NWERROR_H_ */
diff --git a/sys/nwfs/nwfs.h b/sys/nwfs/nwfs.h
new file mode 100644
index 0000000..950d18a
--- /dev/null
+++ b/sys/nwfs/nwfs.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NWFS_H_
+#define _NWFS_H_
+
+#include <nwfs/nwfs_mount.h>
+
+#define NR_OPEN 0
+#define NW_NSB_DOS (1 << NW_NS_DOS)
+#define NW_NSB_MAC (1 << NW_NS_MAC)
+#define NW_NSB_NFS (1 << NW_NS_NFS)
+#define NW_NSB_FTAM (1 << NW_NS_FTAM)
+#define NW_NSB_OS2 (1 << NW_NS_OS2)
+
+#define NWFSIOC_GETCONN _IOR('n',1,int)
+#define NWFSIOC_GETEINFO _IOR('n',2,struct nw_entry_info)
+#define NWFSIOC_GETNS _IOR('n',3,int)
+
+#ifdef KERNEL
+
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+struct nwfsnode;
+
+struct nwmount {
+ struct nwfs_args m;
+ struct mount *mp;
+ struct ncp_handle *connh;
+ int name_space;
+ struct nwnode *n_root;
+ u_int32_t n_volume;
+ ncpfid n_rootent;
+ int n_id;
+};
+
+#define VFSTONWFS(mntp) ((struct nwmount *)((mntp)->mnt_data))
+#define NWFSTOVFS(mnp) ((struct mount *)((mnp)->mount))
+#define VTOVFS(vp) ((vp)->v_mount)
+#define VTONWFS(vp) (VFSTONWFS(VTOVFS(vp)))
+#define NWFSTOCONN(nmp) ((nmp)->connh->nh_conn)
+
+int ncp_conn_logged_in(struct nwmount *);
+int nwfs_ioctl(struct vop_ioctl_args *ap);
+int nwfs_doio(struct buf *bp, struct ucred *cr, struct proc *p);
+int nwfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
+ struct proc *p, int intrflg);
+#endif /* KERNEL */
+
+#endif /* _NWFS_H_ */
diff --git a/sys/nwfs/nwfs_io.c b/sys/nwfs/nwfs_io.c
new file mode 100644
index 0000000..21339b3
--- /dev/null
+++ b/sys/nwfs/nwfs_io.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+
+#include <sys/ioccom.h>
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+static int nwfs_fastlookup = 1;
+
+extern struct linker_set sysctl_vfs_nwfs;
+
+SYSCTL_DECL(_vfs_nwfs);
+SYSCTL_INT(_vfs_nwfs, OID_AUTO, fastlookup, CTLFLAG_RW, &nwfs_fastlookup, 0, "");
+
+
+extern int nwfs_pbuf_freecnt;
+
+#define DE_SIZE (sizeof(struct dirent))
+#define NWFS_RWCACHE
+
+static int
+nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) {
+ struct nwmount *nmp = VTONWFS(vp);
+ int error, count, i, len;
+ struct dirent dp;
+ struct nwnode *np = VTONW(vp);
+ struct nw_entry_info fattr;
+ struct vnode *newvp;
+ struct nameidata nami, *ndp = &nami;
+ struct componentname *cnp = &ndp->ni_cnd;
+ ncpfid fid;
+ u_char *cp;
+
+ np = VTONW(vp);
+ NCPVNDEBUG("dirname='%s'\n",np->n_name);
+ if (uio->uio_resid < DE_SIZE || (uio->uio_offset < 0))
+ return (EINVAL);
+ error = 0;
+ count = 0;
+ ndp->ni_dvp = vp;
+ i = uio->uio_offset / DE_SIZE; /* offset in directory */
+ if (i == 0) {
+ error = ncp_initsearch(vp, uio->uio_procp, cred);
+ if (error) {
+ NCPVNDEBUG("cannot initialize search, error=%d",error);
+ return( error );
+ }
+ }
+
+ for (; uio->uio_resid >= DE_SIZE; i++) {
+ bzero((char *) &dp, DE_SIZE);
+ dp.d_reclen = DE_SIZE;
+ switch (i) {
+ case 0: /* `.' */
+ case 1: /* `..' */
+ dp.d_fileno = (i == 0) ? np->n_fid.f_id : np->n_parent.f_id;
+ if (!dp.d_fileno) dp.d_fileno = NWFS_ROOT_INO;
+ dp.d_namlen = i + 1;
+ dp.d_name[0] = '.';
+ dp.d_name[1] = '.';
+ dp.d_name[i + 1] = '\0';
+ dp.d_type = DT_DIR;
+ break;
+ default:
+ error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_procp, cred);
+ if (error && error < 0x80) break;
+ dp.d_fileno = fattr.dirEntNum;
+ dp.d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG;
+ dp.d_namlen = fattr.nameLen;
+ bcopy(fattr.entryName, dp.d_name, dp.d_namlen);
+ dp.d_name[dp.d_namlen] = '\0';
+#if 0
+ if (error && eofflag) {
+ /* *eofflag = 1;*/
+ break;
+ }
+#endif
+ break;
+ }
+ if (nwfs_fastlookup && !error && i > 1) {
+ fid.f_id = fattr.dirEntNum;
+ fid.f_parent = np->n_fid.f_id;
+ error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp);
+ if (!error) {
+ VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec;
+ cnp->cn_nameptr = dp.d_name;
+ len = cnp->cn_namelen = dp.d_namlen;
+ ndp->ni_vp = newvp;
+ cnp->cn_hash = 0;
+ for (cp = cnp->cn_nameptr; len; len--, cp++)
+ cnp->cn_hash += *cp;
+ cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
+ vput(newvp);
+ } else
+ error = 0;
+ }
+ if (error >= 0x80) {
+ error = 0;
+ break;
+ }
+ if ((error = uiomove((caddr_t)&dp, DE_SIZE, uio)))
+ break;
+ }
+
+ uio->uio_offset = i * DE_SIZE;
+ return (error);
+}
+
+int
+nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred) {
+ struct nwmount *nmp = VFSTONWFS(vp->v_mount);
+ struct nwnode *np = VTONW(vp);
+ struct proc *p;
+ struct vattr vattr;
+ int error, biosize;
+
+ if (vp->v_type != VREG && vp->v_type != VDIR) {
+ printf("%s: vn types other than VREG or VDIR are unsupported !\n",__FUNCTION__);
+ return EIO;
+ }
+ if (uiop->uio_resid == 0) return 0;
+ if (uiop->uio_offset < 0) return EINVAL;
+/* if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
+ return (EFBIG);*/
+ p = uiop->uio_procp;
+ if (vp->v_type == VDIR) {
+ error = nwfs_readvdir(vp, uiop, cred);
+ return error;
+ }
+ biosize = NWFSTOCONN(nmp)->buffer_size;
+ if (np->n_flag & NMODIFIED) {
+ nwfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ } else {
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+ if (np->n_mtime != vattr.va_mtime.tv_sec) {
+ error = nwfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error) return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ }
+ }
+ error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop,cred);
+ return (error);
+}
+
+int
+nwfs_writevnode(vp, uiop, cred, ioflag)
+ register struct vnode *vp;
+ register struct uio *uiop;
+ struct ucred *cred;
+ int ioflag;
+{
+ struct nwmount *nmp = VTONWFS(vp);
+ struct nwnode *np = VTONW(vp);
+ struct proc *p;
+/* struct vattr vattr;*/
+ int error = 0;
+
+ if (vp->v_type != VREG) {
+ printf("%s: vn types other than VREG unsupported !\n",__FUNCTION__);
+ return EIO;
+ }
+ NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
+ if (uiop->uio_offset < 0) return EINVAL;
+/* if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
+ return (EFBIG);*/
+ p = uiop->uio_procp;
+ if (ioflag & (IO_APPEND | IO_SYNC)) {
+ if (np->n_flag & NMODIFIED) {
+ nwfs_attr_cacheremove(vp);
+ error = nwfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error) return (error);
+ }
+ if (ioflag & IO_APPEND) {
+ /* We can relay only on local information about file size,
+ * because until file is closed NetWare will not return
+ * the correct size. */
+#if notyet
+ nwfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+#endif
+ uiop->uio_offset = np->n_size;
+ }
+ }
+ if (uiop->uio_resid == 0) return 0;
+ if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ psignal(p, SIGXFSZ);
+ return (EFBIG);
+ }
+ error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
+ NCPVNDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
+ if (!error) {
+ if (uiop->uio_offset > np->n_size) {
+ np->n_vattr.va_size = np->n_size = uiop->uio_offset;
+ vnode_pager_setsize(vp, np->n_size);
+ }
+ }
+ return (error);
+}
+
+/*
+ * Do an I/O operation to/from a cache block.
+ */
+int
+nwfs_doio(bp, cr, p)
+ register struct buf *bp;
+ struct ucred *cr;
+ struct proc *p;
+{
+ register struct uio *uiop;
+ register struct vnode *vp;
+ struct nwnode *np;
+ struct nwmount *nmp;
+ int error = 0;
+ struct uio uio;
+ struct iovec io;
+
+ vp = bp->b_vp;
+ np = VTONW(vp);
+ nmp = VFSTONWFS(vp->v_mount);
+ uiop = &uio;
+ uiop->uio_iov = &io;
+ uiop->uio_iovcnt = 1;
+ uiop->uio_segflg = UIO_SYSSPACE;
+ uiop->uio_procp = p;
+ if (bp->b_flags & B_READ) {
+ io.iov_len = uiop->uio_resid = bp->b_bcount;
+ io.iov_base = bp->b_data;
+ uiop->uio_rw = UIO_READ;
+ switch (vp->v_type) {
+ case VREG:
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
+ error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
+ if (error)
+ break;
+ if (uiop->uio_resid) {
+ int left = uiop->uio_resid;
+ int nread = bp->b_bcount - left;
+ if (left > 0)
+ bzero((char *)bp->b_data + nread, left);
+ }
+ break;
+/* case VDIR:
+ nfsstats.readdir_bios++;
+ uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
+ if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
+ error = nfs_readdirplusrpc(vp, uiop, cr);
+ if (error == NFSERR_NOTSUPP)
+ nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
+ }
+ if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
+ error = nfs_readdirrpc(vp, uiop, cr);
+ if (error == 0 && uiop->uio_resid == bp->b_bcount)
+ bp->b_flags |= B_INVAL;
+ break;
+*/
+ default:
+ printf("nwfs_doio: type %x unexpected\n",vp->v_type);
+ break;
+ };
+ if (error) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = error;
+ }
+ } else { /* write */
+ if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
+ bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
+
+ if (bp->b_dirtyend > bp->b_dirtyoff) {
+ io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
+ io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
+ uiop->uio_rw = UIO_WRITE;
+ bp->b_flags |= B_WRITEINPROG;
+ error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
+ bp->b_flags &= ~B_WRITEINPROG;
+
+ /*
+ * For an interrupted write, the buffer is still valid
+ * and the write hasn't been pushed to the server yet,
+ * so we can't set B_ERROR and report the interruption
+ * by setting B_EINTR. For the B_ASYNC case, B_EINTR
+ * is not relevant, so the rpc attempt is essentially
+ * a noop. For the case of a V3 write rpc not being
+ * committed to stable storage, the block is still
+ * dirty and requires either a commit rpc or another
+ * write rpc with iomode == NFSV3WRITE_FILESYNC before
+ * the block is reused. This is indicated by setting
+ * the B_DELWRI and B_NEEDCOMMIT flags.
+ */
+ if (error == EINTR
+ || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
+ int s;
+
+ s = splbio();
+ bp->b_flags &= ~(B_INVAL|B_NOCACHE);
+ if ((bp->b_flags & B_ASYNC) == 0)
+ bp->b_flags |= B_EINTR;
+ if ((bp->b_flags & B_PAGING) == 0) {
+ bdirty(bp);
+ bp->b_flags &= ~B_DONE;
+ }
+ if ((bp->b_flags & B_ASYNC) == 0)
+ bp->b_flags |= B_EINTR;
+ splx(s);
+ } else {
+ if (error) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error /*= np->n_error */= error;
+/* np->n_flag |= NWRITEERR;*/
+ }
+ bp->b_dirtyoff = bp->b_dirtyend = 0;
+ }
+ } else {
+ bp->b_resid = 0;
+ biodone(bp);
+ return (0);
+ }
+ }
+ bp->b_resid = uiop->uio_resid;
+ biodone(bp);
+ return (error);
+}
+
+/*
+ * Vnode op for VM getpages.
+ * Wish wish .... get rid from multiple IO routines
+ */
+int
+nwfs_getpages(ap)
+ struct vop_getpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_reqpage;
+ vm_ooffset_t a_offset;
+ } */ *ap;
+{
+#ifndef NWFS_RWCACHE
+ return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
+ ap->a_reqpage);
+#else
+ int i, error, nextoff, size, toff, npages, count;
+ struct uio uio;
+ struct iovec iov;
+ vm_offset_t kva;
+ struct buf *bp;
+ struct vnode *vp;
+ struct proc *p;
+ struct ucred *cred;
+ struct nwmount *nmp;
+ struct nwnode *np;
+ vm_page_t *pages;
+
+ vp = ap->a_vp;
+ p = curproc; /* XXX */
+ cred = curproc->p_ucred; /* XXX */
+ np = VTONW(vp);
+ nmp = VFSTONWFS(vp->v_mount);
+ pages = ap->a_m;
+ count = ap->a_count;
+
+ if (vp->v_object == NULL) {
+ printf("nwfs_getpages: called with non-merged cache vnode??\n");
+ return VM_PAGER_ERROR;
+ }
+
+ bp = getpbuf(&nwfs_pbuf_freecnt);
+ npages = btoc(count);
+ kva = (vm_offset_t) bp->b_data;
+ pmap_qenter(kva, pages, npages);
+
+ iov.iov_base = (caddr_t) kva;
+ iov.iov_len = count;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+ uio.uio_resid = count;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+
+ error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, &uio,cred);
+ pmap_qremove(kva, npages);
+
+ relpbuf(bp, &nwfs_pbuf_freecnt);
+
+ if (error && (uio.uio_resid == count)) {
+ printf("nwfs_getpages: error %d\n",error);
+ for (i = 0; i < npages; i++) {
+ if (ap->a_reqpage != i)
+ vnode_pager_freepage(pages[i]);
+ }
+ return VM_PAGER_ERROR;
+ }
+
+ size = count - uio.uio_resid;
+
+ for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
+ vm_page_t m;
+ nextoff = toff + PAGE_SIZE;
+ m = pages[i];
+
+ m->flags &= ~PG_ZERO;
+
+ if (nextoff <= size) {
+ m->valid = VM_PAGE_BITS_ALL;
+ m->dirty = 0;
+ } else {
+ int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
+ vm_page_set_validclean(m, 0, nvalid);
+ }
+
+ if (i != ap->a_reqpage) {
+ /*
+ * Whether or not to leave the page activated is up in
+ * the air, but we should put the page on a page queue
+ * somewhere (it already is in the object). Result:
+ * It appears that emperical results show that
+ * deactivating pages is best.
+ */
+
+ /*
+ * Just in case someone was asking for this page we
+ * now tell them that it is ok to use.
+ */
+ if (!error) {
+ if (m->flags & PG_WANTED)
+ vm_page_activate(m);
+ else
+ vm_page_deactivate(m);
+ vm_page_wakeup(m);
+ } else {
+ vnode_pager_freepage(m);
+ }
+ }
+ }
+ return 0;
+#endif /* NWFS_RWCACHE */
+}
+
+/*
+ * Vnode op for VM putpages.
+ * possible bug: all IO done in sync mode
+ * Note that vop_close always invalidate pages before close, so it's
+ * not necessary to open vnode.
+ */
+int
+nwfs_putpages(ap)
+ struct vop_putpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_sync;
+ int *a_rtvals;
+ vm_ooffset_t a_offset;
+ } */ *ap;
+{
+ int error;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p;
+ struct ucred *cred;
+
+#ifndef NWFS_RWCACHE
+ p = curproc; /* XXX */
+ cred = p->p_ucred; /* XXX */
+ VOP_OPEN(vp, FWRITE, cred, p);
+ error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
+ ap->a_sync, ap->a_rtvals);
+ VOP_CLOSE(vp, FWRITE, cred, p);
+ return error;
+#else
+ struct uio uio;
+ struct iovec iov;
+ vm_offset_t kva;
+ struct buf *bp;
+ int i, npages, count;
+ int *rtvals;
+ struct nwmount *nmp;
+ struct nwnode *np;
+ vm_page_t *pages;
+
+ p = curproc; /* XXX */
+ cred = p->p_ucred; /* XXX */
+/* VOP_OPEN(vp, FWRITE, cred, p);*/
+ np = VTONW(vp);
+ nmp = VFSTONWFS(vp->v_mount);
+ pages = ap->a_m;
+ count = ap->a_count;
+ rtvals = ap->a_rtvals;
+ npages = btoc(count);
+
+ for (i = 0; i < npages; i++) {
+ rtvals[i] = VM_PAGER_AGAIN;
+ }
+
+ bp = getpbuf(&nwfs_pbuf_freecnt);
+ kva = (vm_offset_t) bp->b_data;
+ pmap_qenter(kva, pages, npages);
+
+ iov.iov_base = (caddr_t) kva;
+ iov.iov_len = count;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+ uio.uio_resid = count;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = p;
+ NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
+
+ error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, &uio, cred);
+/* VOP_CLOSE(vp, FWRITE, cred, p);*/
+ NCPVNDEBUG("paged write done: %d\n", error);
+
+ pmap_qremove(kva, npages);
+ relpbuf(bp, &nwfs_pbuf_freecnt);
+
+ if (!error) {
+ int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
+ for (i = 0; i < nwritten; i++) {
+ rtvals[i] = VM_PAGER_OK;
+ pages[i]->dirty = 0;
+ }
+ }
+ return rtvals[0];
+#endif /* NWFS_RWCACHE */
+}
+/*
+ * Flush and invalidate all dirty buffers. If another process is already
+ * doing the flush, just wait for completion.
+ */
+int
+nwfs_vinvalbuf(vp, flags, cred, p, intrflg)
+ struct vnode *vp;
+ int flags;
+ struct ucred *cred;
+ struct proc *p;
+ int intrflg;
+{
+ register struct nwnode *np = VTONW(vp);
+/* struct nwmount *nmp = VTONWFS(vp);*/
+ int error = 0, slpflag, slptimeo;
+
+ if (vp->v_flag & VXLOCK) {
+ return (0);
+ }
+ if (intrflg) {
+ slpflag = PCATCH;
+ slptimeo = 2 * hz;
+ } else {
+ slpflag = 0;
+ slptimeo = 0;
+ }
+ while (np->n_flag & NFLUSHINPROG) {
+ np->n_flag |= NFLUSHWANT;
+ error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "nwfsvinv", slptimeo);
+ error = ncp_chkintr(NWFSTOCONN(VTONWFS(vp)), p);
+ if (error == EINTR && intrflg)
+ return EINTR;
+ }
+ np->n_flag |= NFLUSHINPROG;
+ error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
+ while (error) {
+ if (intrflg && (error == ERESTART || error == EINTR)) {
+ np->n_flag &= ~NFLUSHINPROG;
+ if (np->n_flag & NFLUSHWANT) {
+ np->n_flag &= ~NFLUSHWANT;
+ wakeup((caddr_t)&np->n_flag);
+ }
+ return EINTR;
+ }
+ error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
+ }
+ np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
+ if (np->n_flag & NFLUSHWANT) {
+ np->n_flag &= ~NFLUSHWANT;
+ wakeup((caddr_t)&np->n_flag);
+ }
+ return (error);
+}
diff --git a/sys/nwfs/nwfs_ioctl.c b/sys/nwfs/nwfs_ioctl.c
new file mode 100644
index 0000000..6b4b510
--- /dev/null
+++ b/sys/nwfs/nwfs_ioctl.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/ioccom.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+int
+nwfs_ioctl(ap)
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ u_long a_command;
+ caddr_t a_data;
+ int fflag;
+ struct ucred *cred;
+ struct proc *p;
+ } */ *ap;
+{
+ int error;
+ struct proc *p = ap->a_p;
+ struct ucred *cred = ap->a_cred;
+ struct vnode *vp = ap->a_vp;
+ struct nwnode *np = VTONW(vp);
+ struct nwmount *nmp = VTONWFS(vp);
+ struct ncp_conn *conn = NWFSTOCONN(nmp);
+ struct ncp_handle *hp;
+ struct nw_entry_info *fap;
+ void *data = ap->a_data;
+
+ switch (ap->a_command) {
+ case NWFSIOC_GETCONN:
+ error = ncp_conn_lock(conn, p, cred, NCPM_READ);
+ if (error) break;
+ error = ncp_conn_gethandle(conn, p, &hp);
+ ncp_conn_unlock(conn, p);
+ if (error) break;
+ *(int*)data = hp->nh_id;
+ break;
+ case NWFSIOC_GETEINFO:
+ if ((error = VOP_ACCESS(vp, VEXEC, cred, p))) break;
+ fap = data;
+ error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, fap,
+ ap->a_p,ap->a_cred);
+ strcpy(fap->entryName, np->n_name);
+ fap->nameLen = np->n_nmlen;
+ break;
+ case NWFSIOC_GETNS:
+ if ((error = VOP_ACCESS(vp, VEXEC, cred, p))) break;
+ *(int*)data = nmp->name_space;
+ break;
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
diff --git a/sys/nwfs/nwfs_mount.h b/sys/nwfs/nwfs_mount.h
new file mode 100644
index 0000000..56a3241
--- /dev/null
+++ b/sys/nwfs/nwfs_mount.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NWFS_MOUNT_H_
+#define _NWFS_MOUNT_H_
+
+#ifndef _NCP_NCP_NLS_H_
+#include <netncp/ncp_nls.h>
+#endif
+
+#define NWFS_VERMAJ 1
+#define NWFS_VERMIN 3200
+#define NWFS_VERSION (NWFS_VERMAJ*100000 + NWFS_VERMIN)
+
+/* Values for flags */
+#define NWFS_MOUNT_SOFT 0x0001
+#define WNFS_MOUNT_INTR 0x0002
+#define NWFS_MOUNT_STRONG 0x0004
+#define NWFS_MOUNT_NO_OS2 0x0008
+#define NWFS_MOUNT_NO_NFS 0x0010
+#define NWFS_MOUNT_NO_LONG 0x0020
+#define NWFS_MOUNT_GET_SYSENT 0x0040 /* special case, look to vfsops :) */
+#define NWFS_MOUNT_HAVE_NLS 0x0080
+
+
+/* Layout of the mount control block for a netware file system. */
+struct nwfs_args {
+ int connRef; /* connection reference */
+ char mount_point[MAXPATHLEN];
+ u_int flags;
+ u_char mounted_vol[NCP_VOLNAME_LEN + 1];
+ u_char root_path[512+1];
+ int version;
+ uid_t uid;
+ gid_t gid;
+ mode_t file_mode;
+ mode_t dir_mode;
+ struct ncp_nlstables nls;
+};
+
+#ifdef KERNEL
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_NWFSMNT);
+#endif
+
+#endif /* KERNEL */
+#endif /* !_NWFS_MOUNT_H_ */
diff --git a/sys/nwfs/nwfs_node.c b/sys/nwfs/nwfs_node.c
new file mode 100644
index 0000000..55e19b7
--- /dev/null
+++ b/sys/nwfs/nwfs_node.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+#include <vm/vm_zone.h>
+#include <sys/queue.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_mount.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+#define NWNOHASH(fhsum) (&nwhashtbl[(fhsum.f_id) & nwnodehash])
+
+extern vop_t **nwfs_vnodeop_p;
+
+static LIST_HEAD(nwnode_hash_head,nwnode) *nwhashtbl;
+static u_long nwnodehash;
+static int nwhashlock = 0;
+
+MALLOC_DEFINE(M_NWNODE, "NWFS node", "NWFS vnode private part");
+MALLOC_DEFINE(M_NWFSHASH, "NWFS hash", "NWFS has table");
+
+static int nwfs_sysctl_vnprint SYSCTL_HANDLER_ARGS;
+
+extern struct linker_set sysctl_vfs_nwfs;
+
+SYSCTL_DECL(_vfs_nwfs);
+
+SYSCTL_PROC(_vfs_nwfs, OID_AUTO, vnprint, CTLFLAG_WR|CTLTYPE_OPAQUE,
+ NULL, 0, nwfs_sysctl_vnprint, "S,vnlist", "vnode hash");
+
+void
+nwfs_hash_init(void) {
+ nwhashtbl = hashinit(desiredvnodes, M_NWFSHASH, &nwnodehash);
+}
+
+void
+nwfs_hash_free(void) {
+ free(nwhashtbl, M_NWFSHASH);
+}
+
+int
+nwfs_sysctl_vnprint SYSCTL_HANDLER_ARGS {
+ struct nwnode *np;
+ struct nwnode_hash_head *nhpp;
+ struct vnode *vp;
+ int i;
+
+ if (nwfs_debuglevel == 0)
+ return 0;
+ printf("Name:uc:hc:fid:pfid\n");
+ for(i = 0; i <= nwnodehash; i++) {
+ nhpp = &nwhashtbl[i];
+ for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
+ vp = NWTOV(np);
+ printf("%s:%d:%d:%d:%d\n",np->n_name,vp->v_usecount,vp->v_holdcnt,
+ np->n_fid.f_id, np->n_fid.f_parent);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Allocate new nwfsnode/vnode from given nwnode.
+ * Vnode referenced and not locked.
+ */
+int
+nwfs_allocvp(struct mount *mp, ncpfid fid, struct vnode **vpp) {
+ struct proc *p = curproc; /* XXX */
+ struct nwnode *np, *np2;
+ struct nwnode_hash_head *nhpp;
+ struct vnode *vp;
+ int error;
+
+retry:
+ nhpp = NWNOHASH(fid);
+loop:
+ for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
+ vp = NWTOV(np);
+ if (mp != vp->v_mount || !NWCMPF(&fid, &np->n_fid))
+ continue;
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ *vpp = vp;
+ return(0);
+ }
+
+ /* lock list, or waiting in malloc can cause problems */
+ if (nwhashlock) {
+ while(nwhashlock) {
+ nwhashlock = -1;
+ tsleep((caddr_t) &nwhashlock, PVM, "nwfsvp", 0);
+ }
+ goto loop;
+ }
+ nwhashlock = 1;
+ /*
+ * Do the MALLOC before the getnewvnode since doing so afterward
+ * might cause a bogus v_data pointer to get dereferenced
+ * elsewhere if MALLOC should block.
+ */
+ MALLOC(np, struct nwnode *, sizeof *np, M_NWNODE, M_WAITOK);
+ error = getnewvnode(VT_NWFS, mp, nwfs_vnodeop_p, &vp);
+ if (error) {
+ if (nwhashlock < 0)
+ wakeup(&nwhashlock);
+ nwhashlock = 0;
+ *vpp = 0;
+ FREE(np, M_NWNODE);
+ return (error);
+ }
+ *vpp = vp;
+ bzero(np,sizeof(*np));
+ vp->v_data = np;
+ np->n_vnode = vp;
+ np->n_mount = VFSTONWFS(mp);
+ np->n_fid = fid;
+ for (np2 = nhpp->lh_first; np2 != 0; np2 = np->n_hash.le_next) {
+ if (mp != NWTOV(np2)->v_mount || !NWCMPF(&fid, &np2->n_fid))
+ continue;
+ vrele(vp);
+ FREE(np, M_NWNODE);
+ if (nwhashlock < 0)
+ wakeup(&nwhashlock);
+ nwhashlock = 0;
+ goto retry;
+ }
+ LIST_INSERT_HEAD(nhpp, np, n_hash);
+ if (nwhashlock < 0)
+ wakeup(&nwhashlock);
+ nwhashlock = 0;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ np->n_flag |= NNEW;
+ return (error);
+}
+
+int
+nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct nwnode **npp) {
+ struct nwnode *np;
+ struct nwnode_hash_head *nhpp;
+
+ nhpp = NWNOHASH(fid);
+ for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
+ if (nmp != np->n_mount || !NWCMPF(&fid, &np->n_fid))
+ continue;
+ *npp = np;
+ return(0);
+ }
+ return ENOENT;
+}
+
+/*
+ * Free nwnode, and give vnode back to system
+ */
+int
+nwfs_reclaim(ap)
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *dvp = NULL, *vp = ap->a_vp;
+ struct nwnode *dnp, *np = VTONW(vp);
+ struct nwmount *nmp=VTONWFS(vp);
+
+ NCPVNDEBUG("%s,%d\n", np->n_name, vp->v_usecount);
+ if (np->n_refparent) {
+ np->n_refparent = 0;
+ if (nwfs_lookupnp(nmp, np->n_parent, &dnp) == 0) {
+ dvp = dnp->n_vnode;
+ } else {
+ NCPVNDEBUG("%s: has no parent ?\n",np->n_name);
+ }
+ }
+ LIST_REMOVE(np, n_hash);
+ cache_purge(vp);
+ if (nmp->n_root == np) {
+ nmp->n_root = NULL;
+ }
+ vp->v_data = NULL;
+ FREE(np, M_NWNODE);
+ if (dvp) {
+ vrele(dvp);
+ }
+ return (0);
+}
+
+int
+nwfs_inactive(ap)
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct proc *p = ap->a_p;
+ struct ucred *cred = p->p_ucred;
+ struct vnode *vp = ap->a_vp;
+ struct nwnode *np = VTONW(vp);
+ int error;
+
+ NCPVNDEBUG("%s: %d\n", VTONW(vp)->n_name, vp->v_usecount);
+ if (np->opened) {
+ error = nwfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, p, cred);
+ np->opened = 0;
+ }
+ VOP_UNLOCK(vp, 0, p);
+ return (0);
+}
+/*
+ * routines to maintain vnode attributes cache
+ * nwfs_attr_cacheenter: unpack np.i to va structure
+ */
+void
+nwfs_attr_cacheenter(struct vnode *vp, struct nw_entry_info *fi) {
+ struct nwnode *np = VTONW(vp);
+ struct nwmount *nmp = VTONWFS(vp);
+ register struct vattr *va = &np->n_vattr;
+
+ va->va_type = vp->v_type; /* vnode type (for create) */
+ if (vp->v_type == VREG) {
+ if (va->va_size != fi->dataStreamSize) {
+ va->va_size = fi->dataStreamSize;
+ vnode_pager_setsize(vp, va->va_size);
+ }
+ va->va_mode = nmp->m.file_mode; /* files access mode and type */
+ } else if (vp->v_type == VDIR) {
+ va->va_size = 16384; /* should be a better way ... */
+ va->va_mode = nmp->m.dir_mode; /* files access mode and type */
+ } else
+ return;
+ np->n_size = va->va_size;
+ va->va_nlink = 1; /* number of references to file */
+ va->va_uid = nmp->m.uid; /* owner user id */
+ va->va_gid = nmp->m.gid; /* owner group id */
+ va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
+ va->va_fileid = np->n_fid.f_id; /* file id */
+ if (va->va_fileid == 0)
+ va->va_fileid = NWFS_ROOT_INO;
+ va->va_blocksize=nmp->connh->nh_conn->buffer_size;/* blocksize preferred for i/o */
+ /* time of last modification */
+ ncp_dos2unixtime(fi->modifyDate, fi->modifyTime, 0, &va->va_mtime);
+ /* time of last access */
+ ncp_dos2unixtime(fi->lastAccessDate, 0, 0, &va->va_atime);
+ va->va_ctime = va->va_mtime; /* time file changed */
+ va->va_gen = VNOVAL; /* generation number of file */
+ va->va_flags = 0; /* flags defined for file */
+ va->va_rdev = VNOVAL; /* device the special file represents */
+ va->va_bytes = va->va_size; /* bytes of disk space held by file */
+ va->va_filerev = 0; /* file modification number */
+ va->va_vaflags = 0; /* operations flags */
+ np->n_vattr = *va;
+ if (np->n_mtime == 0) {
+ np->n_mtime = va->va_mtime.tv_sec;
+ }
+ np->n_atime = time_second;
+ return;
+}
+
+int
+nwfs_attr_cachelookup(struct vnode *vp, struct vattr *va) {
+ struct nwnode *np = VTONW(vp);
+ int diff;
+
+ diff = time_second - np->n_atime;
+ if (diff > 2) { /* XXX should be configurable */
+ return ENOENT;
+ }
+ *va = np->n_vattr;
+ return 0;
+}
diff --git a/sys/nwfs/nwfs_node.h b/sys/nwfs/nwfs_node.h
new file mode 100644
index 0000000..c88c4b4
--- /dev/null
+++ b/sys/nwfs/nwfs_node.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NWFS_NODE_H_
+#define _NWFS_NODE_H_
+
+#define NWFS_ROOT_INO 0x7ffffffd
+#define NWFS_ROOTVOL "#.ROOT"
+
+/* Bits for nwnode.n_flag */
+#define NFLUSHINPROG 0x0001
+#define NFLUSHWANT 0x0002 /* they should gone ... */
+#define NMODIFIED 0x0004 /* bogus, until async IO implemented */
+#define NNEW 0x0008 /* vnode has been allocated */
+#define NVOLUME 0x0010 /* vnode references a volume */
+
+#ifndef VT_NWFS
+#define VT_NWFS VT_TFS
+#endif
+
+struct nwnode {
+ LIST_ENTRY(nwnode) n_hash;
+ struct vnode *n_vnode;
+ struct vattr n_vattr;
+ struct nwmount *n_mount;
+ time_t n_atime; /* attributes cache time*/
+ time_t n_ctime;
+ time_t n_mtime;
+ int n_flag;
+ ncpfid n_parent;
+ ncpfid n_fid;
+ int n_refparent;
+ u_long n_attr; /* LH */
+ u_long n_size;
+ u_long n_dosfid;
+ int opened;
+/* int access;*/
+ u_long n_origfh;
+ ncp_fh n_fh;
+ struct nw_search_seq n_seq;
+ u_char n_nmlen;
+ u_char n_name[256];
+};
+
+#define VTONW(vp) ((struct nwnode *)(vp)->v_data)
+#define NWTOV(np) ((struct vnode *)(np)->n_vnode)
+#define NWCMPF(f1,f2) ((f1)->f_parent == (f2)->f_parent && \
+ (f1)->f_id == (f2)->f_id)
+#define NWCMPN(np1,np2) NWCMPF(&(np1)->n_fid, &(np2)->n_fid)
+#define NWCMPV(vp1,vp2) NWCMPN(VTONW(vp1),VTONW(vp2))
+
+void nwfs_hash_init(void);
+void nwfs_hash_free(void);
+int nwfs_allocvp(struct mount *mp, ncpfid fid, struct vnode **vpp);
+int nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct nwnode **npp);
+int nwfs_inactive __P((struct vop_inactive_args *));
+int nwfs_reclaim __P((struct vop_reclaim_args *));
+int nwfs_nget(struct mount *mp, ncpfid fid, struct nw_entry_info *fap,
+ struct vnode *dvp, struct vnode **vpp);
+
+int nwfs_getpages __P((struct vop_getpages_args *));
+int nwfs_putpages __P((struct vop_putpages_args *));
+int nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred);
+int nwfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag);
+void nwfs_attr_cacheenter(struct vnode *vp, struct nw_entry_info *fi);
+int nwfs_attr_cachelookup(struct vnode *vp,struct vattr *va);
+
+#define nwfs_attr_cacheremove(vp) VTONW(vp)->n_atime = 0
+
+#endif /* _NWFS_NODE_H_ */
diff --git a/sys/nwfs/nwfs_subr.c b/sys/nwfs/nwfs_subr.c
new file mode 100644
index 0000000..d57d675
--- /dev/null
+++ b/sys/nwfs/nwfs_subr.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <machine/clock.h>
+#include <sys/time.h>
+#include <sys/namei.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_user.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/nwerror.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+MALLOC_DEFINE(M_NWFSDATA, "NWFS data", "NWFS private data");
+
+static void
+ncp_extract_file_info(struct nwmount *nmp, struct ncp_rq *rqp, struct nw_entry_info *target) {
+ u_char name_len;
+ const int info_struct_size = sizeof(struct nw_entry_info) - 257;
+
+ ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
+ name_len = ncp_rp_byte(rqp);
+ target->nameLen = name_len;
+ ncp_rp_mem(rqp,(caddr_t)target->entryName, name_len);
+ target->entryName[name_len] = '\0';
+ ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls);
+ return;
+}
+
+static void
+ncp_update_file_info(struct nwmount *nmp, struct ncp_rq *rqp,
+ struct nw_entry_info *target)
+{
+ int info_struct_size = sizeof(struct nw_entry_info) - 257;
+
+ ncp_rp_mem(rqp,(caddr_t)target,info_struct_size);
+ return;
+}
+
+int
+ncp_initsearch(struct vnode *dvp,struct proc *p,struct ucred *cred)
+{
+ struct nwmount *nmp = VTONWFS(dvp);
+ struct ncp_conn *conn = NWFSTOCONN(nmp);
+ struct nwnode *np = VTONW(dvp);
+ u_int8_t volnum = nmp->n_volume;
+ u_int32_t dirent = np->n_fid.f_id;
+ int error;
+ DECLARE_RQ;
+
+ NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent);
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 2); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* reserved */
+ ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
+ checkbad(ncp_request(conn,rqp));
+ ncp_rp_mem(rqp,(caddr_t)&np->n_seq, sizeof(np->n_seq));
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_search_for_file_or_subdir(struct nwmount *nmp,
+ struct nw_search_seq *seq,
+ struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred)
+{
+ struct ncp_conn *conn = NWFSTOCONN(nmp);
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 3); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* data stream */
+ ncp_rq_word_lh(rqp, 0xffff); /* Search attribs */
+ ncp_rq_dword(rqp, IM_ALL); /* return info mask */
+ ncp_rq_mem(rqp, (caddr_t)seq, 9);
+ ncp_rq_byte(rqp, 2); /* 2 byte pattern */
+ ncp_rq_byte(rqp, 0xff); /* following is a wildcard */
+ ncp_rq_byte(rqp, '*');
+ checkbad(ncp_request(conn,rqp));
+ ncp_rp_mem(rqp,(caddr_t)seq, sizeof(*seq));
+ ncp_rp_byte(rqp); /* skip */
+ ncp_extract_file_info(nmp, rqp, target);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+/*
+ * Returns information for a (one-component) name relative to the specified
+ * directory.
+ */
+int
+ncp_obtain_info(struct nwmount *nmp, u_int32_t dirent,
+ int namelen, char *path, struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred)
+{
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ int error;
+ u_char volnum = nmp->n_volume, ns;
+ DECLARE_RQ;
+
+ if (target == NULL) {
+ NCPFATAL("target == NULL\n");
+ return EINVAL;
+ }
+ ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space;
+ NCP_RQ_HEAD(87, p, cred);
+ ncp_rq_byte(rqp, 6); /* subfunction */
+ ncp_rq_byte(rqp, ns);
+ ncp_rq_byte(rqp, ns); /* DestNameSpace */
+ ncp_rq_word(rqp, htons(0xff00)); /* get all */
+ ncp_rq_dword(rqp, IM_ALL);
+ ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls);
+ checkbad(ncp_request(conn,rqp));
+ if (path)
+ ncp_extract_file_info(nmp, rqp, target);
+ else
+ ncp_update_file_info(nmp, rqp, target);
+ NCP_RQ_EXIT;
+ return error;
+}
+/*
+ * lookup name pointed by cnp in directory dvp and return file info in np.
+ * May be I should create a little cache, but another way is to minimize
+ * number of calls, on other hand, in multiprocess environment ...
+ */
+int
+ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
+ struct proc *p,struct ucred *cred)
+{
+ struct nwmount *nmp;
+ struct nwnode *dnp = VTONW(dvp);
+ struct ncp_conn *conn;
+ int error;
+
+ if (!dvp || dvp->v_type != VDIR) {
+ nwfs_printf("dvp is NULL or not a directory.\n");
+ return (ENOENT);
+ }
+ nmp = VTONWFS(dvp);
+ conn = NWFSTOCONN(nmp);
+
+ if (len == 1 && name[0] == '.') {
+ if (strcmp(dnp->n_name, NWFS_ROOTVOL) == 0) {
+ error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL,
+ fap, p, cred);
+ } else {
+ error = ncp_obtain_info(nmp, dnp->n_fid.f_parent,
+ dnp->n_nmlen, dnp->n_name, fap, p, cred);
+ }
+ return error;
+ } else if (len == 2 && name[0] == '.' && name[1] == '.') {
+ printf("%s: knows NOTHING about '..'\n", __FUNCTION__);
+ return EIO;
+ } else {
+ error = ncp_obtain_info(nmp, dnp->n_fid.f_id,
+ len, name, fap, p, cred);
+ }
+ return error;
+}
+
+static void ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh);
+static void
+ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
+ fh->val1 = (fh->val.val32 = sfd);
+ return;
+}
+
+/*
+ * If both dir and name are NULL, then in target there's already a looked-up
+ * entry that wants to be opened.
+ */
+int
+ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp,int namelen,
+ char *name, int open_create_mode, u_int32_t create_attributes,
+ int desired_acc_rights, struct ncp_open_info *nop,
+ struct proc *p,struct ucred *cred)
+{
+
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES);
+ u_int8_t volnum;
+ u_int32_t dirent;
+ int error;
+ DECLARE_RQ;
+
+ volnum = nmp->n_volume;
+ dirent = VTONW(dvp)->n_fid.f_id;
+ if ((create_attributes & aDIR) != 0) {
+ search_attribs |= SA_SUBDIR_FILES;
+ }
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 1);/* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, open_create_mode);
+ ncp_rq_word(rqp, search_attribs);
+ ncp_rq_dword(rqp, IM_ALL);
+ ncp_rq_dword(rqp, create_attributes);
+ /*
+ * The desired acc rights seem to be the inherited rights mask for
+ * directories
+ */
+ ncp_rq_word(rqp, desired_acc_rights);
+ ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls);
+ checkbad(ncp_request(conn,rqp));
+
+ nop->origfh = ncp_rp_dword_lh(rqp);
+ nop->action = ncp_rp_byte(rqp);
+ ncp_rp_byte(rqp); /* skip */
+ ncp_extract_file_info(nmp, rqp, &nop->fattr);
+ ConvertToNWfromDWORD(nop->origfh, &nop->fh);
+ NCP_RQ_EXIT;
+ switch(error) {
+ case NWE_FILE_NO_CREATE_PRIV:
+ error = EACCES;
+ break;
+ }
+ return error;
+}
+
+int
+ncp_close_file(struct ncp_conn *conn, ncp_fh *fh,struct proc *p,struct ucred *cred) {
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(66,p,cred);
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_mem(rqp, (caddr_t)fh, 6);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_DeleteNSEntry(struct nwmount *nmp, u_int32_t dirent,
+ int namelen,char *name,struct proc *p,struct ucred *cred)
+{
+ int error;
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 8); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* reserved */
+ ncp_rq_word(rqp, SA_ALL); /* search attribs: all */
+ ncp_rq_dbase_path(rqp, nmp->n_volume, dirent, namelen, name, &nmp->m.nls);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype,
+ struct ncp_nlstables *nt,
+ nwdirent fdir, char *old_name, int oldlen,
+ nwdirent tdir, char *new_name, int newlen,
+ struct proc *p, struct ucred *cred)
+{
+ DECLARE_RQ;
+ int error;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 4);
+ ncp_rq_byte(rqp, ns);
+ ncp_rq_byte(rqp, 1);
+ ncp_rq_word(rqp, oldtype);
+ /* source Handle Path */
+ ncp_rq_byte(rqp, volume);
+ ncp_rq_dword(rqp, fdir);
+ ncp_rq_byte(rqp, 1);
+ ncp_rq_byte(rqp, 1); /* 1 source component */
+ /* dest Handle Path */
+ ncp_rq_byte(rqp, volume);
+ ncp_rq_dword(rqp, tdir);
+ ncp_rq_byte(rqp, 1);
+ ncp_rq_byte(rqp, 1); /* 1 destination component */
+ ncp_rq_pathstring(rqp, oldlen, old_name, nt);
+ ncp_rq_pathstring(rqp, newlen, new_name, nt);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp,
+ u_int32_t info_mask,
+ struct nw_modify_dos_info *info,
+ struct proc *p,struct ucred *cred)
+{
+ struct nwnode *np=VTONW(vp);
+ u_int8_t volnum = nmp->n_volume;
+ u_int32_t dirent = np->n_fid.f_id;
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ int error;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 7); /* subfunction */
+ ncp_rq_byte(rqp, nmp->name_space);
+ ncp_rq_byte(rqp, 0); /* reserved */
+ ncp_rq_word(rqp, htons(0x0680)); /* search attribs: all */
+ ncp_rq_dword(rqp, info_mask);
+ ncp_rq_mem(rqp, (caddr_t)info, sizeof(*info));
+ ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
+ error = ncp_request(conn,rqp);
+ NCP_RQ_EXIT_NB;
+ return error;
+}
+
+int
+ncp_setattr(vp, vap, cred, procp)
+ register struct vnode *vp;
+ register struct vattr *vap;
+ struct ucred *cred;
+ struct proc *procp;
+{
+ struct nwmount *nmp=VTONWFS(vp);
+ struct nwnode *np=VTONW(vp);
+ struct ncp_open_info nwn;
+ struct ncp_conn *conn=NWFSTOCONN(nmp);
+ struct nw_modify_dos_info info;
+ int error = 0, info_mask;
+ DECLARE_RQ;
+
+ if (vap->va_size != VNOVAL) {
+ error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
+ AR_WRITE | AR_READ, &nwn,procp,cred);
+ if (error) return error;
+ NCP_RQ_HEAD(73,procp,cred);
+ ncp_rq_byte(rqp, 0);
+ ncp_rq_mem(rqp, (caddr_t)&nwn.fh, 6);
+ ncp_rq_dword(rqp, htonl(vap->va_size));
+ ncp_rq_word_hl(rqp, 0);
+ checkbad(ncp_request(conn,rqp));
+ np->n_vattr.va_size = np->n_size = vap->va_size;
+ NCP_RQ_EXIT;
+ ncp_close_file(conn, &nwn.fh, procp, cred);
+ if (error) return error;
+ }
+ info_mask = 0;
+ bzero(&info, sizeof(info));
+
+ if (vap->va_mtime.tv_sec != VNOVAL) {
+ info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
+ ncp_unix2dostime(&vap->va_mtime, &info.modifyDate, &info.modifyTime, NULL);
+ }
+ if (vap->va_atime.tv_sec != VNOVAL) {
+ info_mask |= (DM_LAST_ACCESS_DATE);
+ ncp_unix2dostime(&vap->va_atime, &info.lastAccessDate,NULL,NULL);
+ }
+ if (info_mask) {
+ error = ncp_modify_file_or_subdir_dos_info(nmp, vp, info_mask, &info,procp,cred);
+ }
+ return (error);
+}
+
+int
+ncp_get_volume_info_with_number(struct ncp_conn *conn,
+ int n, struct ncp_volume_info *target,
+ struct proc *p,struct ucred *cred) {
+ int error,len;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD_S(22,44,p,cred);
+ ncp_rq_byte(rqp,n);
+ checkbad(ncp_request(conn,rqp));
+ target->total_blocks = ncp_rp_dword_lh(rqp);
+ target->free_blocks = ncp_rp_dword_lh(rqp);
+ target->purgeable_blocks = ncp_rp_dword_lh(rqp);
+ target->not_yet_purgeable_blocks = ncp_rp_dword_lh(rqp);
+ target->total_dir_entries = ncp_rp_dword_lh(rqp);
+ target->available_dir_entries = ncp_rp_dword_lh(rqp);
+ ncp_rp_dword_lh(rqp);
+ target->sectors_per_block = ncp_rp_byte(rqp);
+ bzero(&target->volume_name, sizeof(target->volume_name));
+ len = ncp_rp_byte(rqp);
+ if (len > NCP_VOLNAME_LEN) {
+ error = ENAMETOOLONG;
+ } else {
+ ncp_rp_mem(rqp,(caddr_t)&target->volume_name, len);
+ }
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
+ struct proc *p,struct ucred *cred) {
+ int error;
+ u_int8_t ns;
+ u_int16_t nscnt;
+ DECLARE_RQ;
+
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 24); /* Subfunction: Get Loaded Name Spaces */
+ ncp_rq_word(rqp, 0);
+ ncp_rq_byte(rqp, volume);
+ checkbad(ncp_request(conn,rqp));
+ nscnt = ncp_rp_word_lh(rqp);
+ *nsf = 0;
+ while (nscnt-- > 0) {
+ ns = ncp_rp_byte(rqp);
+ *nsf |= 1 << ns;
+ }
+ NCP_RQ_EXIT;
+ return error;
+}
+
+int
+ncp_lookup_volume(struct ncp_conn *conn, char *volname,
+ u_char *volNum, u_int32_t *dirEnt,
+ struct proc *p,struct ucred *cred)
+{
+ int error;
+ DECLARE_RQ;
+
+ NCPNDEBUG("looking up vol %s\n", volname);
+ NCP_RQ_HEAD(87,p,cred);
+ ncp_rq_byte(rqp, 22); /* Subfunction: Generate dir handle */
+ ncp_rq_byte(rqp, 0); /* src name space */
+ ncp_rq_byte(rqp, 0); /* dst name space, always zero */
+ ncp_rq_word(rqp, 0); /* dstNSIndicator */
+
+ ncp_rq_byte(rqp, 0); /* faked volume number */
+ ncp_rq_dword(rqp, 0); /* faked dir_base */
+ ncp_rq_byte(rqp, 0xff); /* Don't have a dir_base */
+ ncp_rq_byte(rqp, 1); /* 1 path component */
+ ncp_rq_pstring(rqp, volname);
+ checkbad(ncp_request(conn,rqp));
+ ncp_rp_dword_lh(rqp); /* NSDirectoryBase*/
+ *dirEnt = ncp_rp_dword_lh(rqp);
+ *volNum = ncp_rp_byte(rqp);
+ NCP_RQ_EXIT;
+ return error;
+}
+
+/*
+ * Time & date conversion routines taken from msdosfs. Although leap
+ * year calculation is bogus, it's sufficient before 2100 :)
+ */
+/*
+ * This is the format of the contents of the deTime field in the direntry
+ * structure.
+ * We don't use bitfields because we don't know how compilers for
+ * arbitrary machines will lay them out.
+ */
+#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
+#define DT_2SECONDS_SHIFT 0
+#define DT_MINUTES_MASK 0x7E0 /* minutes */
+#define DT_MINUTES_SHIFT 5
+#define DT_HOURS_MASK 0xF800 /* hours */
+#define DT_HOURS_SHIFT 11
+
+/*
+ * This is the format of the contents of the deDate field in the direntry
+ * structure.
+ */
+#define DD_DAY_MASK 0x1F /* day of month */
+#define DD_DAY_SHIFT 0
+#define DD_MONTH_MASK 0x1E0 /* month */
+#define DD_MONTH_SHIFT 5
+#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
+#define DD_YEAR_SHIFT 9
+/*
+ * Total number of days that have passed for each month in a regular year.
+ */
+static u_short regyear[] = {
+ 31, 59, 90, 120, 151, 181,
+ 212, 243, 273, 304, 334, 365
+};
+
+/*
+ * Total number of days that have passed for each month in a leap year.
+ */
+static u_short leapyear[] = {
+ 31, 60, 91, 121, 152, 182,
+ 213, 244, 274, 305, 335, 366
+};
+
+/*
+ * Variables used to remember parts of the last time conversion. Maybe we
+ * can avoid a full conversion.
+ */
+static u_long lasttime;
+static u_long lastday;
+static u_short lastddate;
+static u_short lastdtime;
+/*
+ * Convert the unix version of time to dos's idea of time to be used in
+ * file timestamps. The passed in unix time is assumed to be in GMT.
+ */
+void
+ncp_unix2dostime(tsp, ddp, dtp, dhp)
+ struct timespec *tsp;
+ u_int16_t *ddp;
+ u_int16_t *dtp;
+ u_int8_t *dhp;
+{
+ u_long t;
+ u_long days;
+ u_long inc;
+ u_long year;
+ u_long month;
+ u_short *months;
+
+ /*
+ * If the time from the last conversion is the same as now, then
+ * skip the computations and use the saved result.
+ */
+ t = tsp->tv_sec - (tz.tz_minuteswest * 60)
+ - (wall_cmos_clock ? adjkerntz : 0);
+ /* - daylight savings time correction */
+ t &= ~1;
+ if (lasttime != t) {
+ lasttime = t;
+ lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ + (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ + (((t / 3600) % 24) << DT_HOURS_SHIFT);
+
+ /*
+ * If the number of days since 1970 is the same as the last
+ * time we did the computation then skip all this leap year
+ * and month stuff.
+ */
+ days = t / (24 * 60 * 60);
+ if (days != lastday) {
+ lastday = days;
+ for (year = 1970;; year++) {
+ inc = year & 0x03 ? 365 : 366;
+ if (days < inc)
+ break;
+ days -= inc;
+ }
+ months = year & 0x03 ? regyear : leapyear;
+ for (month = 0; days >= months[month]; month++)
+ ;
+ if (month > 0)
+ days -= months[month - 1];
+ lastddate = ((days + 1) << DD_DAY_SHIFT)
+ + ((month + 1) << DD_MONTH_SHIFT);
+ /*
+ * Remember dos's idea of time is relative to 1980.
+ * unix's is relative to 1970. If somehow we get a
+ * time before 1980 then don't give totally crazy
+ * results.
+ */
+ if (year > 1980)
+ lastddate += (year - 1980) << DD_YEAR_SHIFT;
+ }
+ }
+ if (dtp)
+ *dtp = lastdtime;
+ if (dhp)
+ *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
+
+ *ddp = lastddate;
+}
+
+/*
+ * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
+ * interval there were 8 regular years and 2 leap years.
+ */
+#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
+
+static u_short lastdosdate;
+static u_long lastseconds;
+
+/*
+ * Convert from dos' idea of time to unix'. This will probably only be
+ * called from the stat(), and fstat() system calls and so probably need
+ * not be too efficient.
+ */
+void
+ncp_dos2unixtime(dd, dt, dh, tsp)
+ u_int dd;
+ u_int dt;
+ u_int dh;
+ struct timespec *tsp;
+{
+ u_long seconds;
+ u_long month;
+ u_long year;
+ u_long days;
+ u_short *months;
+
+ if (dd == 0) {
+ /*
+ * Uninitialized field, return the epoch.
+ */
+ tsp->tv_sec = 0;
+ tsp->tv_nsec = 0;
+ return;
+ }
+ seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+ + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+ + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+ + dh / 100;
+ /*
+ * If the year, month, and day from the last conversion are the
+ * same then use the saved value.
+ */
+ if (lastdosdate != dd) {
+ lastdosdate = dd;
+ days = 0;
+ year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
+ days = year * 365;
+ days += year / 4 + 1; /* add in leap days */
+ if ((year & 0x03) == 0)
+ days--; /* if year is a leap year */
+ months = year & 0x03 ? regyear : leapyear;
+ month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
+ if (month < 1 || month > 12) {
+ month = 1;
+ }
+ if (month > 1)
+ days += months[month - 2];
+ days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
+ lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
+ }
+ tsp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
+ + adjkerntz;
+ /* + daylight savings time correction */
+ tsp->tv_nsec = (dh % 100) * 10000000;
+}
diff --git a/sys/nwfs/nwfs_subr.h b/sys/nwfs/nwfs_subr.h
new file mode 100644
index 0000000..6112933
--- /dev/null
+++ b/sys/nwfs/nwfs_subr.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NWFS_SUBR_H_
+#define _NWFS_SUBR_H_
+
+extern int nwfs_debuglevel;
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_NWFSDATA);
+#endif
+
+int ncp_initsearch(struct vnode *dvp,struct proc *p,struct ucred *cred);
+int ncp_search_for_file_or_subdir(struct nwmount *nmp,struct nw_search_seq *seq,
+ struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred);
+int ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
+ struct proc *p,struct ucred *cred);
+int ncp_lookup_volume(struct ncp_conn *conn, char *volname,
+ u_char *volNum, u_int32_t *dirEnt,
+ struct proc *p,struct ucred *cred);
+int ncp_close_file(struct ncp_conn *conn, ncp_fh *fh,
+ struct proc *p,struct ucred *cred);
+int ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp, int namelen,char *name,
+ int open_create_mode, u_int32_t create_attributes,
+ int desired_acc_rights, struct ncp_open_info *nop,
+ struct proc *p,struct ucred *cred);
+int ncp_DeleteNSEntry(struct nwmount *nmp,
+ u_int32_t dirent, int namelen, char *name,
+ struct proc *p,struct ucred *cred);
+int ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype,
+ struct ncp_nlstables *nt,
+ nwdirent fdir, char *old_name, int oldlen,
+ nwdirent tdir, char *new_name, int newlen,
+ struct proc *p, struct ucred *cred);
+int ncp_obtain_info(struct nwmount *nmp, u_int32_t dirent,
+ int namelen, char *path, struct nw_entry_info *target,
+ struct proc *p,struct ucred *cred);
+int ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp,
+ u_int32_t info_mask,
+ struct nw_modify_dos_info *info,
+ struct proc *p,struct ucred *cred);
+int ncp_setattr(struct vnode *,struct vattr *,struct ucred *,struct proc *);
+int ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
+ struct proc *p,struct ucred *cred);
+int ncp_get_volume_info_with_number(struct ncp_conn *conn,
+ int n, struct ncp_volume_info *target,
+ struct proc *p,struct ucred *cred);
+
+void ncp_unix2dostime __P((struct timespec *tsp, u_int16_t *ddp,
+ u_int16_t *dtp, u_int8_t *dhp));
+void ncp_dos2unixtime __P((u_int dd, u_int dt, u_int dh, struct timespec *tsp));
+
+#endif /* !_NWFS_SUBR_H_ */
diff --git a/sys/nwfs/nwfs_vfsops.c b/sys/nwfs/nwfs_vfsops.c
new file mode 100644
index 0000000..53ecf98
--- /dev/null
+++ b/sys/nwfs/nwfs_vfsops.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "opt_ncp.h"
+#ifndef NCP
+#error "NWFS requires NCP protocol"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_sock.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_rq.h>
+#include <netncp/ncp_nls.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+int nwfs_debuglevel = 0;
+
+static int nwfs_version = NWFS_VERSION;
+
+SYSCTL_DECL(_vfs_nwfs);
+SYSCTL_NODE(_vfs, OID_AUTO, nwfs, CTLFLAG_RW, 0, "Netware file system");
+SYSCTL_INT(_vfs_nwfs, OID_AUTO, version, CTLFLAG_RD, &nwfs_version, 0, "");
+SYSCTL_INT(_vfs_nwfs, OID_AUTO, debuglevel, CTLFLAG_RW, &nwfs_debuglevel, 0, "");
+
+static int nwfs_mount __P((struct mount *, char *, caddr_t,
+ struct nameidata *, struct proc *));
+static int nwfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
+ struct proc *));
+static int nwfs_root __P((struct mount *, struct vnode **));
+static int nwfs_start __P((struct mount *, int, struct proc *));
+static int nwfs_statfs __P((struct mount *, struct statfs *,
+ struct proc *));
+static int nwfs_sync __P((struct mount *, int, struct ucred *,
+ struct proc *));
+static int nwfs_unmount __P((struct mount *, int, struct proc *));
+static int nwfs_init __P((struct vfsconf *vfsp));
+static int nwfs_uninit __P((struct vfsconf *vfsp));
+
+static struct vfsops nwfs_vfsops = {
+ nwfs_mount,
+ nwfs_start,
+ nwfs_unmount,
+ nwfs_root,
+ nwfs_quotactl,
+ nwfs_statfs,
+ nwfs_sync,
+ vfs_stdvget,
+ vfs_stdfhtovp, /* shouldn't happen */
+ vfs_stdcheckexp,
+ vfs_stdvptofh, /* shouldn't happen */
+ nwfs_init,
+ nwfs_uninit
+};
+
+
+VFS_SET(nwfs_vfsops, nwfs, VFCF_NETWORK);
+
+int nwfs_pbuf_freecnt = -1; /* start out unlimited */
+static int nwfsid = 1;
+
+static int
+nwfs_initnls(struct nwmount *nmp) {
+ char *pc, *pe;
+ int error = 0;
+#define COPY_TABLE(t,d) { \
+ if (t) { \
+ error = copyin((t), pc, 256); \
+ if (error) break; \
+ } else \
+ bcopy(d, pc, 256); \
+ (t) = pc; pc += 256; \
+ }
+
+ nmp->m.nls.opt |= NWHP_NLS | NWHP_DOS;
+ if ((nmp->m.flags & NWFS_MOUNT_HAVE_NLS) == 0) {
+ nmp->m.nls.tolower = ncp_defnls.tolower;
+ nmp->m.nls.toupper = ncp_defnls.toupper;
+ nmp->m.nls.n2u = ncp_defnls.n2u;
+ nmp->m.nls.u2n = ncp_defnls.u2n;
+ return 0;
+ }
+ MALLOC(pe, char *, 256 * 4, M_NWFSDATA, M_WAITOK);
+ if (pe == NULL) return ENOMEM;
+ pc = pe;
+ do {
+ COPY_TABLE(nmp->m.nls.tolower, ncp_defnls.tolower);
+ COPY_TABLE(nmp->m.nls.toupper, ncp_defnls.toupper);
+ COPY_TABLE(nmp->m.nls.n2u, ncp_defnls.n2u);
+ COPY_TABLE(nmp->m.nls.u2n, ncp_defnls.u2n);
+ } while(0);
+ if (error) {
+ free(pe, M_NWFSDATA);
+ return error;
+ }
+ return 0;
+}
+/*
+ * mp - path - addr in user space of mount point (ie /usr or whatever)
+ * data - addr in user space of mount params
+ */
+static int nwfs_mount(struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct nwfs_args args; /* will hold data from mount request */
+ size_t size;
+ int error;
+ struct nwmount *nmp = NULL;
+ struct ncp_conn *conn = NULL;
+ struct ncp_handle *handle = NULL;
+ struct vnode *vp;
+ char *pc,*pe;
+
+ if (data == NULL) {
+ nwfs_printf("missing data argument\n");
+ return 1;
+ }
+ if (mp->mnt_flag & MNT_UPDATE) {
+ nwfs_printf("MNT_UPDATE not implemented");
+ return (EOPNOTSUPP);
+ }
+ error = copyin(data, (caddr_t)&args, sizeof(struct nwfs_args));
+ if (error)
+ return (error);
+ if (args.version != NWFS_VERSION) {
+ nwfs_printf("mount version mismatch: kernel=%d, mount=%d\n",NWFS_VERSION,args.version);
+ return (1);
+ }
+ error = ncp_conn_getbyref(args.connRef,p,p->p_ucred,NCPM_EXECUTE,&conn);
+ if (error) {
+ nwfs_printf("invalid connection refernce %d\n",args.connRef);
+ return (error);
+ }
+ error = ncp_conn_gethandle(conn, NULL, &handle);
+ if (error) {
+ nwfs_printf("can't get connection handle\n");
+ return (error);
+ }
+ ncp_conn_unlock(conn,p); /* we keep the ref */
+ mp->mnt_stat.f_iosize = conn->buffer_size;
+ /* We must malloc our own mount info */
+ MALLOC(nmp,struct nwmount *,sizeof(struct nwmount),M_NWFSDATA,M_USE_RESERVE);
+ if (nmp == NULL) {
+ nwfs_printf("could not alloc nwmount\n");
+ error = ENOMEM;
+ goto bad;
+ }
+ bzero(nmp,sizeof(*nmp));
+ mp->mnt_data = (qaddr_t)nmp;
+ nmp->connh = handle;
+ nmp->n_root = NULL;
+ nmp->n_id = nwfsid++;
+ nmp->m = args;
+ nmp->m.file_mode = (nmp->m.file_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
+ nmp->m.dir_mode = (nmp->m.dir_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
+ if ((error = nwfs_initnls(nmp)) != 0) goto bad;
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ pc = mp->mnt_stat.f_mntfromname;
+ pe = pc+sizeof(mp->mnt_stat.f_mntfromname);
+ bzero(pc, MNAMELEN);
+ *(pc++) = '/';
+ pc = index(strncpy(pc, conn->li.server, pe-pc-2),0);
+ if (pc < pe-1) {
+ *(pc++) = ':';
+ pc=index(strncpy(pc, conn->li.user, pe-pc-2),0);
+ if (pc < pe-1) {
+ *(pc++) = '/';
+ strncpy(pc, nmp->m.mounted_vol, pe-pc-2);
+ }
+ }
+ /* protect against invalid mount points */
+ nmp->m.mount_point[sizeof(nmp->m.mount_point)-1] = '\0';
+ vfs_getnewfsid(mp);
+ error = nwfs_root(mp, &vp);
+ if (error)
+ goto bad;
+ /*
+ * Lose the lock but keep the ref.
+ */
+ VOP_UNLOCK(vp, 0, curproc);
+ NCPVODEBUG("rootvp.vrefcnt=%d\n",vp->v_usecount);
+ return error;
+bad:
+ if (nmp)
+ free(nmp, M_NWFSDATA);
+ if (handle)
+ ncp_conn_puthandle(handle, NULL, 0);
+ return error;
+}
+
+/* Unmount the filesystem described by mp. */
+static int
+nwfs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct nwmount *nmp = VFSTONWFS(mp);
+ struct ncp_conn *conn;
+ struct vnode *vp;
+ int error, flags;
+
+ NCPVODEBUG("nwfs_unmount: flags=%04x\n",mntflags);
+ flags = 0;
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+ error = VFS_ROOT(mp,&vp);
+ if (error) return (error);
+ if (vp->v_usecount > 2) {
+ printf("nwfs_unmount: usecnt=%d\n",vp->v_usecount);
+ vput(vp);
+ return (EBUSY);
+ }
+ error = vflush(mp, vp, flags);
+ if (error) {
+ vput(vp);
+ return (error);
+ }
+ /*
+ * There are two reference counts and one lock to get rid of here.
+ */
+ NCPVODEBUG("v_use: %d\n",vp->v_usecount);
+ vput(vp);
+ NCPVODEBUG("v_use after vput: %d\n",vp->v_usecount);
+ vrele(vp);
+ NCPVODEBUG("v_use after vrele: %d\n",vp->v_usecount);
+ vgone(vp);
+ NCPVODEBUG("v_gone finished !!!!\n");
+ conn = NWFSTOCONN(nmp);
+ ncp_conn_puthandle(nmp->connh,NULL,0);
+ if (ncp_conn_lock(conn,p,p->p_ucred,NCPM_WRITE | NCPM_EXECUTE) == 0) {
+ if(ncp_disconnect(conn))
+ ncp_conn_unlock(conn,p);
+ }
+ mp->mnt_data = (qaddr_t)0;
+ if (nmp->m.flags & NWFS_MOUNT_HAVE_NLS)
+ free(nmp->m.nls.tolower, M_NWFSDATA);
+ free(nmp, M_NWFSDATA);
+ mp->mnt_flag &= ~MNT_LOCAL;
+ return (error);
+}
+
+/* Return locked vnode to root of a filesystem */
+static int
+nwfs_root(struct mount *mp, struct vnode **vpp) {
+ struct vnode *vp;
+ struct nwmount *nmp;
+ struct nwnode *np;
+ struct ncp_conn *conn;
+ struct nw_entry_info fattr;
+ struct proc *p = curproc;
+ struct ucred *cred = p->p_ucred;
+ int error, nsf, opt;
+ u_char vol;
+
+ nmp = VFSTONWFS(mp);
+ conn = NWFSTOCONN(nmp);
+ if (nmp->n_root) {
+ *vpp = NWTOV(nmp->n_root);
+ vget(*vpp, LK_EXCLUSIVE, curproc);
+ return 0;
+ }
+ error = ncp_lookup_volume(conn, nmp->m.mounted_vol, &vol,
+ &nmp->n_rootent.f_id, p, cred);
+ if (error)
+ return ENOENT;
+ nmp->n_volume = vol;
+ error = ncp_get_namespaces(conn, vol, &nsf, p, cred);
+ if (error)
+ return ENOENT;
+ if (nsf & NW_NSB_OS2) {
+ NCPVODEBUG("volume %s has os2 namespace\n",nmp->m.mounted_vol);
+ if ((nmp->m.flags & NWFS_MOUNT_NO_OS2) == 0) {
+ nmp->name_space = NW_NS_OS2;
+ nmp->m.nls.opt &= ~NWHP_DOS;
+ }
+ }
+ opt = nmp->m.nls.opt;
+ nsf = opt & (NWHP_UPPER | NWHP_LOWER);
+ if (opt & NWHP_DOS) {
+ if (nsf == (NWHP_UPPER | NWHP_LOWER)) {
+ nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER);
+ } else if (nsf == 0) {
+ nmp->m.nls.opt |= NWHP_LOWER;
+ }
+ } else {
+ if (nsf == (NWHP_UPPER | NWHP_LOWER)) {
+ nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER);
+ }
+ }
+ if (nmp->m.root_path[0]) {
+ nmp->m.root_path[0]--;
+ error = ncp_obtain_info(nmp, nmp->n_rootent.f_id,
+ -nmp->m.root_path[0], nmp->m.root_path, &fattr, p, cred);
+ if (error) {
+ NCPFATAL("Invalid root path specified\n");
+ return ENOENT;
+ }
+ nmp->n_rootent.f_parent = fattr.dirEntNum;
+ nmp->m.root_path[0]++;
+ error = ncp_obtain_info(nmp, nmp->n_rootent.f_id,
+ -nmp->m.root_path[0], nmp->m.root_path, &fattr, p, cred);
+ if (error) {
+ NCPFATAL("Invalid root path specified\n");
+ return ENOENT;
+ }
+ nmp->n_rootent.f_id = fattr.dirEntNum;
+ } else {
+ error = ncp_obtain_info(nmp, nmp->n_rootent.f_id,
+ 0, NULL, &fattr, p, cred);
+ if (error) {
+ NCPFATAL("Can't obtain volume info\n");
+ return ENOENT;
+ }
+ fattr.nameLen = strlen(strcpy(fattr.entryName, NWFS_ROOTVOL));
+ nmp->n_rootent.f_parent = nmp->n_rootent.f_id;
+ }
+ error = nwfs_nget(mp, nmp->n_rootent, &fattr, NULL, &vp);
+ if (error)
+ return (error);
+ vp->v_flag |= VROOT;
+ np = VTONW(vp);
+ if (nmp->m.root_path[0] == 0)
+ np->n_flag |= NVOLUME;
+ nmp->n_root = np;
+/* error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) {
+ vput(vp);
+ NCPFATAL("Can't get root directory entry\n");
+ return error;
+ }*/
+ *vpp = vp;
+ return (0);
+}
+
+/*
+ * Vfs start routine, a no-op.
+ */
+/* ARGSUSED */
+static int
+nwfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+ NCPVODEBUG("flags=%04x\n",flags);
+ return (0);
+}
+
+/*
+ * Do operations associated with quotas, not supported
+ */
+/* ARGSUSED */
+static int
+nwfs_quotactl(mp, cmd, uid, arg, p)
+ struct mount *mp;
+ int cmd;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
+{
+ NCPVODEBUG("return EOPNOTSUPP\n");
+ return (EOPNOTSUPP);
+}
+
+/*ARGSUSED*/
+int
+nwfs_init(struct vfsconf *vfsp)
+{
+
+ nwfs_hash_init();
+ nwfs_pbuf_freecnt = nswbuf / 2 + 1;
+ NCPVODEBUG("always happy to load!\n");
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nwfs_uninit(struct vfsconf *vfsp)
+{
+
+ nwfs_hash_free();
+ NCPVODEBUG("unloaded\n");
+ return (0);
+}
+
+/*
+ * nwfs_statfs call
+ */
+int
+nwfs_statfs(mp, sbp, p)
+ struct mount *mp;
+ register struct statfs *sbp;
+ struct proc *p;
+{
+ struct nwmount *nmp = VFSTONWFS(mp);
+ int error = 0, secsize;
+ struct nwnode *np = nmp->n_root;
+ struct ncp_volume_info vi;
+
+ if (np == NULL) return EINVAL;
+ error = ncp_get_volume_info_with_number(NWFSTOCONN(nmp), nmp->n_volume, &vi,p,p->p_ucred);
+ if (error) return error;
+ secsize = 512; /* XXX how to get real value ??? */
+ sbp->f_spare2=0; /* placeholder */
+ /* fundamental file system block size */
+ sbp->f_bsize = vi.sectors_per_block*secsize;
+ /* optimal transfer block size */
+ sbp->f_iosize = NWFSTOCONN(nmp)->buffer_size;
+ /* total data blocks in file system */
+ sbp->f_blocks= vi.total_blocks;
+ /* free blocks in fs */
+ sbp->f_bfree = vi.free_blocks + vi.purgeable_blocks;
+ /* free blocks avail to non-superuser */
+ sbp->f_bavail= vi.free_blocks+vi.purgeable_blocks;
+ /* total file nodes in file system */
+ sbp->f_files = vi.total_dir_entries;
+ /* free file nodes in fs */
+ sbp->f_ffree = vi.available_dir_entries;
+ sbp->f_flags = 0; /* copy of mount exported flags */
+ if (sbp != &mp->mnt_stat) {
+ sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */
+ sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
+ sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return 0;
+}
+
+/*
+ * Flush out the buffer cache
+ */
+/* ARGSUSED */
+static int
+nwfs_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
+{
+ register struct vnode *vp;
+ int error, allerror = 0;
+ /*
+ * Force stale buffer cache information to be flushed.
+ */
+loop:
+ for (vp = mp->mnt_vnodelist.lh_first;
+ vp != NULL;
+ vp = vp->v_mntvnodes.le_next) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * associated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
+ goto loop;
+ if (VOP_ISLOCKED(vp) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+ waitfor == MNT_LAZY)
+ continue;
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ error = VOP_FSYNC(vp, cred, waitfor, p);
+ if (error)
+ allerror = error;
+ vput(vp);
+ }
+ return (allerror);
+}
diff --git a/sys/nwfs/nwfs_vnops.c b/sys/nwfs/nwfs_vnops.c
new file mode 100644
index 0000000..ab9f220
--- /dev/null
+++ b/sys/nwfs/nwfs_vnops.c
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/ioccom.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+#include <vm/vnode_pager.h>
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_subr.h>
+#include <netncp/nwerror.h>
+#include <netncp/ncp_nls.h>
+
+#include <nwfs/nwfs.h>
+#include <nwfs/nwfs_node.h>
+#include <nwfs/nwfs_subr.h>
+
+/*
+ * Prototypes for NWFS vnode operations
+ */
+static int nwfs_create __P((struct vop_create_args *));
+static int nwfs_mknod __P((struct vop_mknod_args *));
+static int nwfs_open __P((struct vop_open_args *));
+static int nwfs_close __P((struct vop_close_args *));
+static int nwfs_access __P((struct vop_access_args *));
+static int nwfs_getattr __P((struct vop_getattr_args *));
+static int nwfs_setattr __P((struct vop_setattr_args *));
+static int nwfs_read __P((struct vop_read_args *));
+static int nwfs_write __P((struct vop_write_args *));
+static int nwfs_fsync __P((struct vop_fsync_args *));
+static int nwfs_remove __P((struct vop_remove_args *));
+static int nwfs_link __P((struct vop_link_args *));
+static int nwfs_lookup __P((struct vop_lookup_args *));
+static int nwfs_rename __P((struct vop_rename_args *));
+static int nwfs_mkdir __P((struct vop_mkdir_args *));
+static int nwfs_rmdir __P((struct vop_rmdir_args *));
+static int nwfs_symlink __P((struct vop_symlink_args *));
+static int nwfs_readdir __P((struct vop_readdir_args *));
+static int nwfs_abortop __P((struct vop_abortop_args *));
+static int nwfs_bmap __P((struct vop_bmap_args *));
+static int nwfs_strategy __P((struct vop_strategy_args *));
+static int nwfs_print __P((struct vop_print_args *));
+static int nwfs_pathconf __P((struct vop_pathconf_args *ap));
+
+/* Global vfs data structures for nwfs */
+vop_t **nwfs_vnodeop_p;
+static struct vnodeopv_entry_desc nwfs_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) vop_defaultop },
+ { &vop_abortop_desc, (vop_t *) nwfs_abortop },
+ { &vop_access_desc, (vop_t *) nwfs_access },
+ { &vop_bmap_desc, (vop_t *) nwfs_bmap },
+ { &vop_open_desc, (vop_t *) nwfs_open },
+ { &vop_close_desc, (vop_t *) nwfs_close },
+ { &vop_create_desc, (vop_t *) nwfs_create },
+ { &vop_fsync_desc, (vop_t *) nwfs_fsync },
+ { &vop_getattr_desc, (vop_t *) nwfs_getattr },
+ { &vop_getpages_desc, (vop_t *) nwfs_getpages },
+ { &vop_putpages_desc, (vop_t *) nwfs_putpages },
+ { &vop_ioctl_desc, (vop_t *) nwfs_ioctl },
+ { &vop_inactive_desc, (vop_t *) nwfs_inactive },
+ { &vop_islocked_desc, (vop_t *) vop_noislocked },
+ { &vop_link_desc, (vop_t *) nwfs_link },
+ { &vop_lock_desc, (vop_t *) vop_sharedlock },
+ { &vop_lookup_desc, (vop_t *) nwfs_lookup },
+ { &vop_mkdir_desc, (vop_t *) nwfs_mkdir },
+ { &vop_mknod_desc, (vop_t *) nwfs_mknod },
+ { &vop_pathconf_desc, (vop_t *) nwfs_pathconf },
+ { &vop_print_desc, (vop_t *) nwfs_print },
+ { &vop_read_desc, (vop_t *) nwfs_read },
+ { &vop_readdir_desc, (vop_t *) nwfs_readdir },
+ { &vop_reclaim_desc, (vop_t *) nwfs_reclaim },
+ { &vop_remove_desc, (vop_t *) nwfs_remove },
+ { &vop_rename_desc, (vop_t *) nwfs_rename },
+ { &vop_rmdir_desc, (vop_t *) nwfs_rmdir },
+ { &vop_setattr_desc, (vop_t *) nwfs_setattr },
+ { &vop_strategy_desc, (vop_t *) nwfs_strategy },
+ { &vop_symlink_desc, (vop_t *) nwfs_symlink },
+ { &vop_unlock_desc, (vop_t *) vop_nounlock },
+ { &vop_write_desc, (vop_t *) nwfs_write },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc nwfs_vnodeop_opv_desc =
+ { &nwfs_vnodeop_p, nwfs_vnodeop_entries };
+
+VNODEOP_SET(nwfs_vnodeop_opv_desc);
+
+void nwfs_createname(char *_name,struct vnode *vp,struct componentname *cnp);
+
+
+void nwfs_createname(char *_name,struct vnode *vp,struct componentname *cnp){
+ strncpy(_name, cnp->cn_nameptr, cnp->cn_namelen);
+ _name[cnp->cn_namelen] = '\0';
+ ncp_str_upper(_name);
+}
+/*
+ * nwfs_access vnode op
+ * for now just return ok
+ */
+static int
+nwfs_access(ap)
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ struct ucred *cred = ap->a_cred;
+ u_int mode = ap->a_mode;
+ struct nwmount *nmp = VTONWFS(vp);
+ int error = 0;
+
+ NCPVNDEBUG("\n");
+ if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+ switch (vp->v_type) {
+ case VREG: case VDIR: case VLNK:
+ return (EROFS);
+ default:
+ break;
+ }
+ }
+ if (cred->cr_uid == 0)
+ return 0;
+ if (cred->cr_uid != nmp->m.uid) {
+ mode >>= 3;
+ if (!groupmember(nmp->m.gid, cred))
+ mode >>= 3;
+ }
+ error = (((vp->v_type == VREG) ? nmp->m.file_mode : nmp->m.dir_mode) & mode) == mode ? 0 : EACCES;
+ return error;
+}
+/*
+ * nwfs_open vnode op
+ */
+/* ARGSUSED */
+static int
+nwfs_open(ap)
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ int mode = ap->a_mode;
+ struct nwnode *np = VTONW(vp);
+ struct ncp_open_info no;
+ struct nwmount *nmp = VTONWFS(vp);
+ struct vattr vattr;
+ int error, nwm;
+
+ NCPVNDEBUG("%s,%d\n",np->n_name, np->opened);
+ if (vp->v_type != VREG && vp->v_type != VDIR) {
+ NCPFATAL("open eacces vtype=%d\n", vp->v_type);
+ return (EACCES);
+ }
+ if (vp->v_type == VDIR) return 0; /* nothing to do now */
+ if (np->n_flag & NMODIFIED) {
+ if ((error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR)
+ return (error);
+ np->n_atime = 0;
+ error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+ if (error) return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ } else {
+ error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+ if (error) return (error);
+ if (np->n_mtime != vattr.va_mtime.tv_sec) {
+ if ((error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR)
+ return (error);
+ np->n_mtime = vattr.va_mtime.tv_sec;
+ }
+ }
+ if (np->opened) {
+ np->opened++;
+ return 0;
+ }
+ nwm = AR_READ;
+ if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
+ nwm |= AR_WRITE;
+ error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN,
+ 0, nwm, &no, ap->a_p, ap->a_cred);
+ if (error) {
+ if (mode & FWRITE)
+ return EACCES;
+ nwm = AR_READ;
+ error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
+ nwm, &no, ap->a_p,ap->a_cred);
+ }
+ if (!error) {
+ np->opened++;
+ np->n_fh = no.fh;
+ np->n_origfh = no.origfh;
+ }
+ np->n_atime = 0;
+ return (error);
+}
+
+static int
+nwfs_close(ap)
+ struct vop_close_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct nwnode *np = VTONW(vp);
+ int error;
+
+ NCPVNDEBUG("name=%s,pid=%d,c=%d\n",np->n_name,ap->a_p->p_pid,np->opened);
+
+ if (vp->v_type == VDIR) return 0; /* nothing to do now */
+ error = 0;
+ simple_lock(&vp->v_interlock);
+ if (np->opened == 0) {
+ simple_unlock(&vp->v_interlock);
+ return 0;
+ }
+ error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
+ if (--np->opened == 0) {
+ error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, ap->a_p,ap->a_cred);
+ }
+ simple_unlock(&vp->v_interlock);
+ np->n_atime = 0;
+ return (error);
+}
+
+/*
+ * nwfs_getattr call from vfs.
+ */
+static int
+nwfs_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct nwnode *np = VTONW(vp);
+ struct vattr *va=ap->a_vap;
+ struct nwmount *nmp = VTONWFS(vp);
+ struct nw_entry_info fattr;
+ int error;
+ u_int32_t oldsize;
+
+ NCPVNDEBUG("%lx:%d: '%s' %d\n", (long)vp, nmp->n_volume, np->n_name, (vp->v_flag & VROOT) != 0);
+ error = nwfs_attr_cachelookup(vp,va);
+ if (!error) return 0;
+ NCPVNDEBUG("not in cache\n");
+ oldsize = np->n_size;
+ if (np->n_flag & NVOLUME) {
+ error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, &fattr,
+ ap->a_p,ap->a_cred);
+ } else {
+ error = ncp_obtain_info(nmp, np->n_fid.f_parent, np->n_nmlen,
+ np->n_name, &fattr, ap->a_p, ap->a_cred);
+ }
+ if (error) {
+ NCPVNDEBUG("error %d\n", error);
+ return error;
+ }
+ nwfs_attr_cacheenter(vp, &fattr);
+ *va = np->n_vattr;
+ if (np->opened)
+ np->n_size = oldsize;
+ return (0);
+}
+/*
+ * nwfs_setattr call from vfs.
+ */
+static int
+nwfs_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct nwnode *np = VTONW(vp);
+ register struct vattr *vap = ap->a_vap;
+ u_quad_t tsize=0;
+ int error = 0;
+
+ NCPVNDEBUG("\n");
+ if (vap->va_flags != VNOVAL)
+ return (EOPNOTSUPP);
+ /*
+ * Disallow write attempts if the filesystem is mounted read-only.
+ */
+ if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL ||
+ vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
+ vap->va_mode != (mode_t)VNOVAL) &&(vp->v_mount->mnt_flag & MNT_RDONLY))
+ return (EROFS);
+ if (vap->va_size != VNOVAL) {
+ switch (vp->v_type) {
+ case VDIR:
+ return (EISDIR);
+ case VREG:
+ /*
+ * Disallow write attempts if the filesystem is
+ * mounted read-only.
+ */
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ vnode_pager_setsize(vp, (u_long)vap->va_size);
+ tsize = np->n_size;
+ np->n_size = vap->va_size;
+ break;
+ default:
+ return EINVAL;
+ };
+ }
+ error = ncp_setattr(vp, vap, ap->a_cred, ap->a_p);
+ if (error && vap->va_size != VNOVAL) {
+ np->n_size = tsize;
+ vnode_pager_setsize(vp, (u_long)tsize);
+ }
+ np->n_atime = 0; /* invalidate cache */
+ VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
+ np->n_mtime = vap->va_mtime.tv_sec;
+ return (0);
+}
+/*
+ * nwfs_read call.
+ */
+static int
+nwfs_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ struct uio *uio=ap->a_uio;
+ int error;
+ NCPVNDEBUG("nwfs_read:\n");
+
+ if (vp->v_type != VREG && vp->v_type != VDIR)
+ return (EPERM);
+ error = nwfs_readvnode(vp, uio, ap->a_cred);
+ return error;
+}
+
+static int
+nwfs_write(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ int error;
+
+ NCPVNDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid);
+
+ if (vp->v_type != VREG)
+ return (EPERM);
+ error = nwfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag);
+ return(error);
+}
+/*
+ * nwfs_create call
+ * Create a regular file. On entry the directory to contain the file being
+ * created is locked. We must release before we return. We must also free
+ * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
+ * only if the SAVESTART bit in cn_flags is clear on success.
+ */
+static int
+nwfs_create(ap)
+ struct vop_create_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ register struct vnode *dvp = ap->a_dvp;
+ register struct vattr *vap = ap->a_vap;
+ struct vnode **vpp=ap->a_vpp;
+ register struct componentname *cnp = ap->a_cnp;
+ struct vnode *vp = (struct vnode *)0;
+ int error = 0, fmode;
+ struct vattr vattr;
+ struct nwnode *np;
+ struct ncp_open_info no;
+ struct nwmount *nmp=VTONWFS(dvp);
+ ncpfid fid;
+
+
+ NCPVNDEBUG("\n");
+ *vpp = NULL;
+ if (vap->va_type == VSOCK)
+ return (EOPNOTSUPP);
+ if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
+ VOP_ABORTOP(dvp, cnp);
+ return (error);
+ }
+ fmode = AR_READ | AR_WRITE;
+/* if (vap->va_vaflags & VA_EXCLUSIVE)
+ fmode |= AR_DENY_READ | AR_DENY_WRITE;*/
+
+ error = ncp_open_create_file_or_subdir(nmp,dvp,cnp->cn_namelen,cnp->cn_nameptr,
+ OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
+ 0, fmode, &no, cnp->cn_proc, cnp->cn_cred);
+ if (!error) {
+ error = ncp_close_file(NWFSTOCONN(nmp), &no.fh, cnp->cn_proc,cnp->cn_cred);
+ fid.f_parent = VTONW(dvp)->n_fid.f_id;
+ fid.f_id = no.fattr.dirEntNum;
+ error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &vp);
+ if (!error) {
+ np = VTONW(vp);
+ np->opened = 0;
+ *vpp = vp;
+ }
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, vp, cnp);
+ }
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+}
+
+/*
+ * nwfs_remove call. It isn't possible to emulate UFS behaivour because
+ * NetWare doesn't allow delete/rename operations on an opened file.
+ */
+static int
+nwfs_remove(ap)
+ struct vop_remove_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_dvp;
+ struct vnode * a_vp;
+ struct componentname * a_cnp;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct vnode *dvp = ap->a_dvp;
+ register struct componentname *cnp = ap->a_cnp;
+ register struct nwnode *np = VTONW(vp);
+ struct nwmount *nmp = VTONWFS(vp);
+ int error;
+
+ if (vp->v_type == VDIR || np->opened || vp->v_usecount != 1) {
+ error = EPERM;
+ } else if (!ncp_conn_valid(NWFSTOCONN(nmp))) {
+ error = EIO;
+ } else {
+ cache_purge(vp);
+ error = ncp_DeleteNSEntry(nmp, VTONW(dvp)->n_fid.f_id,
+ cnp->cn_namelen,cnp->cn_nameptr,cnp->cn_proc,cnp->cn_cred);
+ if (error == 0x899c) error = EACCES;
+ }
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+}
+
+/*
+ * nwfs_file rename call
+ */
+static int
+nwfs_rename(ap)
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap;
+{
+ register struct vnode *fvp = ap->a_fvp;
+ register struct vnode *tvp = ap->a_tvp;
+ register struct vnode *fdvp = ap->a_fdvp;
+ register struct vnode *tdvp = ap->a_tdvp;
+ register struct componentname *tcnp = ap->a_tcnp;
+ register struct componentname *fcnp = ap->a_fcnp;
+ struct nwmount *nmp=VTONWFS(fvp);
+ u_int16_t oldtype = 6;
+ int error=0;
+
+ /* Check for cross-device rename */
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+ goto out;
+ }
+
+ if (tvp && tvp->v_usecount > 1) {
+ error = EBUSY;
+ goto out;
+ }
+ if (tvp && tvp != fvp) {
+ error = ncp_DeleteNSEntry(nmp, VTONW(tdvp)->n_fid.f_id,
+ tcnp->cn_namelen, tcnp->cn_nameptr,
+ tcnp->cn_proc, tcnp->cn_cred);
+ if (error == 0x899c) error = EACCES;
+ if (error)
+ goto out;
+ }
+ if (fvp->v_type == VDIR) {
+ oldtype |= NW_TYPE_SUBDIR;
+ } else if (fvp->v_type == VREG) {
+ oldtype |= NW_TYPE_FILE;
+ } else
+ return EINVAL;
+ error = ncp_nsrename(NWFSTOCONN(nmp), nmp->n_volume, nmp->name_space,
+ oldtype, &nmp->m.nls,
+ VTONW(fdvp)->n_fid.f_id, fcnp->cn_nameptr, fcnp->cn_namelen,
+ VTONW(tdvp)->n_fid.f_id, tcnp->cn_nameptr, tcnp->cn_namelen,
+ tcnp->cn_proc,tcnp->cn_cred);
+
+ if (error == 0x8992)
+ error = EEXIST;
+ if (fvp->v_type == VDIR) {
+ if (tvp != NULL && tvp->v_type == VDIR)
+ cache_purge(tdvp);
+ cache_purge(fdvp);
+ }
+out:
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ vrele(fdvp);
+ vrele(fvp);
+ nwfs_attr_cacheremove(fdvp);
+ nwfs_attr_cacheremove(tdvp);
+ /*
+ * Need to get rid of old vnodes, because netware will change
+ * file id on rename
+ */
+ vgone(fvp);
+ if (tvp)
+ vgone(tvp);
+ /*
+ * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
+ */
+ if (error == ENOENT)
+ error = 0;
+ return (error);
+}
+
+/*
+ * nwfs hard link create call
+ * Netware filesystems don't know what links are. But since we already called
+ * nwfs_lookup() with create and lockparent, the parent is locked so we
+ * have to free it before we return the error.
+ */
+static int
+nwfs_link(ap)
+ struct vop_link_args /* {
+ struct vnode *a_tdvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+/* VOP_ABORTOP(ap->a_tdvp, ap->a_cnp);*/
+ zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ return EOPNOTSUPP;
+}
+
+/*
+ * nwfs_symlink link create call
+ * Netware filesystems don't know what symlinks are.
+ */
+static int
+nwfs_symlink(ap)
+ struct vop_symlink_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ char *a_target;
+ } */ *ap;
+{
+ zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
+ return (EOPNOTSUPP);
+}
+
+static int nwfs_mknod(ap)
+ struct vop_mknod_args /* {
+ } */ *ap;
+{
+ return (EOPNOTSUPP);
+}
+
+/*
+ * nwfs_mkdir call
+ */
+static int
+nwfs_mkdir(ap)
+ struct vop_mkdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ register struct vnode *dvp = ap->a_dvp;
+/* register struct vattr *vap = ap->a_vap;*/
+ register struct componentname *cnp = ap->a_cnp;
+ register int len=cnp->cn_namelen;
+ struct ncp_open_info no;
+ struct nwnode *np;
+ struct vnode *newvp = (struct vnode *)0;
+ ncpfid fid;
+ int error = 0;
+ struct vattr vattr;
+ char *name=cnp->cn_nameptr;
+
+ if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
+ VOP_ABORTOP(dvp, cnp);
+ return (error);
+ }
+ if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) {
+ VOP_ABORTOP(dvp, cnp);
+ return EEXIST;
+ }
+ if (ncp_open_create_file_or_subdir(VTONWFS(dvp),dvp, cnp->cn_namelen,
+ cnp->cn_nameptr,OC_MODE_CREATE, aDIR, 0xffff,
+ &no, cnp->cn_proc, cnp->cn_cred) != 0) {
+ error = EACCES;
+ } else {
+ error = 0;
+ }
+ if (!error) {
+ fid.f_parent = VTONW(dvp)->n_fid.f_id;
+ fid.f_id = no.fattr.dirEntNum;
+ error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &newvp);
+ if (!error) {
+ np = VTONW(newvp);
+ newvp->v_type = VDIR;
+ *ap->a_vpp = newvp;
+ }
+ }
+ zfree(namei_zone, cnp->cn_pnbuf);
+ return (error);
+}
+
+/*
+ * nwfs_remove directory call
+ */
+static int
+nwfs_rmdir(ap)
+ struct vop_rmdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct vnode *dvp = ap->a_dvp;
+ register struct componentname *cnp = ap->a_cnp;
+ struct nwmount *nmp = VTONWFS(vp);
+ struct nwnode *dnp = VTONW(dvp);
+ int error = EIO;
+
+ if (dvp == vp) return EINVAL;
+ if (!ncp_conn_valid(NWFSTOCONN(nmp))) return(error);
+
+ error = ncp_DeleteNSEntry(nmp, dnp->n_fid.f_id,
+ cnp->cn_namelen, cnp->cn_nameptr,cnp->cn_proc,cnp->cn_cred);
+ if (error == NWE_DIR_NOT_EMPTY) error = ENOTEMPTY;
+ zfree(namei_zone, cnp->cn_pnbuf);
+ dnp->n_flag |= NMODIFIED;
+ nwfs_attr_cacheremove(dvp);
+ cache_purge(dvp);
+ cache_purge(vp);
+ return (error);
+}
+
+/*
+ * nwfs_readdir call
+ */
+static int
+nwfs_readdir(ap)
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct uio *uio = ap->a_uio;
+ int error;
+
+ if (vp->v_type != VDIR)
+ return (EPERM);
+ if (ap->a_ncookies) {
+ printf("nwfs_readdir: no support for cookies now...");
+ return (EOPNOTSUPP);
+ }
+
+ error = nwfs_readvnode(vp, uio, ap->a_cred);
+ return error;
+}
+/* ARGSUSED */
+static int
+nwfs_fsync(ap)
+ struct vop_fsync_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_vp;
+ struct ucred * a_cred;
+ int a_waitfor;
+ struct proc * a_p;
+ } */ *ap;
+{
+/* return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));*/
+ return (0);
+}
+/* ARGSUSED */
+static
+int nwfs_print (ap)
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ return (0);
+}
+
+static int nwfs_pathconf (ap)
+ struct vop_pathconf_args /* {
+ struct vnode *vp;
+ int name;
+ int *retval;
+ } */ *ap;
+{
+ int name=ap->a_name, error=0;
+ int *retval=ap->a_retval;
+
+ switch(name){
+ case _PC_LINK_MAX:
+ *retval=0;
+ break;
+ case _PC_NAME_MAX:
+ *retval=NCP_MAX_FILENAME; /* XXX from nwfsnode */
+ break;
+ case _PC_PATH_MAX:
+ *retval=NCP_MAXPATHLEN; /* XXX from nwfsnode */
+ break;
+ default:
+ error=EINVAL;
+ }
+ return(error);
+}
+
+static int nwfs_strategy (ap)
+ struct vop_strategy_args /* {
+ struct buf *a_bp
+ } */ *ap;
+{
+ struct buf *bp=ap->a_bp;
+ struct ucred *cr;
+ struct proc *p;
+ int error = 0;
+
+ NCPVNDEBUG("\n");
+ if (bp->b_flags & B_PHYS)
+ panic("nwfs physio");
+ if (bp->b_flags & B_ASYNC)
+ p = (struct proc *)0;
+ else
+ p = curproc; /* XXX */
+ if (bp->b_flags & B_READ)
+ cr = bp->b_rcred;
+ else
+ cr = bp->b_wcred;
+ /*
+ * If the op is asynchronous and an i/o daemon is waiting
+ * queue the request, wake it up and wait for completion
+ * otherwise just do it ourselves.
+ */
+ if ((bp->b_flags & B_ASYNC) == 0 )
+ error = nwfs_doio(bp, cr, p);
+ return (error);
+}
+
+static int
+nwfs_bmap(ap)
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct vnode **a_vpp;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+
+ if (ap->a_vpp != NULL)
+ *ap->a_vpp = vp;
+ if (ap->a_bnp != NULL)
+ *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
+ if (ap->a_runp != NULL)
+ *ap->a_runp = 0;
+ if (ap->a_runb != NULL)
+ *ap->a_runb = 0;
+ return (0);
+}
+/*
+ * nwfs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Currently nothing to do.
+ */
+/* ARGSUSED */
+int
+nwfs_abortop(ap)
+ struct vop_abortop_args /* {
+ struct vnode *a_dvp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+
+ if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
+ zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ return (0);
+}
+
+int
+nwfs_nget(struct mount *mp, ncpfid fid, struct nw_entry_info *fap,
+ struct vnode *dvp, struct vnode **vpp)
+{
+ int error;
+ struct nwnode *newnp;
+ struct vnode *vp;
+
+ *vpp = NULL;
+ error = nwfs_allocvp(mp, fid, &vp);
+ if (error)
+ return error;
+ newnp = VTONW(vp);
+ if (fap) {
+ if (newnp->n_flag & NNEW) {
+ newnp->n_nmlen = fap->nameLen;
+ bcopy(fap->entryName, newnp->n_name, newnp->n_nmlen);
+ newnp->n_name[fap->nameLen] = 0;
+ }
+ newnp->n_attr = fap->attributes;
+ newnp->n_dosfid = fap->DosDirNum;
+ vp->v_type = newnp->n_attr & aDIR ? VDIR : VREG;
+ nwfs_attr_cacheenter(vp, fap);
+ }
+ if (dvp) {
+ newnp->n_parent = VTONW(dvp)->n_fid;
+ if ((newnp->n_flag & NNEW) && vp->v_type == VDIR) {
+ if ((dvp->v_flag & VROOT) == 0) {
+ newnp->n_refparent = 1;
+ vref(dvp); /* vhold */
+ }
+ }
+ } else {
+ if ((newnp->n_flag & NNEW) && vp->v_type == VREG)
+ printf("new vnode '%s' borned without parent ?\n",newnp->n_name);
+ }
+ newnp->n_flag &= ~NNEW;
+ *vpp = vp;
+ return 0;
+}
+
+/*
+ * How to keep the brain busy ...
+ * Currently lookup routine can make two lookup for vnode. This can be
+ * avoided by reorg the code.
+ */
+int
+nwfs_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ int flags = cnp->cn_flags;
+ struct vnode *vp;
+ struct nwmount *nmp;
+ struct mount *mp = dvp->v_mount;
+ struct nwnode *dnp, *npp;
+ struct nw_entry_info fattr, *fap;
+ ncpfid fid;
+ int nameiop=cnp->cn_nameiop, islastcn;
+ int lockparent, wantparent, error = 0, notfound;
+ struct proc *p = cnp->cn_proc;
+ char _name[cnp->cn_namelen+1];
+ bcopy(cnp->cn_nameptr,_name,cnp->cn_namelen);
+ _name[cnp->cn_namelen]=0;
+
+ if (dvp->v_type != VDIR)
+ return (ENOTDIR);
+ if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) {
+ printf("nwfs_lookup: invalid '..'\n");
+ return EIO;
+ }
+
+ NCPVNDEBUG("%d '%s' in '%s' id=d\n", nameiop, _name,
+ VTONW(dvp)->n_name/*, VTONW(dvp)->n_name*/);
+
+ islastcn = flags & ISLASTCN;
+ if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP))
+ return (EROFS);
+ if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p)))
+ return (error);
+ lockparent = flags & LOCKPARENT;
+ wantparent = flags & (LOCKPARENT|WANTPARENT);
+ nmp = VFSTONWFS(mp);
+ dnp = VTONW(dvp);
+/*
+printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & ISDOTDOT);
+*/
+ error = ncp_pathcheck(cnp->cn_nameptr, cnp->cn_namelen, &nmp->m.nls,
+ (nameiop == CREATE || nameiop == RENAME) && (nmp->m.nls.opt & NWHP_NOSTRICT) == 0);
+ if (error)
+ return ENOENT;
+
+ error = cache_lookup(dvp, vpp, cnp);
+ NCPVNDEBUG("cache_lookup returned %d\n",error);
+ if (error > 0)
+ return error;
+ if (error) { /* name was found */
+ struct vattr vattr;
+ int vpid;
+
+ vp = *vpp;
+ vpid = vp->v_id;
+ if (dvp == vp) { /* lookup on current */
+ vref(vp);
+ error = 0;
+ NCPVNDEBUG("cached '.'");
+ } else if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p); /* unlock parent */
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (!error && lockparent && islastcn)
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ } else {
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (!lockparent || error || !islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ if (!error) {
+ if (vpid == vp->v_id) {
+ if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, p)
+ && vattr.va_ctime.tv_sec == VTONW(vp)->n_ctime) {
+ if (nameiop != LOOKUP && islastcn)
+ cnp->cn_flags |= SAVENAME;
+ NCPVNDEBUG("use cached vnode");
+ return (0);
+ }
+ cache_purge(vp);
+ }
+ vput(vp);
+ if (lockparent && dvp != vp && islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ *vpp = NULLVP;
+ if (error)
+ return (error);
+ }
+ /* not in cache, so ... */
+ error = 0;
+ *vpp = NULLVP;
+ fap = NULL;
+ if (flags & ISDOTDOT) {
+ if (NWCMPF(&dnp->n_parent, &nmp->n_rootent)) {
+ fid = nmp->n_rootent;
+ fap = NULL;
+ notfound = 0;
+ } else {
+ error = nwfs_lookupnp(nmp, dnp->n_parent, &npp);
+ if (error) {
+ return error;
+ }
+ fid = dnp->n_parent;
+ fap = &fattr;
+ /*np = *npp;*/
+ notfound = ncp_obtain_info(nmp, npp->n_dosfid,
+ 0, NULL, fap, p, cnp->cn_cred);
+ }
+ } else {
+ fap = &fattr;
+ notfound = ncp_lookup(dvp, cnp->cn_namelen, cnp->cn_nameptr,
+ fap, p, cnp->cn_cred);
+ fid.f_parent = dnp->n_fid.f_id;
+ fid.f_id = fap->dirEntNum;
+ NCPVNDEBUG("call to ncp_lookup returned=%d\n",notfound);
+ }
+ if (notfound && notfound < 0x80 )
+ return (notfound); /* hard error */
+ if (notfound) { /* entry not found */
+ /* Handle RENAME or CREATE case... */
+ if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) {
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent)
+ VOP_UNLOCK(dvp, 0, p);
+ return (EJUSTRETURN);
+ }
+ return ENOENT;
+ }/* else {
+ NCPVNDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum);
+ }*/
+ /* handle DELETE case ... */
+ if (nameiop == DELETE && islastcn) { /* delete last component */
+ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error) return (error);
+ if (NWCMPF(&dnp->n_fid, &fid)) { /* we found ourselfs */
+ VREF(dvp);
+ *vpp = dvp;
+ return 0;
+ }
+ error = nwfs_nget(mp, fid, fap, dvp, &vp);
+ if (error) return (error);
+ *vpp = vp;
+ cnp->cn_flags |= SAVENAME; /* I free it later */
+ if (!lockparent) VOP_UNLOCK(dvp,0,p);
+ return (0);
+ }
+ if (nameiop == RENAME && islastcn && wantparent) {
+ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error) return (error);
+ if (NWCMPF(&dnp->n_fid, &fid)) return EISDIR;
+ error = nwfs_nget(mp, fid, fap, dvp, &vp);
+ if (error) return (error);
+ *vpp = vp;
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent)
+ VOP_UNLOCK(dvp,0,p);
+ return (0);
+ }
+ if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p); /* race to get the inode */
+ error = nwfs_nget(mp, fid, NULL, NULL, &vp);
+ if (error) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
+ }
+ if (lockparent && islastcn &&
+ (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
+ vput(vp);
+ return (error);
+ }
+ *vpp = vp;
+ } else if (NWCMPF(&dnp->n_fid, &fid)) {
+ vref(dvp);
+ *vpp = dvp;
+ } else {
+ error = nwfs_nget(mp, fid, fap, dvp, &vp);
+ if (error) return (error);
+ *vpp = vp;
+ NCPVNDEBUG("lookup: getnewvp!\n");
+ if (!lockparent || !islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) {
+ VTONW(*vpp)->n_ctime = VTONW(*vpp)->n_vattr.va_ctime.tv_sec;
+ cache_enter(dvp, *vpp, cnp);
+ }
+ return (0);
+}
OpenPOWER on IntegriCloud