OpenSS7
SS7 for the
Common Man

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified:

Home Overview Status News Documentation Resources About
   
 Overview
 Status
 News
 Documentation
 Resources
 About

   
Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sdli/spm.c


File /code/strss7/drivers/sdli/spm.c



#ident "@(#) $RCSfile: spm.c,v $ $Name:  $($Revision: 0.8.2.1 $) $Date: 2003/04/03 19:50:57 $"

static char const ident[] = "$RCSfile: spm.c,v $ $Name:  $($Revision: 0.8.2.1 $) $Date: 2003/04/03 19:50:57 $";

/*
 *  This is an SDL pipemod driver for testing and use with pipes.  This module
 *  is pushed on one side of the pipe (after pipemod) to make a pipe appear as
 *  a directly connected pair of SDL drivers.
 */

#define _DEBUG 1

#include <linux/config.h>
#include <linux/version.h>
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/module.h>

#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/cmn_err.h>

#include "../priv.h"
#include "../debug.h"
#include "../lock.h"
#include "../allocb.h"
#include "../queue.h"
#include "../bufq.h"

#include <ss7/lmi.h>
#include <ss7/lmi_ioctl.h>

#include <ss7/sdli.h>
#include <ss7/sdli_ioctl.h>

#define SPM_DESCRIP	"SS7/SDL: (Signalling Data Terminal) STREAMS PIPE MODULE."
#define SPM_COPYRIGHT	"Copyright (c) 1997-2002 OpenSS7 Corporation.  All Rights Reserved."
#define SPM_DEVICES	"Provides OpenSS7 SDL pipe driver."
#define SPM_CONTACT	"Brian Bidulock <bidulock@openss7.org>"
#define SPM_BANNER	SPM_DESCRIP	"\n" \
			SPM_COPYRIGHT	"\n" \
			SPM_DEVICES	"\n" \
			SPM_CONTACT	"\n"
#define SPM_LICENSE	"GPL"

MODULE_AUTHOR(SPM_CONTACT);
MODULE_DESCRIPTION(SPM_DESCRIP);
MODULE_SUPPORTED_DEVICE(SPM_DEVICES);
#ifdef MODULE_LICENSE
MODULE_LICENSE(SPM_LICENSE);
#endif

#ifndef INT
#define INT int
#endif

typedef void (*bufcall_fnc_t) (long);

/*
 *  =======================================================================
 *
 *  STREAMS Definitions
 *
 *  =======================================================================
 */

#define SPM_MOD_ID	0
#define SPM_MOD_NAME	"spm"

STATIC struct module_info spm_winfo = {
	SPM_MOD_ID,			/* Module ID number */
	SPM_MOD_NAME "-wr",		/* Module name */
	1,				/* Min packet size accepted */
	280,				/* Max packet size accepted */
	1,				/* Hi water mark */
	0				/* Lo water mark */
};

STATIC struct module_info spm_rinfo = {
	SPM_MOD_ID,			/* Module ID number */
	SPM_MOD_NAME "-rd",		/* Module name */
	1,				/* Min packet size accepted */
	128,				/* Max packet size accepted */
	1,				/* Hi water mark */
	0				/* Lo water mark */
};

STATIC int spm_open(queue_t *, dev_t *, int, int, cred_t *);
STATIC int spm_close(queue_t *, int, cred_t *);

STATIC INT spm_wput(queue_t *, mblk_t *);
STATIC INT spm_wsrv(queue_t *);

STATIC struct qinit spm_winit = {
	spm_wput,			/* Write put (message from above) */
	spm_wsrv,			/* Write queue service */
	NULL,				/* Each open */
	NULL,				/* Last close */
	NULL,				/* Admin (not used) */
	&spm_winfo,			/* Information */
	NULL				/* Statistics */
};

STATIC INT spm_rput(queue_t *, mblk_t *);
STATIC INT spm_rsrv(queue_t *);

STATIC struct qinit spm_rinit = {
	spm_rput,			/* Read put (message from below) */
	spm_rsrv,			/* Read queue service */
	spm_open,			/* Each open */
	spm_close,			/* Last close */
	NULL,				/* Admin (not used) */
	&spm_rinfo,			/* Information */
	NULL				/* Statistics */
};

STATIC struct streamtab spm_info = {
	&spm_rinit,			/* Upper read queue */
	&spm_winit,			/* Upper write queue */
	NULL,				/* Lower read queue */
	NULL				/* Lower write queue */
};

