/*
 * copyright (c) 2004
 * the regents of the university of michigan
 * all rights reserved
 * 
 * permission is granted to use, copy, create derivative works and redistribute
 * this software and such derivative works for any purpose, so long as the name
 * of the university of michigan is not used in any advertising or publicity
 * pertaining to the use or distribution of this software without specific,
 * written prior authorization.  if the above copyright notice or any other
 * identification of the university of michigan is included in any copy of any
 * portion of this software, then the disclaimer below must also be included.
 * 
 * this software is provided as is, without representation from the university
 * of michigan as to its fitness for any purpose, and without warranty by the
 * university of michigan of any kind, either express or implied, including
 * without limitation the implied warranties of merchantability and fitness for
 * a particular purpose. the regents of the university of michigan shall not be
 * liable for any damages, including special, indirect, incidental, or
 * consequential damages, with respect to any claim arising out of or in
 * connection with the use of the software, even if it has been or is hereafter
 * advised of the possibility of such damages.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/unistd.h>
#include <sys/vnode.h>
#include <sys/queue.h>

#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>

#include <nfs4client/nfs4_glue.h>

#include <rpc/rpcclnt.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs4client/nfs4.h>
#include <nfs/nfsnode.h>
#include <nfs/nfsmount.h>
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/nfsdiskless.h>
#include <nfs/nfs_socket.h>

#include <nfs/nfs_vfsops.h>

#include <nfs4client/nfs4m_subs.h>
#include <nfs4client/nfs4_vfs.h>
#include <nfs4client/nfs4m_glue.h>

#include <string.h>

/* This is Darwin specific. */

static int _do_renew(struct nfsmount *, struct ucred *);

int nfs4_renewd_wchan = 0;
int nfs4_renewd_invoked = 0;

/* We get the kernel funnel on invocation here. */
int
nfs4_darwin_syscall(p, args, retval)
	struct proc *p;
	void *args;
	int *retval;
{
	struct mount *mp;
	struct nfsmount *nmp;
	int error;

	/* Supah-Usah */
	error = suser(p->p_ucred, &p->p_acflag);
	if (error != 0)
		return (error);

	/* XXX protect */
	nfs4_renewd_invoked = 1;

	for (;;) {
		simple_lock(&mountlist_slock);
		CIRCLEQ_FOREACH(mp, &mountlist, mnt_list) {
			if (strcmp(mp->mnt_vfc->vfc_name, "nfs4") != 0)
				continue;			

			nmp = VFSTONFS(mp);
			if (time_second < nmp->nm_last_renewal + nmp->nm_lease_time - 4)
				continue;
			_do_renew(nmp, nmp->nm_mntcred);
		}
		simple_unlock(&mountlist_slock);

		if (tsleep(&nfs4_renewd_wchan, PVFS | PCATCH, "nfs4", 2 * hz) != EWOULDBLOCK)
			goto done;
	}

 done:
	nfs4_renewd_invoked = 0;
	return (0);
}

static int
_do_renew(struct nfsmount *nmp, struct ucred *cred)
{
	struct nfs4_compound cp;
	struct mbuf *mreq, *mrep = NULL, *md, *mb;
	caddr_t bpos, dpos;	
	int error;

	mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, sizeof(uint64_t));
	mb = mreq;
	bpos = mtod(mb, caddr_t);

	nfs_v4initcompound(&cp);

	nfsm_v4build_compound(&cp, "nfs4_do_renew()");
	nfsm_v4build_renew(&cp, nmp->nm_clientid);
	nfsm_v4build_finalize(&cp);

	nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curcthread, cred);
	if (error != 0)
		goto nfsmout;

	nfsm_v4dissect_compound(&cp);
	nfsm_v4dissect_renew(&cp);
	nmp->nm_last_renewal = time_second;
	return (0);

 nfsmout:
	error = nfs_v4postop(&cp, error);

	/* XXX */
	if (mrep != NULL)
		m_freem(mrep);
	return (error);
}
