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/sli/sl_mux.c


File /code/strss7/drivers/sli/sl_mux.c



#ident "@(#) $RCSfile: sl_mux.c,v $ $Name:  $($Revision: 0.8.2.8 $) $Date: 2003/04/03 19:51:13 $"

char const ident[] =
    "$RCSfile: sl_mux.c,v $ $Name:  $($Revision: 0.8.2.8 $) $Date: 2003/04/03 19:51:13 $";

#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 <sys/dki.h>

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

#include "../debug.h"

#define SL_DESCRIP	"SS7/IP SIGNALLING LINK (SL) STREAMS MULTIPLEXING DRIVER."
#define SL_COPYRIGHT	"Copyright (c) 1997-2002 OpenSS7 Corporation.  All Rights Reserved."
#define SL_DEVICE	"Part of the OpenSS7 Stack for LiS STREAMS."
#define SL_CONTACT	"Brian Bidulock <bidulock@openss7.org>"
#define SL_LICENSE	"GPL"
#define SL_BANNER	SL_DESCRIP	"\n" \
			SL_COPYRIGHT	"\n" \
			SL_DEVICE	"\n" \
			SL_CONTACT

MODULE_AUTHOR(SL_CONTACT);
MODULE_DESCRIPTION(SL_DESCRIP);
MODULE_SUPPORTED_DEVICE(SL_DEVICE);
#ifdef MODULE_LICENSE
MODULE_LICENSE(SL_LICENSE);
#endif

static struct module_info sl_minfo = {
	0,				/* id */
	"sl-mux",			/* name */
	0,				/* min packet size accepted */
	INFPSZ,				/* max packet size accepted */
	10240L,				/* high water mark */
	512L				/* low water mark */
};

static int sl_open(queue_t *, dev_t *, int, int, cred_t *);
static int sl_close(queue_t *, int, cred_t *);

static int sl_u_wput(queue_t *, mblk_t *);
static int sl_l_rput(queue_t *, mblk_t *);
static int sl_u_rsrv(queue_t * q);
static int sl_l_wsrv(queue_t * q);

static struct qinit sl_rinit = {
	NULL,				/* put */
	sl_u_rsrv,			/* service */
	sl_open,			/* open */
	sl_close,			/* close */
	NULL,				/* admin */
	&sl_minfo,			/* info */
	NULL				/* stat */
};

static struct qinit sl_winit = {
	sl_u_wput,			/* put */
	NULL,				/* service */
	NULL,				/* open */
	NULL,				/* close */
	NULL,				/* admin */
	&sl_minfo,			/* info */
	NULL				/* stat */
};

/*
 * qinit structures (rd and wr side, lower) 
 */
static struct module_info sl_lminfo = {
	0,				/* id */
	"sl-mux-lwr",			/* name */
	0,				/* min packet size accepted */
	INFPSZ,				/* max packet size accepted */
	10240L,				/* high water mark */
	512L				/* low water mark */
};

static struct qinit sl_lrinit = {
	sl_l_rput,			/* put */
	NULL,				/* service */
	NULL,				/* open */
	NULL,				/* close */
	NULL,				/* admin */
	&sl_lminfo,			/* info */
	NULL				/* stat */
};

static struct qinit sl_lwinit = {
	NULL,				/* put */
	sl_l_wsrv,			/* service */
	NULL,				/* open */
	NULL,				/* close */
	NULL,				/* admin */
	&sl_lminfo,			/* info */
	NULL				/* stat */
};

static struct streamtab sl_info = {
	&sl_rinit,			/* read queue */
	&sl_winit,			/* write queue */
	&sl_lrinit,			/* mux read queue */
	&sl_lwinit			/* mux write queue */
};

static queue_t *qbot = NULL;
static queue_t *qtop = NULL;

static int sltm_timer = 0;
static int recovery_timer = 0;

static int sltm_failures = 0;
static int recovery_attempts = 0;

static int sl_ioctl(queue_t * q, mblk_t * mp)
{
	struct iocblk *iocb;
	struct linkblk *lb;
	int err;
	iocb = (typeof(iocb)) mp->b_rptr;
	switch (iocb->ioc_cmd) {
	case I_LINK:
	case I_PLINK:
	{
		ptrace(("Got I_(P)LINK\n"));
		if (!mp->b_cont) {
			assure(mp->b_cont);
			err = EINVAL;
			break;
		}
		if (qbot) {
			assure(!qbot);
			err = EBUSY;
			break;
		}
		lb = (typeof(lb)) mp->b_cont->b_rptr;
		if (!(qbot = lb->l_qbot)) {
			assure(qbot);
			err = EINVAL;
			break;
		}
		MOD_INC_USE_COUNT;
		sltm_failures = 0;
		recovery_attempts = 0;
		RD(qbot)->q_ptr = &qtop;
		WR(qbot)->q_ptr = &qtop;
		err = 0;
		break;
	}
	case I_UNLINK:
	case I_PUNLINK:
	{
		ptrace(("Got I_(P)UNLINK\n"));
		if (!qbot) {
			assure(!qbot);
			err = EINVAL;
			break;
		}
		if (recovery_timer)
			untimeout(xchg(&recovery_timer, 0));
		if (sltm_timer)
			untimeout(xchg(&sltm_timer, 0));
		RD(qbot)->q_ptr = NULL;
		WR(qbot)->q_ptr = NULL;
		qbot = NULL;
		MOD_DEC_USE_COUNT;
		err = 0;
		break;
	}
	default:
		ptrace(("Got IOCTL: %d\n", iocb->ioc_cmd));
		if (qbot) {
			ptrace(("Passing along IOCTL\n"));
			putq(qbot, mp);
			return (0);
		}
		assure(0);
		ptrace(("Unsupported IOCTL\n"));
		err = EOPNOTSUPP;
		break;
	}
	if (err) {
		mp->b_datap->db_type = M_IOCNAK;
		iocb->ioc_error = err;
		iocb->ioc_rval = -1;
	} else {
		mp->b_datap->db_type = M_IOCACK;
		iocb->ioc_error = 0;
		iocb->ioc_rval = 0;
	}
	qreply(q, mp);
	return (0);
}

static void restart_link(caddr_t data)
{
	queue_t *q = (queue_t *) data;
	mblk_t *dp;
	recovery_timer = 0;
	if ((dp = allocb(sizeof(long), BPRI_MED))) {
		sl_start_req_t *p;
		dp->b_datap->db_type = M_PROTO;
		p = ((typeof(p)) dp->b_wptr)++;
		p->sl_primitive = SL_START_REQ;
		ptrace(("Sending SL_START_REQ\n"));
		recovery_attempts++;
		qreply(q, dp);
		return;
	}
	recovery_timer = timeout(&restart_link, (caddr_t) q, 12 * HZ);
}

static void send_sltm(caddr_t data);

static void failed_sltm(caddr_t data)
{
	sltm_timer = 0;
	__printd(("mtp: SLTM Failed\n"));
	if (++sltm_failures >= 2) {
		queue_t *q = (queue_t *) data;
		mblk_t *dp;
		if ((dp = allocb(sizeof(long), BPRI_MED))) {
			sl_stop_req_t *p;
			dp->b_datap->db_type = M_PROTO;
			p = ((typeof(p)) dp->b_wptr)++;
			p->sl_primitive = SL_STOP_REQ;
			ptrace(("Sending SL_STOP_REQ\n"));
			recovery_timer = timeout(&restart_link, (caddr_t) q, 12 * HZ);
			qreply(q, dp);
		}
	}
	send_sltm(data);
}

static void send_sltm(caddr_t data)
{
	queue_t *q = (queue_t *) data;
	mblk_t *mp;
	uint dpc = 0x11d8;
	uint opc = 0x11ae;
	uint sls = 0;
	uint h0 = 1;
	uint h1 = 1;
	uint tbyte = ((jiffies >> 8) & 0x0f);
	uint tlen = jiffies & 0x0f;
	if ((mp = allocb(7 + tlen, BPRI_MED))) {
		int i;
		unsigned char *x;
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += 6;
		mp->b_wptr += 6;
		x = mp->b_wptr;
		*x++ = 0x01;	/* sio == 1 */
		*x++ = dpc;
		*x++ = ((dpc >> 8) & 0x3f) | (opc << 6);
		*x++ = (opc >> 2);
		*x++ = ((opc >> 10) & 0x0f) | (sls << 4);
		*x++ = h0 | (h1 << 4);
		*x++ = (tlen << 4) & 0xf0;
		for (i = 0; i < tlen; i++)
			*x++ = tbyte;
		mp->b_wptr = x;
		__printd(("mtp: Sent SLTM\n"));
		qreply(q, mp);
	}
	sltm_timer = timeout(&failed_sltm, (caddr_t) q, 4 * HZ);	/* T1T */
}

