OpenSS7
SS7 for the
Common Man
© Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved.
Last modified: Sat, 16 Aug 2008 01:54:33 GMT
Home TopIndex FirstPrev Next LastMore Download Info FAQ Mail  Home -> Resources -> Browse Source -> /code/strxnet/src/modules/timod.c
Quick Links

Download

SCTP

SIGTRAN

SS7

Hardware

STREAMS

Asterisk

Related

Package

Manual

FAQ

Browse Source

Applications

SS7 Stack

ISDN Stack

SIGTRAN Stack

VoIP Stack

MG Stack

SS7/ISDN Devices

IP Transport

Embedded Systems

Operating System

Resources

Packages

Sys Req

Download

Mailing Lists

Browse Source

CVS Archive

Bug Reports

Library

Hardware

Vendor Links

Home

Overview

Status

Documentation

Resources

About

News

Description: Code

File /code/strxnet/src/modules/timod.c



#ident "@(#) timod.c,v openss7-0_9_2_F(0.9.2.31) 2007/04/12 20:07:06"

static char const ident[] =
    "timod.c,v openss7-0_9_2_F(0.9.2.31) 2007/04/12 20:07:06";

#include <sys/os7/compat.h>

#if defined HAVE_TIHDR_H
#   include <tihdr.h>
#else
#   include <sys/tihdr.h>
#endif
#if defined HAVE_TIMOD_H
#   include <timod.h>
#else
#   include <sys/timod.h>
#endif

#define TIMOD_DESCRIP	"UNIX SYSTEM V RELEASE 4.2 FAST STREAMS FOR LINUX"
#define TIMOD_COPYRIGHT	"Copyright (c) 1997-2006 OpenSS7 Corporation.  All Rights Reserved."
#define TIMOD_REVISION	"OpenSS7 timod.c,v openss7-0_9_2_F(0.9.2.31) 2007/04/12 20:07:06"
#define TIMOD_DEVICE	"SVR 4.2 STREAMS XTI Library Module for TLI Devices (TIMOD)"
#define TIMOD_CONTACT	"Brian Bidulock <bidulock@openss7.org>"
#define TIMOD_LICENSE	"GPL"
#define TIMOD_BANNER	TIMOD_DESCRIP	"\n" \
			TIMOD_COPYRIGHT	"\n" \
			TIMOD_REVISION	"\n" \
			TIMOD_DEVICE	"\n" \
			TIMOD_CONTACT
#define TIMOD_SPLASH	TIMOD_DEVICE	" - " \
			TIMOD_REVISION

#ifdef LINUX
MODULE_AUTHOR(TIMOD_CONTACT);
MODULE_DESCRIPTION(TIMOD_DESCRIP);
MODULE_SUPPORTED_DEVICE(TIMOD_DEVICE);
#ifdef MODULE_LICENSE
MODULE_LICENSE(TIMOD_LICENSE);
#endif
#if defined MODULE_ALIAS
MODULE_ALIAS("streams-timod");
#endif
#endif

#ifndef CONFIG_STREAMS_TIMOD_NAME
#error "CONFIG_STREAMS_TIMOD_NAME must be defined."
#endif
#ifndef CONFIG_STREAMS_TIMOD_MODID
#error "CONFIG_STREAMS_TIMOD_MODID must be defined."
#endif

modID_t modid = CONFIG_STREAMS_TIMOD_MODID;

#ifndef module_param
MODULE_PARM(modid, "h");
#else
module_param(modid, ushort, 0444);
#endif
MODULE_PARM_DESC(modid, "Module ID for TIMOD. (0 for allocation.)");

#define MOD_NAME	CONFIG_STREAMS_TIMOD_NAME

static struct module_info timod_minfo = {
	.mi_idnum = CONFIG_STREAMS_TIMOD_MODID,
	.mi_idname = CONFIG_STREAMS_TIMOD_NAME,
	.mi_minpsz = 0,
	.mi_maxpsz = INFPSZ,
	.mi_hiwat = 0,
	.mi_lowat = 0,
};

static struct module_stat timod_rstat __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
static struct module_stat timod_wstat __attribute__ ((__aligned__(SMP_CACHE_BYTES)));

static streamscall int timod_open(queue_t *, dev_t *, int, int, cred_t *);
static streamscall int timod_close(queue_t *, int, cred_t *);

static streamscall int timod_rput(queue_t *, mblk_t *);
static streamscall int timod_wput(queue_t *, mblk_t *);

static struct qinit timod_rinit = {
	.qi_putp = timod_rput,
	.qi_qopen = timod_open,
	.qi_qclose = timod_close,
	.qi_minfo = &timod_minfo,
	.qi_mstat = &timod_rstat,
};

static struct qinit timod_winit = {
	.qi_putp = timod_wput,
	.qi_minfo = &timod_minfo,
	.qi_mstat = &timod_wstat,
};

MODULE_STATIC struct streamtab timodinfo = {
	.st_rdinit = &timod_rinit,
	.st_wrinit = &timod_winit,
};

struct timod {
	queue_t *rq;
	queue_t *wq;
	queue_t *hq;
	ulong state;
	ulong oldstate;
	ulong flags;
	mblk_t *iocblk;
	ulong qlen;
	ulong cons;
};

#define TIMOD_PRIV(__q) ((struct timod *)((__q)->q_ptr))

static kmem_cachep_t timod_priv_cachep = NULL;
static __unlikely int
timod_init_caches(void)
{
	if (!timod_priv_cachep
	    && !(timod_priv_cachep =
		 kmem_cache_create(MOD_NAME, sizeof(struct timod), 0, SLAB_HWCACHE_ALIGN, NULL,
				   NULL))) {
		cmn_err(CE_WARN, "%s: %s: Cannot allocate timod_priv_cachep", MOD_NAME,
			__FUNCTION__);
		return (-ENOMEM);
	}
	return (0);
}

static __unlikely int
timod_term_caches(void)
{
	if (timod_priv_cachep) {
#ifdef HAVE_KTYPE_KMEM_CACHE_T_P
		if (kmem_cache_destroy(timod_priv_cachep)) {
			cmn_err(CE_WARN, "%s: %s: did not destroy timod_priv_cachep", MOD_NAME,
				__FUNCTION__);
			return (-EBUSY);
		}
#else
		kmem_cache_destroy(timod_priv_cachep);
#endif
	}
	return (0);
}

static struct timod *
timod_alloc_priv(queue_t *q)
{
	struct timod *priv;

	if ((priv = kmem_cache_alloc(timod_priv_cachep, GFP_ATOMIC))) {
		bzero(priv, sizeof(*priv));
		priv->rq = q;
		priv->wq = WR(q);
		priv->hq = q->q_next;
		priv->state = TS_UNBND;
		priv->oldstate = -1UL;
		priv->flags = 0;
		priv->qlen = 0;
		priv->cons = 0;

		priv->wq->q_minpsz = priv->wq->q_next->q_minpsz;
		priv->wq->q_maxpsz = priv->wq->q_next->q_maxpsz;
		q->q_ptr = WR(q)->q_ptr = priv;
	}
	return (priv);
}

static void
timod_free_priv(queue_t *q)
{
	struct timod *priv;

	if ((priv = (typeof(priv)) q->q_ptr)) {
		q->q_ptr = WR(q)->q_ptr = NULL;
		priv->rq = NULL;
		priv->wq = NULL;
		priv->hq = NULL;
		priv->state = -1UL;
		priv->oldstate = -1UL;
		priv->flags = 0;
		priv->qlen = 0;
		priv->cons = 0;
		if (priv->iocblk)
			freemsg(xchg(&priv->iocblk, NULL));
		kmem_cache_free(timod_priv_cachep, priv);
	}
	return;
}

static __hot_put int
split_buffer(mblk_t *mp, int offset)
{
	unsigned char *ptr = mp->b_rptr + offset;

	if (ptr > mp->b_wptr)
		return (-EINVAL);
	if (ptr < mp->b_wptr) {
		mblk_t *dp;

		if ((dp = copyb(mp))) {
			dp->b_datap->db_type = M_DATA;
			dp->b_rptr += offset;
			mp->b_datap->db_type = M_PROTO;
			mp->b_wptr = ptr;
			linkb(mp, dp);
			return (0);
		}
		return (-ENOSR);
	}
	mp->b_datap->db_type = M_PROTO;
	return (0);
}

static noinline streams_fastcall __unlikely int
timod_rput_slow(queue_t *q, mblk_t *mp)
{
	struct timod *priv = q->q_ptr;

#if defined LIS
	if (q->q_next == NULL || OTHERQ(q)->q_next == NULL) {
		cmn_err(CE_WARN, "%s: %s: LiS pipe bug: called with NULL q->q_next pointer",
			MOD_NAME, __FUNCTION__);
		freemsg(mp);
		return (0);
	}
#endif
	switch (mp->b_datap->db_type) {
		union T_primitives *p;
		struct iocblk *ioc;
		mblk_t *dp;

	case M_PCPROTO:
	case M_PROTO:
		p = (typeof(p)) mp->b_rptr;
		if (!(dp = xchg(&priv->iocblk, NULL)))
			goto pass_along;

		ioc = (typeof(ioc)) dp->b_rptr;
		switch (p->type) {
		case T_OK_ACK:
			switch (ioc->ioc_cmd) {
			case O_TI_UNBIND:
			case TI_UNBIND:
				priv->state = TS_UNBND;
				priv->qlen = 0;
				goto ack_it;
#ifdef TI_ACCEPT
			case TI_ACCEPT:
#endif
			case TI_SETMYNAME:
				switch (priv->state) {
				case TS_WACK_CRES:

					priv->state = (priv->cons && --priv->cons > 0)
					    ? TS_WRES_CIND : TS_IDLE;
					break;
				case TS_WACK_DREQ7:
					priv->state = (priv->cons && --priv->cons > 0)
					    ? TS_WRES_CIND : TS_IDLE;
					break;
				}
				goto ack_it;
#ifdef TI_CONNECT
			case TI_CONNECT:
#endif
			case TI_SETPEERNAME:
				switch (priv->state) {
				case TS_WACK_CREQ:
					priv->state = TS_WCON_CREQ;
					break;
				case TS_WACK_DREQ6:
				case TS_WACK_DREQ9:
				case TS_WACK_DREQ10:
				case TS_WACK_DREQ11:
					priv->state = TS_IDLE;
					break;
				}
				priv->state = TS_WCON_CREQ;
				goto ack_it;
#ifdef TI_DISCONNECT
			case TI_DISCONNECT:
				priv->state = TS_IDLE;
				goto ack_it;
#endif
			}
			break;
		case T_INFO_ACK:
			switch (ioc->ioc_cmd) {
			case O_TI_GETINFO:
			case TI_GETINFO:
				priv->state = priv->oldstate;
				goto ack_it;
			}
			break;
		case T_BIND_ACK:
			switch (ioc->ioc_cmd) {
			case O_TI_BIND:
			case TI_BIND:
				priv->state = TS_IDLE;
				priv->qlen = p->bind_ack.CONIND_number;
				goto ack_it;
			}
			break;
		case T_OPTMGMT_ACK:
			switch (ioc->ioc_cmd) {
			case O_TI_OPTMGMT:
			case TI_OPTMGMT:
				priv->state = priv->oldstate;
				goto ack_it;
			}
			break;
		case T_ADDR_ACK:
			switch (ioc->ioc_cmd) {
#ifdef TI_GETPROTADDR
			case TI_GETPROTADDR:
#endif
			case TI_GETADDRS:
			case TI_GETMYNAME:
			case TI_GETPEERNAME:
				priv->state = priv->oldstate;
				goto ack_it;
			}
			break;
#ifdef T_CAPABILITY_ACK
		case T_CAPABILITY_ACK:
			switch (ioc->ioc_cmd) {
			case TI_CAPABILITY:
				priv->state = priv->oldstate;
				goto ack_it;
			}
			break;
#endif
		case T_ERROR_ACK:
			priv->state = priv->oldstate;
			dp->b_datap->db_type = M_IOCACK;
			linkb(dp, mp);
			ioc->ioc_count = mp->b_wptr - mp->b_rptr;
			ioc->ioc_error = 0;
			ioc->ioc_rval = (p->error_ack.UNIX_error << 8) | p->error_ack.TLI_error;
			if (ioc->ioc_rval == 0 || ioc->ioc_rval == TSYSERR)
				ioc->ioc_rval = (EINVAL << 8) | TSYSERR;
			putnext(q, dp);
			return (0);
		      ack_it:
			dp->b_datap->db_type = M_IOCACK;
			linkb(dp, mp);
			ioc->ioc_count = mp->b_wptr - mp->b_rptr;
			ioc->ioc_error = 0;
			ioc->ioc_rval = 0;
			putnext(q, dp);
			return (0);
		}

	      pass_along:
		switch (p->type) {
		case T_CONN_IND:
			priv->oldstate = priv->state;
			priv->cons++;
			priv->state = TS_WRES_CIND;
			break;
		case T_CONN_CON:
			priv->oldstate = priv->state;
			priv->state = TS_DATA_XFER;
			break;
		case T_DISCON_IND:
			priv->oldstate = priv->state;
			if (priv->cons && --priv->cons) {
				priv->state = TS_WRES_CIND;
				break;
			}
			priv->state = TS_IDLE;
			break;
		case T_DATA_IND:
			priv->oldstate = priv->state;
			priv->state = TS_DATA_XFER;
			break;
		case T_EXDATA_IND:
			priv->oldstate = priv->state;
			priv->state = TS_DATA_XFER;
			break;
		case T_INFO_ACK:
			priv->state = priv->oldstate;
			break;
		case T_BIND_ACK:
			priv->oldstate = priv->state;
			priv->qlen = p->bind_ack.CONIND_number;
			priv->state = TS_IDLE;
			break;
		case T_ERROR_ACK:
			priv->state = priv->oldstate;
			break;
		case T_OK_ACK:
			switch ((priv->oldstate = priv->state)) {
			case TS_WACK_UREQ:
				priv->state = TS_UNBND;
				break;
			case TS_WACK_CREQ:
				priv->state = TS_WCON_CREQ;
				break;
			case TS_WACK_CRES:

				priv->state = TS_DATA_XFER;
				break;
			case TS_WACK_DREQ6:
			case TS_WACK_DREQ9:
			case TS_WACK_DREQ10:
			case TS_WACK_DREQ11:
				priv->state = TS_IDLE;
				break;
			case TS_WACK_DREQ7:
				if (priv->cons && --priv->cons) {
					priv->state = TS_WRES_CIND;
					break;
				}
				priv->state = TS_IDLE;
				break;
			}
			break;
		case T_UNITDATA_IND:
			priv->oldstate = priv->state;
			priv->state = TS_IDLE;
			break;
		case T_UDERROR_IND:
			priv->oldstate = priv->state;
			priv->state = TS_IDLE;
			break;
		case T_OPTMGMT_ACK:
			priv->state = priv->oldstate;
			break;
		case T_ORDREL_IND:
			switch ((priv->oldstate = priv->state)) {
			case TS_DATA_XFER:
				priv->state = TS_WIND_ORDREL;
				break;
			case TS_WIND_ORDREL:
				priv->state = TS_IDLE;
				break;
			}
			break;
		case T_ADDR_ACK:
			priv->state = priv->oldstate;
			break;
#ifdef T_CAPABILITY_ACK
		case T_CAPABILITY_ACK:
			priv->state = priv->oldstate;
			break;
#endif
		}
		break;
	case M_ERROR:
	case M_HANGUP:
		priv->oldstate = -1UL;
		priv->state = -1UL;
		break;
	}
	putnext(q, mp);
	return (0);
}
static streamscall __hot_in int
timod_rput(queue_t *q, mblk_t *mp)
{
	union T_primitives *p;

#if defined LIS
	if (q->q_next == NULL || OTHERQ(q)->q_next == NULL) {
		cmn_err(CE_WARN, "%s: %s: LiS pipe bug: called with NULL q->q_next pointer",
			MOD_NAME, __FUNCTION__);
		freemsg(mp);
		return (0);
	}
#endif

	if (unlikely(mp->b_datap->db_type != M_PROTO))
		goto go_slow;
	if (unlikely(mp->b_wptr < mp->b_rptr + sizeof(p->type)))
		goto go_slow;
	p = (typeof(p)) mp->b_rptr;

	if (unlikely(!((1 << p->type)
		       & ((1 << T_UNITDATA_IND) | (1 << T_UDERROR_IND) |
			  (1 << T_EXDATA_IND) | (1 << T_DATA_IND)))))
		goto go_slow;
	putnext(q, mp);
	return (0);

      go_slow:
	return timod_rput_slow(q, mp);
}

static noinline streams_fastcall __unlikely int
timod_wput_slow(queue_t *q, mblk_t *mp)
{
	struct timod *priv = q->q_ptr;

#if defined LIS

	if (q->q_next == NULL || OTHERQ(q)->q_next == NULL) {
		cmn_err(CE_WARN, "%s: %s: LiS pipe bug: called with NULL q->q_next pointer",
			MOD_NAME, __FUNCTION__);
		freemsg(mp);
		return (0);
	}
#endif
	switch (mp->b_datap->db_type) {
		union T_primitives *p;
		struct iocblk *ioc;
		mblk_t *dp;
		int err;

	case M_IOCTL:

		ioc = (typeof(ioc)) mp->b_rptr;
		err = -EFAULT;
		if (!(dp = unlinkb(mp)))
			goto error;
		dp->b_datap->db_type = (ioc->ioc_cmd == TI_GETINFO) ? M_PCPROTO : M_PROTO;
		p = (typeof(p)) dp->b_rptr;
		err = -EINVAL;
		if (ioc->ioc_count == TRANSPARENT)
			goto error;
		switch (ioc->ioc_cmd) {
		case O_TI_OPTMGMT:
			err = TNOTSUPPORT;
			goto error;
		case TI_OPTMGMT:
			if (p->type == T_OPTMGMT_REQ && ioc->ioc_count >= sizeof(p->optmgmt_ack)) {
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
#ifdef TS_WACK_OPTREQ
				priv->state = TS_WACK_OPTREQ;
#endif
				break;
			}
			goto error;
		case O_TI_BIND:
			err = TNOTSUPPORT;
			goto error;
		case TI_BIND:
			if (p->type == T_BIND_REQ && ioc->ioc_count >= sizeof(p->bind_ack)) {
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				priv->state = TS_WACK_BREQ;
				break;
			}
			goto error;
		case O_TI_GETINFO:
			err = TNOTSUPPORT;
			goto error;
		case TI_GETINFO:
			if (p->type == T_INFO_REQ && ioc->ioc_count >= sizeof(p->info_ack)) {
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				break;
			}
			goto error;
		case O_TI_UNBIND:
			err = TNOTSUPPORT;
			goto error;
		case TI_UNBIND:
			if (p->type == T_UNBIND_REQ && ioc->ioc_count >= sizeof(p->ok_ack)) {
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				priv->state = TS_WACK_UREQ;
				break;
			}
			goto error;
#if defined TI_ACCEPT
		case TI_ACCEPT:
#endif
		case TI_SETMYNAME:
			if (p->type == T_CONN_RES && ioc->ioc_count >= sizeof(p->conn_res)) {
				int doff = sizeof(p->conn_res);

				if (p->conn_res.OPT_length
				    && doff < p->conn_res.OPT_offset + p->conn_res.OPT_length)
					doff = p->conn_res.OPT_offset + p->conn_res.OPT_length;
				if ((err = split_buffer(dp, doff)) < 0)
					goto error;
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				priv->state = TS_WACK_CRES;
				break;
			}
			if (p->type == T_DISCON_REQ && ioc->ioc_count >= sizeof(p->discon_req)) {
				if ((err = split_buffer(dp, sizeof(p->discon_req))) < 0)
					goto error;
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				priv->state = TS_WACK_DREQ7;
				break;
			}
			goto error;
#if defined TI_CONNECT
		case TI_CONNECT:
#endif
		case TI_SETPEERNAME:
			if (p->type == T_CONN_REQ && ioc->ioc_count >= sizeof(p->conn_req)) {
				int doff = sizeof(p->conn_req);

				if (p->conn_req.OPT_length
				    && doff < p->conn_req.OPT_offset + p->conn_req.OPT_length)
					doff = p->conn_req.OPT_offset + p->conn_req.OPT_length;
				if (p->conn_req.DEST_length
				    && doff < p->conn_req.DEST_offset + p->conn_req.DEST_length)
					doff = p->conn_req.DEST_offset + p->conn_req.DEST_length;
				if ((err = split_buffer(dp, doff)) < 0)
					goto error;
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				priv->state = TS_WACK_CREQ;
				break;
			}
			if (p->type == T_DISCON_REQ && ioc->ioc_count >= sizeof(p->discon_req)) {
				if ((err = split_buffer(dp, sizeof(p->discon_req))) < 0)
					goto error;
				dp->b_datap->db_type = M_PROTO;
				switch ((priv->oldstate = priv->state)) {
				case TS_WCON_CREQ:
					priv->state = TS_WACK_DREQ6;
					break;
				case TS_DATA_XFER:
					priv->state = TS_WACK_DREQ9;
					break;
				case TS_WIND_ORDREL:
					priv->state = TS_WACK_DREQ10;
					break;
				case TS_WREQ_ORDREL:
					priv->state = TS_WACK_DREQ11;
					break;
				}
				break;
			}
			goto error;
		case TI_GETMYNAME:
			if (ioc->ioc_count >= sizeof(p->addr_ack)) {
				dp->b_datap->db_type = M_PCPROTO;
				p->type = T_ADDR_REQ;
				dp->b_wptr = dp->b_rptr + sizeof(p->addr_req);
				break;
			}
			goto error;
		case TI_GETPEERNAME:
			if (ioc->ioc_count >= sizeof(p->addr_ack)) {
				dp->b_datap->db_type = M_PCPROTO;
				p->type = T_ADDR_REQ;
				dp->b_wptr = dp->b_rptr + sizeof(p->addr_req);
				break;
			}
			goto error;
		case TI_GETADDRS:
			if (ioc->ioc_count >= sizeof(p->addr_ack)
			    && p->type == T_ADDR_REQ) {
				dp->b_datap->db_type = M_PCPROTO;
				priv->oldstate = priv->state;
				break;
			}
			goto error;
		case TI_SYNC:
			if (ioc->ioc_count >= sizeof(struct ti_sync_ack)) {
				int flags = ((struct ti_sync_req *) p)->tsr_flags;

				if (flags & TSRF_INFO_REQ) {
					dp->b_datap->db_type = M_PCPROTO;
					p->type = T_INFO_REQ;
					dp->b_wptr = dp->b_rptr + sizeof(p->info_req);
					break;
				} else {
				}
				if (flags & TSRF_IS_EXP_IN_RCVBUF) {
				}
				if (flags & TSRF_QLEN_REQ) {
				}
				break;
			}
			goto error;
#if 0
		case TI_GETPROTADDR:
			err = -EOPNOTSUPP;
			goto error;
		case TI_DISCONNECT:
			if (p->type == T_DISCON_REQ && ioc->ioc_count >= sizeof(p->discon_req)) {
				if ((err = split_buffer(dp, sizeof(p->discon_req))) < 0)
					goto error;
				dp->b_datap->db_type = M_PROTO;
				priv->oldstate = priv->state;
				switch (priv->state) {
				case TS_WCON_CREQ:
					priv->state = TS_WACK_DREQ6;
					break;
				case TS_WRES_CIND:
					priv->state = TS_WACK_DREQ7;
					break;
				case TS_DATA_XFER:
					priv->state = TS_WACK_DREQ9;
					break;
				case TS_WIND_ORDREL:
					priv->state = TS_WACK_DREQ10;
					break;
				case TS_WREQ_ORDREL:
					priv->state = TS_WACK_DREQ11;
					break;
				default:
					priv->state = -1;
					goto error;
				}
				break;
			}
			goto error;
#endif
		case TI_CAPABILITY:
#ifdef T_CAPABILITY_REQ
			if (ioc->ioc_count >= sizeof(p->capability_req)
			    && p->type == T_CAPABILITY_REQ) {
				dp->b_datap->db_type = M_PCPROTO;
				priv->oldstate = priv->state;
				break;
			}
			goto error;
#endif
		default:
			putnext(q, mp);
			return (0);
		}
		if ((mp = xchg(&priv->iocblk, mp)))
			freemsg(mp);
		putnext(q, dp);
		return (0);
	      error:
		mp->b_datap->db_type = M_IOCNAK;
		linkb(mp, dp);
		ioc->ioc_error = -err;
		ioc->ioc_rval = -1;
		qreply(q, mp);
		return (0);
	case M_PROTO:
	case M_PCPROTO:

		if (mp->b_wptr < mp->b_rptr + sizeof(p->type))
			break;
		p = (typeof(p)) mp->b_rptr;
		switch (p->type) {
		case T_CONN_REQ:
			priv->oldstate = priv->state;
			priv->state = TS_WACK_CREQ;
			break;
		case T_CONN_RES:
			priv->oldstate = priv->state;
			priv->state = TS_WACK_CRES;
			break;
		case T_DISCON_REQ:
			switch ((priv->oldstate = priv->state)) {
			case TS_WCON_CREQ:
				priv->state = TS_WACK_DREQ6;
				break;
			case TS_WRES_CIND:
				priv->state = TS_WACK_DREQ7;
				break;
			case TS_DATA_XFER:
				priv->state = TS_WACK_DREQ9;
				break;
			case TS_WIND_ORDREL:
				priv->state = TS_WACK_DREQ10;
				break;
			case TS_WREQ_ORDREL:
				priv->state = TS_WACK_DREQ11;
				break;
			}
			break;
		case T_DATA_REQ:
			priv->oldstate = priv->state;
			priv->state = TS_DATA_XFER;
			break;
		case T_EXDATA_REQ:
			priv->oldstate = priv->state;
			priv->state = TS_DATA_XFER;
			break;
		case T_INFO_REQ:
			priv->oldstate = priv->state;
			priv->state = priv->oldstate;
			break;
		case T_BIND_REQ:
			priv->oldstate = priv->state;
			priv->state = TS_WACK_BREQ;
			break;
		case T_UNBIND_REQ:
			priv->oldstate = priv->state;
			priv->state = TS_WACK_UREQ;
			break;
		case T_UNITDATA_REQ:
			priv->oldstate = priv->state;
			priv->state = TS_IDLE;
			break;
		case T_OPTMGMT_REQ:
			priv->oldstate = priv->state;
#ifdef TS_WACK_OPTREQ
			priv->state = TS_WACK_OPTREQ;
#endif
			break;
		case T_ORDREL_REQ:
			switch ((priv->oldstate = priv->state)) {
			case TS_WREQ_ORDREL:
				priv->state = TS_IDLE;
				break;
			case TS_DATA_XFER:
				priv->state = TS_WIND_ORDREL;
				break;
			}
			break;
		case T_ADDR_REQ:
			priv->oldstate = priv->state;
			priv->state = priv->oldstate;
			break;
#ifdef T_CAPABILITY_REQ
		case T_CAPABILITY_REQ:
			priv->oldstate = priv->state;
			priv->state = priv->oldstate;
			break;
#endif
		default:
			break;
		}
	}
	putnext(q, mp);
	return (0);
}

static streamscall __hot_out int
timod_wput(queue_t *q, mblk_t *mp)
{
	union T_primitives *p;

#if defined LIS

	if (q->q_next == NULL || OTHERQ(q)->q_next == NULL) {
		cmn_err(CE_WARN, "%s: %s: LiS pipe bug: called with NULL q->q_next pointer",
			MOD_NAME, __FUNCTION__);
		freemsg(mp);
		return (0);
	}
#endif

	if (unlikely(mp->b_datap->db_type != M_PROTO))
		goto go_slow;
	if (unlikely(mp->b_wptr < mp->b_rptr + sizeof(p->type)))
		goto go_slow;
	p = (typeof(p)) mp->b_rptr;

	if (unlikely(!((1 << p->type)
		       & ((1 << T_UNITDATA_REQ) | (1 << T_EXDATA_REQ) | (1 << T_DATA_REQ)))))
		goto go_slow;
	putnext(q, mp);
	return (0);

      go_slow:
	return timod_wput_slow(q, mp);
}

#define TIMOD_HANGUP	01
#define TIMOD_EPROTO	02

#if !defined BPRI_WAITOK
#   if defined BPRI_FT
#	define BPRI_WAITOK BPRI_FT
#   else
#	define BPRI_WAITOK BPRI_HI
#   endif
#endif

static __unlikely void
timod_pop(queue_t *q)
{
	struct timod *priv = (typeof(priv)) q->q_ptr;
	mblk_t *mp;

	switch (priv->state) {
	case TS_WREQ_ORDREL:
		if (!(priv->flags & TIMOD_EPROTO)) {
			if ((mp = allocb(sizeof(struct T_ordrel_req), BPRI_WAITOK))) {
				struct T_ordrel_req *prim = (typeof(prim)) mp->b_wptr;

				mp->b_wptr = (unsigned char *) (prim + 1);
				mp->b_datap->db_type = M_PROTO;
				prim->PRIM_type = T_ORDREL_REQ;
				qreply(q, mp);
			}
		}

	case TS_DATA_XFER:
		if ((mp = allocb(sizeof(struct T_discon_req), BPRI_WAITOK))) {
			struct T_discon_req *prim = (typeof(prim)) mp->b_wptr;

			mp->b_wptr = (unsigned char *) (prim + 1);
			mp->b_datap->db_type = M_PROTO;
			prim->PRIM_type = T_DISCON_REQ;
			prim->SEQ_number = 0;
			qreply(q, mp);
		}
		break;
	case TS_IDLE:
	default:
		break;
	}
	if ((priv->flags & TIMOD_EPROTO)) {
		if ((mp = allocb(2, BPRI_WAITOK))) {
			mp->b_datap->db_type = M_ERROR;
			*(mp->b_wptr)++ = 0;
			*(mp->b_wptr)++ = 0;
			putnext(q, mp);
		}
#	    if defined M_ERROR_UNDOES_M_HANGUP
		priv->flags &= ~(TIMOD_EPROTO | TIMOD_HANGUP);
#	    else
		priv->flags &= ~TIMOD_EPROTO;
#	    endif
	}
#   if defined M_UNHANGUP
	if ((priv->flags & TIMOD_HANGUP)) {
		if ((mp = allocb(0, BRPI_WAITOK))) {
			mp->b_datap->db_type = M_UNHANGUP;
			putnext(q, mp);
		}
		priv->flags &= ~TIMOD_HANGUP;
	}
#   endif
}

static streamscall int
timod_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
{
	int err = 0;

	if (q->q_ptr != NULL)
		goto quit;
	err = ENXIO;
	if (sflag != MODOPEN || WR(q)->q_next == NULL)
		goto quit;
	err = ENOMEM;
	if (!(timod_alloc_priv(q)))
		goto quit;
	qprocson(q);
	return (0);
      quit:
	return (err);
}

static streamscall int
timod_close(queue_t *q, int oflag, cred_t *crp)
{
	(void) oflag;
	(void) crp;
#if defined LIS

	if (q->q_ptr == NULL) {
		cmn_err(CE_WARN, "%s: %s: LiS double-close bug detected.", MOD_NAME, __FUNCTION__);
		goto quit;
	}

	if (q->q_next == NULL || OTHERQ(q)->q_next == NULL) {
		cmn_err(CE_WARN, "%s: %s: LiS pipe bug: called with NULL q->q_next pointer",
			MOD_NAME, __FUNCTION__);
		goto skip_pop;
	}
#endif
	timod_pop(q);
	goto skip_pop;
      skip_pop:
	qprocsoff(q);
	timod_free_priv(q);
	goto quit;
      quit:
	return (0);
}

#ifdef LINUX

#ifdef LFS

STATIC struct fmodsw timod_fmod = {
	.f_name = MOD_NAME,
	.f_str = &timodinfo,
	.f_flag = D_MP,
	.f_kmod = THIS_MODULE,
};

STATIC __unlikely int
timod_register_strmod(void)
{
	int err;

	if ((err = register_strmod(&timod_fmod)) < 0)
		return (err);
	return (0);
}

STATIC __unlikely int
timod_unregister_strmod(void)
{
	int err;

	if ((err = unregister_strmod(&timod_fmod)) < 0)
		return (err);
	return (0);
}

#if defined WITH_32BIT_CONVERSION
struct timod_trans {
	unsigned int cmd;
	void *opaque;
};

STATIC timod_trans timod_trans_map[] = {
	{.cmd = _O_TI_GETINFO,}
	, {.cmd = _O_TI_OPTMGMT,}
	, {.cmd = _O_TI_BIND,}
	, {.cmd = _O_TI_UNBIND,}
	, {.cmd = _O_TI_GETMYNAME,}
	, {.cmd = _O_TI_GETPEERNAME,}
	, {.cmd = _O_TI_XTI_HELLO,}
	, {.cmd = _O_TI_XTI_GET_STATE,}
	, {.cmd = _O_TI_XTI_CLEAR_EVENT,}
	, {.cmd = _O_TI_XTI_MODE,}
	, {.cmd = _O_TI_TLI_MODE,}
	, {.cmd = O_TI_GETINFO,}
	, {.cmd = O_TI_OPTMGMT,}
	, {.cmd = O_TI_BIND,}
	, {.cmd = O_TI_UNBIND,}
	, {.cmd = TI_GETINFO,}
	, {.cmd = TI_OPTMGMT,}
	, {.cmd = TI_BIND,}
	, {.cmd = TI_UNBIND,}
	, {.cmd = TI_GETMYNAME,}
	, {.cmd = TI_GETPEERNAME,}
	, {.cmd = TI_SETMYNAME,}
	, {.cmd = TI_SETPEERNAME,}
	, {.cmd = TI_SYNC,}
	, {.cmd = TI_GETADDRS,}
	, {.cmd = TI_CAPABILITY,}
	, {.cmd = 0,}
};

STATIC __unlikely void
timod_ioctl32_unregister(void)
{
	struct timod_trans *t;

	for (t = timod_trans_map; t->cmd != 0; t++) {
		streams_unregister_ioctl32(t->opaque);
		t->opaque = NULL;
	}
	return;
}

STATIC __unlikely int
timod_ioctl32_register(void)
{
	struct timod_trans *t;

	for (t = timod_trans_map; t->cmd != 0; t++) {
		if ((t->opaque = streams_register_ioctl32(t->cmd)) == NULL) {
			timod_ioctl32_unregister();
			return (-ENOMEM);
		}
	}
	return (0);
}

#endif

#endif

#ifdef LIS

STATIC __unlikely int
timod_register_strmod(void)
{
	int err;

	if ((err = lis_register_strmod(&timodinfo, MOD_NAME)) == LIS_NULL_MID)
		return (-EIO);
	if ((err = lis_register_module_qlock_option(err, LIS_QLOCK_NONE)) < 0) {
		lis_unregister_strmod(&timodinfo);
		return (err);
	}
	return (0);
}

STATIC __unlikely int
timod_unregister_strmod(void)
{
	int err;

	if ((err = lis_unregister_strmod(&timodinfo)) < 0)
		return (err);
	return (0);
}

#endif

MODULE_STATIC int __init
timodinit(void)
{
	int err;

#ifdef CONFIG_STREAMS_TIMOD_MODULE
	cmn_err(CE_NOTE, TIMOD_BANNER);
#else
	cmn_err(CE_NOTE, TIMOD_SPLASH);
#endif
	if ((err = timod_init_caches())) {
		cmn_err(CE_WARN, "%s: could not init caches, err = %d", MOD_NAME, err);
		return (err);
	}
#if defined WITH_32BIT_CONVERSION
	if ((err = timod_ioctl32_register())) {
		cmn_err(CE_WARN, "%s: could not register 32bit ioctls, err = %d", MOD_NAME, err);
		timod_term_caches();
		return (err);
	}
#endif
	if ((err = timod_register_strmod())) {
		cmn_err(CE_WARN, "%s: could not register module, err = %d", MOD_NAME, err);
#if defined WITH_32BIT_CONVERSION
		timod_ioctl32_unregister();
#endif
		timod_term_caches();
		return (err);
	}
	if (modid == 0)
		modid = err;
	return (0);
}

MODULE_STATIC void __exit
timodterminate(void)
{
	int err;

	if ((err = timod_unregister_strmod()))
		cmn_err(CE_WARN, "%s: could not unregister module", MOD_NAME);
#if defined WITH_32BIT_CONVERSION
	timod_ioctl32_unregister();
#endif
	if ((err = timod_term_caches()))
		cmn_err(CE_WARN, "%s: could not terminate caches", MOD_NAME);
	return;
}

module_init(timodinit);
module_exit(timodterminate);

#endif

OpenSS7
SS7 for the
Common Man
Home TopIndex FirstPrev Next LastMore Download Info FAQ Mail  Home -> Resources -> Browse Source -> /code/strxnet/src/modules/timod.c
Last modified: Sat, 16 Aug 2008 01:54:33 GMT
© Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved.