/*
 * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_IPP_IPP_IMPL_H
#define	_IPP_IPP_IMPL_H

#pragma ident	"@(#)ipp_impl.h	1.2	03/05/02 SMI"

/*
 * IP Policy Framework (IPPF) implementation detail.
 *
 * WARNING: Everything in this file is private, belonging to the IPPF
 * subsystem.  The interfaces and declarations made here are subject
 * to change.
 */

#include <sys/stream.h>
#include <sys/thread.h>
#include <ipp/ipp.h>

#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	_KERNEL

#define	IPP_ALIGN		64

#define	IPP_NBUCKET		23

#define	IPP_LOG2NACTION		16
#define	IPP_NACTION		(1 << IPP_LOG2NACTION)

#define	IPP_LOG2NMOD		6
#define	IPP_NMOD		(1 << IPP_LOG2NMOD)

#define	IPP_NCLASS		5
#define	IPP_NLOG		IPP_NMOD

typedef	struct ipp_ref	ipp_ref_t;

struct ipp_ref {
	ipp_ref_t		*ippr_nextp;
	uint_t			ippr_count;
	union {
	    ipp_mod_t		*u_mod;
	    ipp_action_t	*u_action;
	    void		*u_ptr;
	} ippr_u;
};

#define	ippr_action	ippr_u.u_action
#define	ippr_mod	ippr_u.u_mod
#define	ippr_ptr	ippr_u.u_ptr

typedef enum {
	IPP_MODSTATE_PROTO = 0x10,
	IPP_MODSTATE_AVAILABLE
} ipp_modstate_t;

struct ipp_mod {
	ipp_mod_id_t	ippm_id;
	ipp_ops_t	*ippm_ops;
	ipp_ref_t	*ippm_action;
	ipp_modstate_t	ippm_state;
	krwlock_t	ippm_lock[1];
	uint32_t	ippm_hold_count;
	boolean_t	ippm_destruct_pending;
	char		ippm_name[MAXNAMELEN];
};

typedef enum {
	IPP_ASTATE_PROTO = 0x20,
	IPP_ASTATE_CONFIG_PENDING,
	IPP_ASTATE_AVAILABLE
} ipp_astate_t;

typedef struct cfglock {
	kmutex_t	cl_mutex[1];
	kcondvar_t	cl_cv[1];
	uint_t		cl_writers;
	boolean_t	cl_reader;
	kthread_id_t	cl_owner;
} cfglock_t;

#ifndef	__lint

#define	CL_READ		0
#define	CL_WRITE	1

#define	CONFIG_LOCK_INIT(_clp)						\
	{								\
		mutex_init((_clp)->cl_mutex, NULL, MUTEX_DEFAULT,	\
		    (void *)ipltospl(LOCK_LEVEL));			\
		cv_init((_clp)->cl_cv, NULL, CV_DEFAULT, NULL);		\
	}

#define	CONFIG_LOCK_FINI(_clp)						\
	{								\
		mutex_destroy((_clp)->cl_mutex);			\
		cv_destroy((_clp)->cl_cv);				\
	}

#define	CONFIG_LOCK_ENTER(_clp, _rw)					\
	{								\
		mutex_enter((_clp)->cl_mutex);				\
		if ((_rw) == CL_WRITE) {				\
			while ((_clp)->cl_reader ||			\
			    ((_clp)->cl_owner != NULL &&		\
			    (_clp)->cl_owner != curthread))		\
				cv_wait((_clp)->cl_cv,			\
				    (_clp)->cl_mutex);			\
			(_clp)->cl_owner = curthread;			\
			(_clp)->cl_writers++;				\
		}							\
		else if ((_rw) == CL_READ) {				\
			while ((_clp)->cl_reader ||			\
			    (_clp)->cl_writers > 0) {			\
				ASSERT((_clp)->cl_owner != curthread);	\
				cv_wait((_clp)->cl_cv,			\
				    (_clp)->cl_mutex);			\
			}						\
			(_clp)->cl_owner = curthread;			\
			(_clp)->cl_reader = B_TRUE;			\
		}							\
		mutex_exit((_clp)->cl_mutex);				\
	}

#define	CONFIG_LOCK_EXIT(_clp)						\
	{								\
		mutex_enter((_clp)->cl_mutex);				\
		if ((_clp)->cl_reader) {				\
			(_clp)->cl_reader = B_FALSE;			\
			(_clp)->cl_owner = NULL;			\
			cv_broadcast((_clp)->cl_cv);			\
		} else {						\
			ASSERT((_clp)->cl_writers != 0);		\
			(_clp)->cl_writers--;				\
			if ((_clp)->cl_writers == 0) {			\
				(_clp)->cl_owner = NULL;		\
				cv_broadcast((_clp)->cl_cv);		\
			}						\
		}							\
		mutex_exit((_clp)->cl_mutex);				\
	}

#else	/* __lint */

#define	CONFIG_LOCK_INIT(_clp)
#define	CONFIG_LOCK_FINI(_clp)
#define	CONFIG_LOCK_ENTER(_clp, _rw)
#define	CONFIG_LOCK_EXIT(_clp)

#endif	/* __lint */

struct ipp_action {
	ipp_action_id_t	ippa_id;
	ipp_mod_t	*ippa_mod;
	ipp_ref_t	*ippa_ref;
	ipp_ref_t	*ippa_refby;
	void		*ippa_ptr;
	uint32_t	ippa_packets;
	ipp_astate_t	ippa_state;
	krwlock_t	ippa_lock[1];
	uint32_t	ippa_hold_count;
	boolean_t	ippa_destruct_pending;
	cfglock_t	ippa_config_lock[1];
	boolean_t	ippa_nameless;
	char		ippa_name[MAXNAMELEN];
	ipp_ref_t	**ippa_condemned;
};

struct ipp_class {
	ipp_action_id_t	ippc_aid;
	char		ippc_name[MAXNAMELEN];
};

struct ipp_log {
	ipp_action_id_t	ippl_aid;
	timespec_t	ippl_begin;
	timespec_t	ippl_end;
	char		ippl_name[MAXNAMELEN];
};

typedef struct ipp_stat_impl	ipp_stat_impl_t;

struct ipp_stat_impl {
	void		*ippsi_data;
	kstat_t		*ippsi_ksp;
	int		ippsi_limit;
	int		ippsi_count;
	int		(*ippsi_update)(ipp_stat_t *, void *, int);
	void		*ippsi_arg;
	kmutex_t	ippsi_lock[1];
	char		ippsi_name[MAXNAMELEN];
};

struct ipp_packet {
	mblk_t		*ippp_data;
	ipp_class_t	*ippp_class_array;
	uint_t		ippp_class_limit;
	uint_t		ippp_class_rindex;
	uint_t		ippp_class_windex;
	ipp_log_t	*ippp_log;
	uint_t		ippp_log_limit;
	uint_t		ippp_log_windex;
	void		*ippp_private;
	void		(*ippp_private_free)(void *);
};

extern void		ipp_init(void);

#endif	/* _KERNEL */

#ifdef __cplusplus
}
#endif

#endif /* _IPP_IPP_IMPL_H */