static int handle_message(queue_t * q, mblk_t * mp)
{
	unsigned char *x = mp->b_rptr;
	uint sio, dpc, opc, sls, h0, h1, b;
	int i;
	__printd(("mtp: M_DATA: "));
	for (i = 0; i < mp->b_wptr - mp->b_rptr; i++)
		__printd(("%02x ", x[i] & 0x0ff));
	__printd(("\n"));
	sio = *x++;
	if ((sio & 0xf) == 1 || (sio & 0xf) == 2) {
		ptrace(("Got Test Message\n"));
		b = *x++ & 0x00ff;
		dpc = ((b << 0) & 0xff);
		b = *x++ & 0x00ff;
		dpc |= ((b << 8) & 0x3f00);
		opc = ((b >> 6) & 0x03);
		b = *x++ & 0x00ff;
		opc |= ((b << 2) & 0x3fc);
		b = *x++ & 0x00ff;
		opc |= ((b << 10) & 0x3c00);
		sls = (b >> 4) & 0x0f;
		b = *x++ & 0x00ff;
		h0 = b & 0x0f;
		h1 = b >> 4;
		if (h0 == 1 && h1 == 1) {
			mblk_t *dp;
			__printd(("mtp: Got SLTM\n"));
			if ((dp = copymsg(mp))) {
				x = dp->b_rptr;
				h1 = 2;
				x++;
				*x++ = opc;
				*x++ = ((opc >> 8) & 0x3f) | (dpc << 6);
				*x++ = (dpc >> 2);
				*x++ = ((dpc >> 10) & 0x0f) | (sls << 4);
				*x++ = h0 | (h1 << 4);
				/* send back */
				__printd(("mtp: Sent SLTA\n"));
				qreply(q, dp);
				freemsg(mp);
				return (1);
			}
		} else if (h0 == 1 && h1 == 2) {
			__printd(("mtp: Got SLTA\n"));
			if (sltm_timer)
				untimeout(sltm_timer);
			sltm_failures = 0;
			sltm_timer = timeout(&send_sltm, (caddr_t) q, 2 * 60 * HZ);	/* T2T */
		}
	}
	return (0);
}

static int sl_l_rput(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_DATA:
		if (handle_message(q, mp))
			return (0);
		break;
	case M_PROTO:
	case M_PCPROTO:
	{
		ptrace(("Got M_PROTO = %ld\n", *(long *) mp->b_rptr));
		switch (*(long *) mp->b_rptr) {
		case SL_OUT_OF_SERVICE_IND:
		{
			__printd(("mtp: Got SL_OUT_OF_SERVICE_IND\n"));
			if (sltm_timer)
				untimeout(xchg(&sltm_timer, 0));
			if (recovery_timer)
				untimeout(xchg(&recovery_timer, 0));
			if (!recovery_attempts)
				restart_link((caddr_t) q);
			else
				recovery_timer = timeout(&restart_link, (caddr_t) q, 1 * HZ);	/* T17 
												 */
			freemsg(mp);
			return (0);
		}
		case SL_PDU_IND:
			__printd(("mtp: Got SL_PDU_IND\n"));
			if (handle_message(q, mp->b_cont)) {
				freeb(mp);
				return (0);
			}
			break;
		case SL_IN_SERVICE_IND:
			__printd(("mtp: Got SL_IN_SERVICE_IND\n"));
			recovery_attempts = 0;
			send_sltm((caddr_t) q);
			freemsg(mp);
			return (0);
		}
		break;
	}
	}
	if (qtop) {
		ptrace(("Passing along\n"));
		putq(qtop, mp);
		return (0);
	}
	ptrace(("Discarding\n"));
	freemsg(mp);
	return (0);
}

static int sl_u_wput(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_IOCTL:
		ptrace(("Got IOCTL\n"));
		sl_ioctl(q, mp);
		return (0);
	case M_FLUSH:
		if (*mp->b_rptr & FLUSHW)
			flushq(q, FLUSHDATA);
		if (*mp->b_rptr & FLUSHR) {
			*mp->b_rptr &= ~FLUSHW;
			flushq(OTHER(q), FLUSHDATA);
			qreply(q, mp);
		} else {
			ptrace(("Discarding\n"));
			freemsg(mp);
		}
		return (0);
	}
	if (qbot) {
		ptrace(("Passing along\n"));
		putq(qbot, mp);
		return (0);
	}
	ptrace(("Discarding\n"));
	freemsg(mp);
	return (0);
}

static int sl_u_rsrv(queue_t * q)
{
	mblk_t *mp;
	while ((mp = getq(q))) {
		if (q->q_next)
			putnext(q, mp);
		else
			freemsg(mp);
	}
	return (0);
}

static int sl_l_wsrv(queue_t * q)
{
	mblk_t *mp;
	while ((mp = getq(q))) {
		if (q->q_next)
			putnext(q, mp);
		else
			freemsg(mp);
	}
	return (0);
}

static int sl_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp)
{
	if (q->q_ptr)
		return (0);
	if (qtop) {
		assure(!qtop);
		return (ENXIO);
	}
	MOD_INC_USE_COUNT;
	qtop = q;
	RD(q)->q_ptr = &qbot;
	WR(q)->q_ptr = &qbot;
	return (0);
}

static int sl_close(queue_t * q, int sflag, cred_t * crp)
{
	qtop = NULL;
	RD(q)->q_ptr = NULL;
	WR(q)->q_ptr = NULL;
	MOD_DEC_USE_COUNT;
	return (0);
}

/*
 *  =========================================================================
 *
 *  Kernel Module Initialization
 *
 *  =========================================================================
 */
int init_module(void)
{
	cmn_err(CE_NOTE, SL_BANNER);	/* console splash */
	lis_register_strdev(MUX_CMAJOR, &sl_info, 256, "sl-mux");
	return (0);
}
void cleanup_module(void)
{
	lis_unregister_strdev(MUX_CMAJOR);
	return;
}


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

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

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