/*
 *  ========================================================================
 *
 *  Private structure
 *
 *  ========================================================================
 */

typedef struct spm {
	struct spm *next;		/* list linkage */
	struct spm **prev;		/* list linkage */
	ushort cmajor;			/* major device number */
	ushort cminor;			/* minor device number */
	queue_t *rq;			/* rd queue */
	queue_t *wq;			/* wr queue */
	uint rbid;			/* rd bufcall id */
	uint wbid;			/* wr bufcall id */
	lis_spin_lock_t lock;		/* queue lock */
	uint nest;			/* nest of this queue lock */
	void *user;			/* user of this queue lock */
	uint state;			/* interface state */
	uint version;			/* interface version */
	uint flags;			/* interface flags */
	size_t refcnt;			/* reference count */
	lmi_option_t option;		/* LMI protocol and variant options */
	sdl_statem_t statem;		/* SDL state machine variables */
	sdl_config_t config;		/* SDL configuration options */
	sdl_notify_t notify;		/* SDL notification options */
	sdl_stats_t stats;		/* SDL statistics */
	sdl_stats_t stamp;		/* SDL statistics timestamps */
	sdl_stats_t statsp;		/* SDL statistics periods */
	unsigned long wts;		/* WR throttle timestamp */
	uint wno;			/* WR throttle count */
	uint wtim;			/* WR throttle timer */
	unsigned long rts;		/* RD throttle timestamp */
	uint rno;			/* RD throttle count */
	uint rtim;			/* WR throttle timer */
} spm_t;
#define PRIV(__q) ((spm_t *)(__q)->q_ptr)

/*
 *  ========================================================================
 *
 *  PRIVATE struct allocation and deallocation
 *
 *  ========================================================================
 */
STATIC kmem_cache_t *spm_priv_cachep = NULL;
/*
 *  Cache allocation
 *  ------------------------------------------------------------------------
 */
STATIC void spm_init_caches(void)
{
	if (!spm_priv_cachep &&
	    !(spm_priv_cachep = kmem_cache_create
	      ("spm_priv_cachep", sizeof(spm_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
		panic("%s: Cannot allocate spm_priv_cachep\n", __FUNCTION__);
	printd(("spm: Allocated/selected private structure cache\n"));
	return;
}
STATIC void spm_free_caches(void)
{
	if (spm_priv_cachep) {
		if (kmem_cache_destroy(spm_priv_cachep))
			cmn_err(CE_WARN, "%s: did not destroy spm_priv_cachep.", __FUNCTION__);
		else
			printd(("spm: destroyed spm_priv_cachep\n"));
	}
	return;
}

/*
 *  Private structure allocation
 *  ------------------------------------------------------------------------
 */
STATIC spm_t *spm_alloc_priv(queue_t * q, spm_t ** sp, ushort cmajor, ushort cminor)
{
	spm_t *s;
	if ((s = kmem_cache_alloc(spm_priv_cachep, SLAB_ATOMIC))) {
		printd(("spm: allocated module private structure\n"));
		bzero(s, sizeof(*s));
		if ((s->next = *sp))
			s->next->prev = &s->next;
		s->prev = sp;
		*sp = s;
		printd(("spm: linked module private structure\n"));
		s->rq = RD(q);
		s->wq = WR(q);
		s->rq->q_ptr = s->wq->q_ptr = s;
		s->cmajor = cmajor;
		s->cminor = cminor;
		lis_spin_lock_init(&s->lock, "spm-queue-lock");
		s->state = LMI_DISABLED;	/* Style 1 */
		s->version = 1;
		s->wts = jiffies;
		s->wno = 0;
		s->rts = jiffies;
		s->rno = 0;
		/* 
		 *  Set some defaults:
		 */
		printd(("spm: setting module defaults\n"));
		/* LMI configuration defaults */
		s->option.pvar = SS7_PVAR_ITUT_88;
		s->option.popt = 0;
#if 0
		/* SDT configuration defaults */
		s->config.Tin = 4;	/* AERM normal proving threshold */
		s->config.Tie = 1;	/* AERM emergency proving threshold */
		s->config.T = 64;	/* SUERM error threshold */
		s->config.D = 256;	/* SUERM error rate parameter */
		s->config.t8 = 100 * HZ / 1000;	/* T8 timeout */
		s->config.Te = 577169;	/* EIM error threshold */
		s->config.De = 9308000;	/* EIM correct decrement */
		s->config.Ue = 144292000;	/* EIM error increment */
#endif
	}
	return (s);
}
STATIC void spm_free_priv(queue_t * q)
{
	uint t;
	spm_t *s = PRIV(q);
	ensure(s, return);
	if (s->rbid)
		unbufcall(xchg(&s->rbid, 0));
	if (s->wbid)
		unbufcall(xchg(&s->wbid, 0));
	if ((*(s->prev) = s->next))
		s->next->prev = s->prev;
	s->next = NULL;
	s->prev = NULL;
	if ((t = xchg(&s->wtim, 0)))
		untimeout(t);
	if ((t = xchg(&s->rtim, 0)))
		untimeout(t);
	noenable(s->wq);
	noenable(s->rq);
	assure(s->refcnt == 0);
	printd(("spm: unlinked module private structure\n"));
	kmem_cache_free(spm_priv_cachep, s);
	printd(("spm: freed module private structure\n"));
	return;
}

/*
 *  ========================================================================
 *
 *  PRIMITIVES sent upstream or downstream
 *
 *  ========================================================================
 */
/*
 *  M_ERROR
 *  -----------------------------------
 */
STATIC int m_error(queue_t * q, int err)
{
	mblk_t *mp;
	if ((mp = ss7_allocb(q, 2, BPRI_MED))) {
		mp->b_datap->db_type = M_ERROR;
		*(mp->b_wptr)++ = err < 0 ? -err : err;
		*(mp->b_wptr)++ = err < 0 ? -err : err;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  SDL_RECEIVED_BITS_IND
 *  -----------------------------------
 */
STATIC INLINE int sdl_received_bits_ind(queue_t * q, mblk_t * mp)
{
	union SDL_primitives *p = (union SDL_primitives *) mp->b_rptr;
	p->sdl_primitive = SDL_RECEIVED_BITS_IND;
	putnext(q, mp);
	return (QR_ABSORBED);
}

/*
 *  SDL_DISCONNECT_IND
 *  -----------------------------------
 */
STATIC INLINE int sdl_disconnect_ind(queue_t * q, mblk_t * mp)
{
	union SDL_primitives *p = (union SDL_primitives *) mp->b_rptr;
	p->sdl_primitive = SDL_DISCONNECT_IND;
	putnext(q, mp);
	return (QR_ABSORBED);
}

/*
 *  LMI_INFO_ACK
 *  -----------------------------------
 */
STATIC INLINE int lmi_info_ack(queue_t * q, long state, caddr_t ppa_ptr, size_t ppa_len)
{
	mblk_t *mp;
	lmi_info_ack_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p) + ppa_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_INFO_ACK;
		p->lmi_version = 1;
		p->lmi_state = state;
		p->lmi_max_sdu = 8;
		p->lmi_min_sdu = 8;
		p->lmi_header_len = 0;
		p->lmi_ppa_style = LMI_STYLE1;
		bcopy(ppa_ptr, mp->b_wptr, ppa_len);
		mp->b_wptr += ppa_len;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_OK_ACK
 *  -----------------------------------
 */
STATIC INLINE int lmi_ok_ack(queue_t * q, long state, long prim)
{
	mblk_t *mp;
	lmi_ok_ack_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_OK_ACK;
		p->lmi_correct_primitive = prim;
		p->lmi_state = state;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_ERROR_ACK
 *  -----------------------------------
 */
STATIC INLINE int lmi_error_ack(queue_t * q, long state, long prim, long err, long reason)
{
	mblk_t *mp;
	lmi_error_ack_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_ERROR_ACK;
		p->lmi_errno = err;
		p->lmi_reason = reason;
		p->lmi_state = state;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_ENABLE_CON
 *  -----------------------------------
 */
STATIC INLINE int lmi_enable_con(queue_t * q, long state)
{
	mblk_t *mp;
	lmi_enable_con_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_ENABLE_CON;
		p->lmi_state = state;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_DISABLE_CON
 *  -----------------------------------
 */
STATIC INLINE int lmi_disable_con(queue_t * q, long state)
{
	mblk_t *mp;
	lmi_disable_con_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_DISABLE_CON;
		p->lmi_state = state;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_OPTMGMT_ACK
 *  -----------------------------------
 */
#if 0
STATIC INLINE int lmi_optmgmt_ack(queue_t * q, ulong flags, caddr_t opt_ptr, size_t opt_len)
{
	mblk_t *mp;
	lmi_optmgmt_ack_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p) + opt_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_OPTMGMT_ACK;
		p->lmi_opt_length = opt_len;
		p->lmi_opt_offset = opt_len ? sizeof(*p) : 0;
		p->lmi_flags = flags;
		bcopy(opt_ptr, mp->b_wptr, opt_len);
		mp->b_wptr += opt_len;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}
#endif

/*
 *  LMI_ERROR_IND
 *  -----------------------------------
 */
STATIC INLINE int lmi_error_ind(queue_t * q, long state, long error, long reason)
{
	mblk_t *mp;
	lmi_error_ind_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_ERROR_IND;
		p->lmi_errno = error;
		p->lmi_reason = reason;
		p->lmi_state = state;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_STATS_IND
 *  -----------------------------------
 */
STATIC INLINE int lmi_stats_ind(queue_t * q)
{
	mblk_t *mp;
	lmi_stats_ind_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_STATS_IND;
		p->lmi_interval = 0;
		p->lmi_timestamp = jiffies;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_EVENT_IND
 *  -----------------------------------
 */
STATIC INLINE int lmi_event_ind(queue_t * q, ulong oid, ulong level, caddr_t inf_ptr,
				size_t inf_len)
{
	mblk_t *mp;
	lmi_event_ind_t *p;
	if ((mp = ss7_allocb(q, sizeof(*p) + inf_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->lmi_primitive = LMI_EVENT_IND;
		p->lmi_objectid = oid;
		p->lmi_timestamp = jiffies;
		p->lmi_severity = level;
		bcopy(inf_ptr, mp->b_wptr, inf_len);
		mp->b_wptr += inf_len;
		qreply(q, mp);
		return (QR_DONE);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  ========================================================================
 *
 *  EVENTS from above or below
 *
 *  ========================================================================
 *
 *  MESSAGES from above or below
 *
 *  -------------------------------------------------------------------------
 */
/*
 *  SDL_BITS_FOR_TRANSMISSION_REQ
 *  -----------------------------------
 */
STATIC INLINE int sdl_bits_for_transmission_req(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	/* strip to M_DATA */
	return (QR_STRIP);
}

/*
 *  SDL_CONNECT_REQ
 *  -----------------------------------
 */
STATIC INLINE int sdl_connect_req(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	/* ignore */
	return (QR_DONE);
}

/*
 *  SDL_DISCONNECT_REQ
 *  -----------------------------------
 */
STATIC INLINE int sdl_disconnect_req(queue_t * q, mblk_t * mp)
{
	/* translated to indication */
	return sdl_disconnect_ind(q, mp);
}

/*
 *  LMI_INFO_REQ
 *  -----------------------------------
 */
STATIC INLINE int lmi_info_req(queue_t * q, mblk_t * mp)
{
	(void) mp;
	return lmi_info_ack(q, 0, NULL, 0);
}

/*
 *  LMI_ATTACH_REQ
 *  -----------------------------------
 */
STATIC INLINE int lmi_attach_req(queue_t * q, mblk_t * mp)
{
	(void) mp;
	return lmi_ok_ack(q, LMI_DISABLED, LMI_ATTACH_REQ);
}

/*
 *  LMI_DETACH_REQ
 *  -----------------------------------
 */
STATIC INLINE int lmi_detach_req(queue_t * q, mblk_t * mp)
{
	(void) mp;
	return lmi_ok_ack(q, LMI_UNATTACHED, LMI_DETACH_REQ);
}

/*
 *  LMI_ENABLE_REQ
 *  -----------------------------------
 */
STATIC INLINE int lmi_enable_req(queue_t * q, mblk_t * mp)
{
	(void) mp;
	return lmi_enable_con(q, LMI_ENABLED);
}

/*
 *  LMI_DISABLE_REQ
 *  -----------------------------------
 */
STATIC INLINE int lmi_disable_req(queue_t * q, mblk_t * mp)
{
	(void) mp;
	return lmi_disable_con(q, LMI_DISABLED);
}

/*
 *  LMI_OPTMGMT_REQ
 *  -----------------------------------
 */
STATIC INLINE int lmi_optmgmt_req(queue_t * q, mblk_t * mp)
{
	(void) mp;
	return lmi_error_ack(q, 0, LMI_OPTMGMT_REQ, EOPNOTSUPP, 0);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  IO CONTROLS from above or below
 *
 *  -------------------------------------------------------------------------
 */
/*
 *  SDL_IOCGOPTIONS
 *  -----------------------------------
 */
STATIC int sdl_iocgoptions(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	*(lmi_option_t *) arg = s->option;
	return (0);
}

/*
 *  SDL_IOCSOPTIONS
 *  -----------------------------------
 */
STATIC int sdl_iocsoptions(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	s->option = *(lmi_option_t *) arg;
	return (0);
}

/*
 *  SDL_IOCGCONFIG
 *  -----------------------------------
 */
STATIC int sdl_iocgconfig(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	*(sdl_config_t *) arg = s->config;
	return (0);
}

/*
 *  SDL_IOCSCONFIG
 *  -----------------------------------
 */
STATIC int sdl_iocsconfig(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	s->config = *(sdl_config_t *) arg;
	return (0);
}

/*
 *  SDL_IOCTCONFIG
 *  -----------------------------------
 */
STATIC int sdl_ioctconfig(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	(void) s;
	(void) arg;
	fixme(("Test the configuration\n"));
	return (-EOPNOTSUPP);
}

/*
 *  SDL_IOCCCONFIG
 *  -----------------------------------
 */
STATIC int sdl_ioccconfig(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	(void) s;
	(void) arg;
	fixme(("Commit the configuration\n"));
	return (-EOPNOTSUPP);
}

/*
 *  SDL_IOCGSTATEM
 *  -----------------------------------
 */
STATIC int sdl_iocgstatem(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	*(sdl_statem_t *) arg = s->statem;
	return (0);
}

/*
 *  SDL_IOCCMRESET
 *  -----------------------------------
 */
STATIC int sdl_ioccmreset(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	(void) s;
	(void) arg;
	fixme(("Master reset\n"));
	return (-EOPNOTSUPP);
}

/*
 *  SDL_IOCGSTATSP
 *  -----------------------------------
 */
STATIC int sdl_iocgstatsp(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	*(sdl_stats_t *) arg = s->statsp;
	return (0);
}

/*
 *  SDL_IOCSSTATSP
 *  -----------------------------------
 */
STATIC int sdl_iocsstatsp(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	s->statsp = *(sdl_stats_t *) arg;
	return (0);
}

/*
 *  SDL_IOCGSTATS
 *  -----------------------------------
 */
STATIC int sdl_iocgstats(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	*(sdl_stats_t *) arg = s->stats;
	return (0);
}

/*
 *  SDL_IOCCSTATS
 *  -----------------------------------
 */
STATIC int sdl_ioccstats(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	(void) arg;
	bzero(&s->stats, sizeof(s->stats));
	return (0);
}

/*
 *  SDL_IOCGNOTIFY
 *  -----------------------------------
 */
STATIC int sdl_iocgnotify(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	*(sdl_notify_t *) arg = s->notify;
	return (0);
}

/*
 *  SDL_IOCSNOTIFY
 *  -----------------------------------
 */
STATIC int sdl_iocsnotify(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	s->notify = *(sdl_notify_t *) arg;
	return (0);
}

/*
 *  SDL_IOCCNOTIFY
 *  -----------------------------------
 */
STATIC int sdl_ioccnotify(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	s->notify.events &= ~((sdl_notify_t *) arg)->events;
	return (0);
}

/*
 *  ========================================================================
 *
 *  STREAMS Message Handling
 *
 *  ========================================================================
 *
 *  M_IOCTL Handling
 *  -----------------------------------------------------------------------
 */
STATIC int spm_m_ioctl(queue_t * q, mblk_t * mp)
{
	int ret;
	struct iocblk *iocp = (struct iocblk *) mp->b_rptr;
	int cmd = iocp->ioc_cmd, count = iocp->ioc_count;
	int type = _IOC_TYPE(cmd), nr = _IOC_NR(cmd), size = _IOC_SIZE(cmd);
	(void) nr;
	switch (type) {
	case __SID:
	{
		switch (cmd) {
		default:
			ptrace(("spm: ERROR: Unknown IOCTL %d\n", cmd));
			ret = -EINVAL;
			break;
		case I_STR:
		case I_LINK:
		case I_PLINK:
		case I_UNLINK:
		case I_PUNLINK:
		{
			void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
			struct linkblk *lp = (struct linkblk *) arg;
			rare();
			(void) lp;
			ret = -EINVAL;
			break;
		}
		}
		ret = -EFAULT;
		break;
	}
	case SDL_IOC_MAGIC:
	{
		if (count < size || PRIV(q)->state == LMI_UNATTACHED) {
			ret = -EINVAL;
			break;
		}
		switch (cmd) {
		case SDL_IOCGOPTIONS:	/* lmi_option_t */
			ret = sdl_iocgoptions(q, mp);
			break;
		case SDL_IOCSOPTIONS:	/* lmi_option_t */
			ret = sdl_iocsoptions(q, mp);
			break;
		case SDL_IOCGCONFIG:	/* sdt_config_t */
			ret = sdl_iocgconfig(q, mp);
			break;
		case SDL_IOCSCONFIG:	/* sdt_config_t */
			ret = sdl_iocsconfig(q, mp);
			break;
		case SDL_IOCTCONFIG:	/* sdt_config_t */
			ret = sdl_ioctconfig(q, mp);
			break;
		case SDL_IOCCCONFIG:	/* sdt_config_t */
			ret = sdl_ioccconfig(q, mp);
			break;
		case SDL_IOCGSTATEM:	/* sdt_statem_t */
			ret = sdl_iocgstatem(q, mp);
			break;
		case SDL_IOCCMRESET:	/* sdt_statem_t */
			ret = sdl_ioccmreset(q, mp);
			break;
		case SDL_IOCGSTATSP:	/* lmi_sta_t */
			ret = sdl_iocgstatsp(q, mp);
			break;
		case SDL_IOCSSTATSP:	/* lmi_sta_t */
			ret = sdl_iocsstatsp(q, mp);
			break;
		case SDL_IOCGSTATS:	/* sdt_stats_t */
			ret = sdl_iocgstats(q, mp);
			break;
		case SDL_IOCCSTATS:	/* sdt_stats_t */
			ret = sdl_ioccstats(q, mp);
			break;
		case SDL_IOCGNOTIFY:	/* sdt_notify_t */
			ret = sdl_iocgnotify(q, mp);
			break;
		case SDL_IOCSNOTIFY:	/* sdt_notify_t */
			ret = sdl_iocsnotify(q, mp);
			break;
		case SDL_IOCCNOTIFY:	/* sdt_notify_t */
			ret = sdl_ioccnotify(q, mp);
			break;
		default:
			ret = -EOPNOTSUPP;
			break;
		}
		ret = -EFAULT;
		break;
	}
	default:
		return (QR_PASSALONG);
	}
	if (ret >= 0) {
		mp->b_datap->db_type = M_IOCACK;
		iocp->ioc_error = 0;
		iocp->ioc_rval = 0;
	} else {
		mp->b_datap->db_type = M_IOCNAK;
		iocp->ioc_error = -ret;
		iocp->ioc_rval = -1;
	}
	qreply(q, mp);
	return (QR_ABSORBED);
}

/*
 *  M_PROTO, M_PCPROTO Handling
 *  -----------------------------------------------------------------------
 */
STATIC int spm_m_proto(queue_t * q, mblk_t * mp)
{
	int rtn;
	ulong prim;
	spm_t *s = PRIV(q);
	ulong oldstate = s->state;
	if ((prim = *(ulong *) mp->b_rptr) == SDL_BITS_FOR_TRANSMISSION_REQ)
		rtn = sdl_bits_for_transmission_req(q, mp);
	else
		switch (prim) {
		case SDL_BITS_FOR_TRANSMISSION_REQ:
			rtn = sdl_bits_for_transmission_req(q, mp);
			break;
		case SDL_CONNECT_REQ:
			rtn = sdl_connect_req(q, mp);
			break;
		case SDL_DISCONNECT_REQ:
			rtn = sdl_disconnect_req(q, mp);
			break;
		case LMI_INFO_REQ:
			rtn = lmi_info_req(q, mp);
			break;
		case LMI_ATTACH_REQ:
			rtn = lmi_attach_req(q, mp);
			break;
		case LMI_DETACH_REQ:
			rtn = lmi_detach_req(q, mp);
			break;
		case LMI_ENABLE_REQ:
			rtn = lmi_enable_req(q, mp);
			break;
		case LMI_DISABLE_REQ:
			rtn = lmi_disable_req(q, mp);
			break;
		case LMI_OPTMGMT_REQ:
			rtn = lmi_optmgmt_req(q, mp);
			break;
		default:
			/* pass along anything we don't recognize */
			rtn = QR_PASSFLOW;
			break;
		}
	if (rtn < 0)
		s->state = oldstate;
	return (rtn);
}

/*
 *  M_DATA Handling
 *  -------------------------------------------------------------------------
 *  We need to throttle these to avoid locking up the processor.  The throttle
 *  is for 10 blocks every 10ms maximum which is precisely 64kbps.
 */
STATIC void spm_w_timeout(caddr_t data)
{
	queue_t *q = (queue_t *) data;
	spm_t *s = PRIV(q);
	if (!xchg(&s->wtim, 0))
		return;
	enableok(q);
	qenable(q);
	return;
}
STATIC void spm_r_timeout(caddr_t data)
{
	queue_t *q = (queue_t *) data;
	spm_t *s = PRIV(q);
	if (!xchg(&s->rtim, 0))
		return;
	enableok(q);
	qenable(q);
	return;
}
STATIC INLINE int spm_w_data(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	if (s->wts == jiffies) {
		if (s->wno++ >= 10) {
			/* come back in a tick */
			s->wtim = timeout(&spm_w_timeout, (caddr_t) q, 1);
			// printd(("spm: tx: blocking\n"));
			return (QR_DISABLE);
		}
	} else {
		s->wno = 1;
		s->wts = jiffies;
	}
	return (QR_PASSFLOW);
}
STATIC INLINE int spm_r_data(queue_t * q, mblk_t * mp)
{
	spm_t *s = PRIV(q);
	if (s->rts == jiffies) {
		if (s->rno++ >= 10) {
			/* come back in a tick */
			s->rtim = timeout(&spm_r_timeout, (caddr_t) q, 1);
			// printd(("spm: rx: blocking\n"));
			return (QR_DISABLE);
		}
	} else {
		s->rno = 1;
		s->rts = jiffies;
	}
	return (QR_PASSFLOW);
}

/*
 *  M_RSE, M_PCRSE Handling
 *  -------------------------------------------------------------------------
 */
STATIC int spm_m_pcrse(queue_t * q, mblk_t * mp)
{
	int rtn;
	switch (*(ulong *) mp->b_rptr) {
	default:
		rtn = -EFAULT;
		break;
	}
	return (rtn);
}

/*
 *  M_FLUSH Handling
 *  -------------------------------------------------------------------------
 */
STATIC INLINE int spm_m_flush(queue_t * q, mblk_t * mp, const uint8_t mflag)
{
	if (*mp->b_rptr & mflag) {
		if (*mp->b_rptr & FLUSHBAND)
			flushband(q, mp->b_rptr[1], FLUSHALL);
		else
			flushq(q, FLUSHALL);
	}
	return (QR_LOOP);
}
STATIC int spm_w_flush(queue_t * q, mblk_t * mp)
{
	return spm_m_flush(q, mp, FLUSHW);
}
STATIC int spm_r_flush(queue_t * q, mblk_t * mp)
{
	return spm_m_flush(q, mp, FLUSHR);
}

/*
 *  =========================================================================
 *
 *  PUT and SRV
 *
 *  =========================================================================
 */
STATIC INLINE int spm_r_prim(queue_t * q, mblk_t * mp)
{
	/* Fast Path */
	if (mp->b_datap->db_type == M_DATA)
		return spm_r_data(q, mp);
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return spm_r_data(q, mp);
	case M_PROTO:
	case M_PCPROTO:
		return spm_m_proto(q, mp);
	case M_RSE:
	case M_PCRSE:
		return spm_m_pcrse(q, mp);
	case M_FLUSH:
		return spm_r_flush(q, mp);
	case M_IOCTL:
		return spm_m_ioctl(q, mp);
	}
	return (QR_PASSFLOW);
}
STATIC INLINE int spm_w_prim(queue_t * q, mblk_t * mp)
{
	/* Fast Path */
	if (mp->b_datap->db_type == M_DATA)
		return spm_w_data(q, mp);
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return spm_w_data(q, mp);
	case M_PROTO:
	case M_PCPROTO:
		return spm_m_proto(q, mp);
	case M_RSE:
	case M_PCRSE:
		return spm_m_pcrse(q, mp);
	case M_FLUSH:
		return spm_w_flush(q, mp);
	case M_IOCTL:
		return spm_m_ioctl(q, mp);
	}
	return (QR_PASSFLOW);
}
STATIC void spm_rx_wakeup(queue_t * q)
{
}
STATIC INT spm_rput(queue_t * q, mblk_t * mp)
{
	return (INT) ss7_putq(q, mp, &spm_r_prim);
}
STATIC INT spm_rsrv(queue_t * q)
{
	return (INT) ss7_srvq(q, &spm_r_prim, &spm_rx_wakeup);
}
STATIC void spm_tx_wakeup(queue_t * q)
{
}
STATIC INT spm_wput(queue_t * q, mblk_t * mp)
{
	return (INT) ss7_putq(q, mp, &spm_w_prim);
}
STATIC INT spm_wsrv(queue_t * q)
{
	return (INT) ss7_srvq(q, &spm_w_prim, &spm_tx_wakeup);
}

/*
 *  =======================================================================
 *
 *  OPEN and CLOSE
 *
 *  =======================================================================
 */
STATIC spm_t *spm_list = NULL;
STATIC int spm_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp)
{
	int cmajor = getmajor(*devp);
	int cminor = getminor(*devp);
	spm_t *s, **sp = &spm_list;
	(void) crp;
	MOD_INC_USE_COUNT;	/* keep module from unloading in our face */
	if (q->q_ptr != NULL) {
		MOD_DEC_USE_COUNT;
		return (0);	/* already open */
	}
	if (sflag == DRVOPEN || WR(q)->q_next == NULL) {
		ptrace(("spm: ERROR: Can't open as driver\n"));
		MOD_DEC_USE_COUNT;
		return (EIO);
	}
	for (; *sp && (*sp)->cmajor < cmajor; sp = &(*sp)->next);
	for (; *sp && (*sp)->cmajor == cmajor && (*sp)->cminor < cminor; sp = &(*sp)->next);
	if (*sp && (*sp)->cmajor == cmajor && (*sp)->cminor == cminor) {
		ptrace(("spm: ERROR: Multiple push\n"));
		MOD_DEC_USE_COUNT;
		return (ENXIO);
	}
	printd(("spm: Pushed module for char device %d:%d\n", cmajor, cminor));
	if (!(s = spm_alloc_priv(q, sp, cmajor, cminor))) {
		ptrace(("spm: ERROR: No cache memory\n"));
		MOD_DEC_USE_COUNT;
		return (ENOMEM);
	}
	return (0);
}
STATIC int spm_close(queue_t * q, int flag, cred_t * crp)
{
	spm_t *s = PRIV(q);
	(void) flag;
	(void) crp;
	(void) s;
	printd(("spm: Popped module for char device %d:%d\n", s->cmajor, s->cminor));
	spm_free_priv(q);
	MOD_DEC_USE_COUNT;
	return (0);
}

/*
 *  =======================================================================
 *
 *  LiS Module Initialization (For unregistered driver.)
 *
 *  =======================================================================
 */
STATIC int spm_initialized = 0;
STATIC void spm_init(void)
{
	unless(spm_initialized > 0, return);
	cmn_err(CE_NOTE, SPM_BANNER);	/* console splash */
	spm_init_caches();
	if ((spm_initialized = lis_register_strmod(&spm_info, SPM_MOD_NAME)) < 0) {
		cmn_err(CE_WARN, "spm: couldn't register module\n");
		spm_free_caches();
		return;
	}
	spm_initialized = 1;
	return;
}
STATIC void spm_terminate(void)
{
	ensure(spm_initialized > 0, return);
	if ((spm_initialized = lis_unregister_strmod(&spm_info)) < 0) {
		cmn_err(CE_WARN, "spm: couldn't unregister module\n");
		return;
	}
	spm_free_caches();
	spm_initialized = 0;
	return;
}

/*
 *  =======================================================================
 *
 *  Kernel Module Initialization
 *
 *  =======================================================================
 */
int init_module(void)
{
	spm_init();
	if (spm_initialized < 0)
		return spm_initialized;
	return (0);
}
void cleanup_module(void)
{
	spm_terminate();
}


Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sdli/spm.c

OpenSS7
SS7 for the
Common Man
Home Overview Status News Documentation Resources About

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified: