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/sigtran/lm.c


File /code/strss7/drivers/sigtran/lm.c



#ident "@(#) $RCSfile: lm.c,v $ $Name:  $($Revision: 0.8.2.2 $) $Date: 2002/10/18 03:09:20 $"

static char const ident[] =
    "$RCSfile: lm.c,v $ $Name:  $($Revision: 0.8.2.2 $) $Date: 2002/10/18 03:09:20 $";

/*
 *  =========================================================================
 */

extern ua_t *ua_opens_list;
extern ua_t *ua_links_list;

static xp_t *ua_xp_find(uint type, uint aspid)
{
	xp_t *xp = NULL;
	if (aspid)
		for (xp = (type & UA_MODE_SGP) ? ua_sgp_list : ua_asp_list;
		     xp && xp->aspid != aspid; xp = xp->type.next);
	return (xp);
}

static int ua_xp_create(lp_t * lp, uint aspid, uint type)
{
	xp_t *xp, **xpp, **cpp;
	if ((xp = ua_xp_find(type, aspid))) {
		if (xp->pp)
			return (-EBUSY);
		xp->use_count++;
		xp->pp = lp;
		if (lp)
			lp->xp = xp;
		return (0);
	}
	if ((xp = kmem_cache_alloc(ua_xp_cachep, SLAB_ATOMIC))) {
		xp->pp = lp;
		xp->id = aspid;
		xp->state = ASP_DOWN;
		xp->type = type;
		xp->version = 1;
		xp->use_count = 1;
		switch (type & UA_MODE_MASK) {
		case UA_MODE_SGP:
			switch (type & UA_PROT_MASK) {
			case UA_PROT_SL:
				xp->recv = &m2ua_sgp_recv;
				xp->send = &m2ua_sgp_send;
				xpp = &m2ua_sgp_list;
				break;
			case UA_PROT_MTP:
				xp->recv = &m3ua_sgp_recv;
				xp->send = &m3ua_sgp_send;
				xpp = &m3ua_sgp_list;
				break;
			case UA_PROT_ISUP:
				xp->recv = &isua_sgp_recv;
				xp->send = &isua_sgp_send;
				xpp = &isua_sgp_list;
				break;
			case UA_PROT_SCCP:
				xp->recv = &sua_sgp_recv;
				xp->send = &sua_sgp_send;
				xpp = &sua_sgp_list;
				break;
			case UA_PROT_TCAP:
				xp->recv = &tua_sgp_recv;
				xp->send = &tua_sgp_send;
				xpp = &tua_sgp_list;
				break;
			default:
				kmem_cache_free(ua_xp_cachep, xp);
				return (-EINVAL);
			}
			cpp = &ua_sgp_list;
			break;
		case UA_MODE_ASP:
			switch (type & UA_PROT_MASK) {
			case UA_PROT_SL:
				xp->recv = &m2ua_asp_recv;
				xp->send = &m2ua_asp_send;
				xpp = &m2ua_asp_list;
				break;
			case UA_PROT_MTP:
				xp->recv = &m3ua_asp_recv;
				xp->send = &m3ua_asp_send;
				xpp = &m3ua_asp_list;
				break;
			case UA_PROT_ISUP:
				xp->recv = &isua_asp_recv;
				xp->send = &isua_asp_send;
				xpp = &isua_asp_list;
				break;
			case UA_PROT_SCCP:
				xp->recv = &sua_asp_recv;
				xp->send = &sua_asp_send;
				xpp = &sua_asp_list;
				break;
			case UA_PROT_TCAP:
				xp->recv = &tua_asp_recv;
				xp->send = &tua_asp_send;
				xpp = &tua_asp_list;
				break;
			default:
				kmem_cache_free(ua_xp_cachep, xp);
				return (-EINVAL);
			}
			cpp = &ua_asp_list;
			break;
		default:
			kmem_cache_free(ua_xp_cachep, xp);
			return (-EINVAL);
		}
		if ((xp->prot.next = *xpp))
			xp->prot.next->prot.prev = &xp->prot.next;
		xp->prot.prev = xpp;
		*xpp = xp;
		if ((xp->clas.next = *cpp))
			xp->clas.next->clas.prev = &xp->clas.next;
		xp->clas.prev = cpp;
		*cpp = xp;
		if (lp)
			lp->xp = xp;
		return (0);
	}
	return (-ENOMEM);
}

/*
 *  =========================================================================
 */

/*
 *  LM_AS_ADD_REQ
 *  -----------------------------------
 *  Requests that the driver add or augment the application server for the
 *  protocol on whose user or control queue the  request was issued.  The AS
 *  identifier si for further reference.  The RC or IID identifier will be
 *  added to the AS if the AS already exists with the specified AS Id.
 *
 *  The lower or local management queue normally uses this primitive to add an
 *  application server which does not yet exist at boot time or in response to
 *  an LM_REG_REQ before issuing and LM_REG_RES.
 *
 *  The optional routing (link) key is only required for statically allocated
 *  Application Servers.  This key is used to bind/connect SS7 provider
 *  streams which support the AS or to generate REG REQ to SGP/SPP IPC and UA
 *  proxies.  I don't really intend to use this function, but it is there to
 *  support all SIGTRAN UA allocation modes.
 */
static int lm_as_add_req(queue_t * q, mblk_t * mp)
{
	int err;
	as_t *as;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	do {
		if (mlen < sizeof(*p)) {
			if (!(as = ua_as_find(p->asid, p->rc))) {
				if ((err = ua_as_create(NULL, p->asid, p->rc)))
					break;
				return lm_ok_ack(q, mp, LM_AS_ADD_REQ);
			}
			err = -EBUSY;
			break;
		}
		err = -EMSGSIZE;
		break;
	} while (0);
	return lm_error_ack(q, mp, LM_AS_ADD_REQ, err);
}
static int lm_as_del_req(queue_t * q, mblk_t * mp)
{
}

/*
 *  LM_PROC_ADD_REQ
 *  -----------------------------------
 *  Requests that the driver add an ASP/SGP proxy process.  This is for static
 *  configuration of proxy processes only.  Dynamic configuration will create
 *  SGP proxy processes on demand.
 */
static int lm_proc_add_req(queue_t * q, mblk_t * mp)
{
	int err;
	xp_t *xp;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	do {
		if (mlen < sizeof(*p)) {
			if (!(xp = ua_xp_find(p->type, p->aspid))) {
				if ((err = ua_xp_create(NULL, p->aspid, p->type)))
					break;
				return lm_ok_ack(q, mp, LM_PROC_ADD_REQ);
			}
		      err = -EBUSY:break;
		}
		err = -EMSGSIZE;
		break;
	} while (0);
	return lm_error_ack(q, mp, LM_PROC_ADD_REQ, err);
}
static int lm_proc_del_req(queue_t * q, mblk_t * mp)
{
}

/*
 *  LM_LINK_ADD_REQ
 *  -----------------------------------
 *  Requests that the driver configures and associated the indicated linked
 *  (muxid) stream as the indicated type of proxy and associate it with the
 *  indicated local or remote ASP Identifier.  Transport SGP proxies must have
 *  aspids associated with them.  Transport ASP proxies may either have fixed
 *  aspids associated wtih them or may have aspid set to zero, the aspid to be
 *  identified in subsequent ASPUP message from the ASP if the ASP requires
 *  dynamic registration.
 */
static int lm_link_add_req(queue_t * q, mblk_t * mp)
{
	int err;
	lp_t *lp;
	xp_t *xp;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	lm_link_add_req_t *p = (typeof(p)) mp->b_rptr;
	do {
		if (mlen < sizeof(*p)) {
			if ((lp = ua_link_find(p->muxid))) {

				switch (p->type) {
				case LM_ASP:
				case LM_ASP | LM_IPC:
				case LM_ASP | LM_UAP:

				case LM_SGP:
				case LM_SGP | LM_IPC:
				case LM_SGP | LM_UAP:

				case LM_SPP:
				case LM_SPP | LM_IPC:
				case LM_SPP | LM_UAP:

					if (!(lp->u.xp)) {
						if ((err = ua_xp_create(lp, p->aspid, p->type)))
							break;
						return lm_ok_ack(q, mp, LM_LINK_ADD_REQ);
					}
					err = -EBUSY;
					break;

				default:
				case LM_SS7:
				case LM_SGP | LM_SS7:
				case LM_ASP | LM_SS7:
				case LM_SPP | LM_SS7:
					err = -EINVAL;
					break;
				}
				break;

			}
			err = -ENXIO;
			break;
		}
		err = -EMSGSIZE;
		break;
	} while (0);
	return lm_error_ack_reply(q, mp, LM_LINK_ADD_REQ, err);

}
static int lm_link_del_req(queue_t * q, mblk_t * mp)
{
}
static int lm_route_add_req(queue_t * q, mblk_t * mp)
{
}
static int lm_route_del_req(queue_t * q, mblk_t * mp)
{
}
static int lm_reg_res(queue_t * q, mblk_t * mp)
{
}
static int lm_reg_ref(queue_t * q, mblk_t * mp)
{
}
static int lm_ioctl(queue_t * q, mblk_t * mp)
{
	int err = EOPNOTSUPP;
	struct iocblk *iocp = (struct iocblk *) mp->b_rptr;
	switch (_IOC_TYPE(iocp->ioc_cmd)) {
	case __SID:
	{
		lp_t *lp;
		ua_t *ua = (ua_t *) q->q_ptr;
		struct linkblk *lb = (struct linkblk *)
		    (mp->b_cont ? mp->b_cont->b_rptr : NULL);
		switch (iocp->ioc_cmd) {
		case I_PLINK:
			err = EPERM;
			if (iocp->ioc_cr->cr_uid != 0) {
				ptrace(("Non-root attempt to I_PLINK\n"));
				break;
			}
		case I_LINK:
			err = 0;
			if (lb->l_qbot->q_ptr != NULL) {
				ptrace(("Stream already linked\n"));
				break;
			}
			if ((lp = kmem_cache_alloc(ua_pp_cachep, SLAB_ATOMIC))) {
				bzero(lp, sizeof(lp_t));
				if ((lp->next = ua_links_list))
					lp->next->prev = &lp->next;
				lp->prev = &ua_links_list;
				ua_links_list = lp;
				lp->id.nux = lp->l_index;
				lp->rq = RD(lb->l_qbot);
				lp->wq = WR(lb->l_qbot);
				lp->mq = RD(q);
				lp->rq->q_ptr = lp;
				lp->wq->q_ptr = lp;
			}
			err = ENOMEM;
			break;
		case I_PUNLINK:
			err = EPERM;
			if (iocp->ioc_cr->cr_uid != 0) {
				ptrace(("Non-root attempt to I_PUNLINK\n"));
				break;
			}
		case I_UNLINK:
			err = 0;
			if (!(lp = (lp_t *) lb->l_qbot->q_ptr)) {
				ptrace(("Stream already unlinked\n"));
				break;
			}
			fixme(("Make sure we are not linked to xp\n"));
			if ((*(lp->prev) = lp->next))
				lp->next->prev = lp->prev;
			lp->prev = NULL;
			lp->next = NULL;
			if (lp->bid)
				unbufcall(lp->bid);
			lp->rq->q_ptr = NULL;
			lp->wq->q_ptr = NULL;
			kmem_cache_free(ua_pp_cachep, lp);
			qenable(lp->rq);
			qenable(lp->wq);
			break;
		}
	}
	}
	if (err) {
		mp->b_datap->db_type = M_IOCNAK;
		iocp->ioc_error = err;
		iocp->ioc_rval = -1;
	} else {
		mp->b_datap->db_type = M_IOCACK;
		iocp->ioc_error = 0;
		iocp->ioc_rval = 0;
	}
	qreply(q, mp);
	return (1);
}
static int ua_u_w_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_PROTO:
	case M_PCPROTO:
		switch (*((long *) mp->b_rptr)) {
		case LM_AS_ADD_REQ:
			return lm_as_add_req(q, mp);
		case LM_AS_DEL_REQ:
			return lm_as_del_req(q, mp);
		case LM_PROC_ADD_REQ:
			return lm_proc_add_req(q, mp);
		case LM_PROC_DEL_REQ:
			return lm_proc_del_req(q, mp);
		case LM_LINK_ADD_REQ:
			return lm_link_add_req(q, mp);
		case LM_LINK_DEL_REQ:
			return lm_link_del_req(q, mp);
		case LM_ROUTE_ADD_REQ:
			return lm_route_add_req(q, mp);
		case LM_ROUTE_DEL_REQ:
			return lm_route_del_req(q, mp);
		case LM_REG_RES:
			return lm_reg_res(q, mp);
		case LM_REG_REF:
			return lm_reg_ref(q, mp);
		}
		break;
	case M_IOCTL:
		return lm_ioctl(q, mp);
	case M_FLUSH:
		return ua_w_flush(q, mp);
	}
	return (-EOPNOTSUPP);
}
static INT ua_u_wput(queue_t * q, mblk_t * mp)
{
	return ua_putq(q, mp, &ua_u_w_prim);
}
static INT ua_u_wsrv(queue_t * q)
{
	return ua_srvq(q, &ua_u_w_prim);
}

static int n_data(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_data_ind(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_exdata_ind(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_datack_ind(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_discon_ind(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_reset_ind(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_other_ind(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_ctl(queue_t * q, mblk_t * mp)
{
}
static int n_error(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int n_hangup(queue_t * q, mblk_t * mp)
{
	ua_t *ua = (ua_t *) q->q_ptr;
	if (ua->xp)
		return ((*ua->xp->recv) (q, mp));
	noenable(q);
	return (-EAGAIN);
}
static int ua_l_r_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return n_data(q, mp);
	case M_PROTO:
	case M_PCPROTO:
		switch (*((long *) mp->b_rptr)) {
		case N_DATA_IND:
			return n_data_ind(q, mp);
		case N_EXDATA_IND:
			return n_exdata_ind(q, mp);
		case N_DATACK_IND:
			return n_datack_ind(q, mp);
		case N_DISCON_IND:
			return n_discon_ind(q, mp);
		case N_RESET_IND:
			return n_reset_ind(q, mp);
		default:
			return n_other_ind(q, mp);
		}
		break;
	case M_CTL:
		return n_ctl(q, mp);
	case M_ERROR:
		return n_error(q, mp);
	case M_HANGUP:
		return n_hangup(q, mp);
	case M_FLUSH:
		return ua_r_flush(q, mp);
	}
	return (-EPROTO);
}
static INT ua_l_rput(queue_t * q, mblk_t * mp)
{
	return ua_putq(q, mp, &ua_l_r_prim);
}
static INT ua_l_rsrv(queue_t * q)
{
	return ua_srvq(q, &ua_l_r_prim);
}

static int ua_u_r_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_CTL:
		return ua_u_r_ctl(q, mp);
	case M_FLUSH:
		return ua_r_flush(q, mp);
	default:
		return (5);
	}
}
static INT ua_u_rput(queue_t * q, mblk_t * mp)
{
	return ua_putq(q, mp, &ua_u_r_prim);
}
static INT ua_u_rsrv(queue_t * q)
{
	return ua_srvq(q, &ua_u_r_prim);
}

static int ua_l_w_prim(queue_t * q, mblk_t * mp)
{
	int rtn;
	switch (mp->b_datap->db_type) {
	case M_FLUSH:
		return ua_w_flush(q, mp);
	default:
		return (5);
	}
}
static INT ua_l_wput(queue_t * q, mblk_t * mp)
{
	return ua_putq(q, mp, &ua_l_w_prim);
}
static INT ua_l_wsrv(queue_t * q)
{
	return ua_srvq(q, &ua_l_w_prim);
}

/*
 *  =========================================================================
 *
 *  OPEN and CLOSE
 *
 *  =========================================================================
 */
static int ua_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp)
{
	int cmajor = getmajor(*devp);
	int cminor = getminor(*devp);
	dp_t *dp, **dpp;
	if (sflag == MODOPEN || WR(q)->q_next) {
		ptrace(("Can't open as module\n"));
		return (EIO);
	}
	if (cmajor == UA_CMAJOR && cminor == 1 && crp->cr_uid != 0) {
		ptrace(("Non-root priviledge user attempting to open control stream\n"));
		return (PERM);
	}
	if (q->q_ptr != NULL) {
		ptrace(("Device already open\n"));
		return (0);
	}
	if (cmajor == UA_CMAJOR && cminor == 0) {
		ptrace(("Clone minor opened\n"));
		sflag = CLONEOPEN;
	}
	for (dpp = &ua_opens_list; *dpp; dpp = &(*dpp)->next) {
		ushort dmajor = getmajor(*devp);
		if (cmajor < dmajor)
			break;
		if (cmajor == dmajor) {
			if (sflag == CLONEOPEN) {
				if (++cminor > UA_NMINOR) {
					if (++cmajor > UA_CMAJOR + (UA_NMAJOR - 1))
						break;
					cminor = 0;
				}
				continue;
			}
			ptrace(("Requested device in use\n"));
			return (EIO);
		}
	}
	if (cmajor > UA_CMAJOR + (UA_NMAJOR - 1)) {
		ptrace(("No devices available\n"));
		return (ENXIO);
	}
	*devp = makedevice(cmajor, cminor);
	if (!(dp = kmem_cache_alloc(ua_pp_cachep, SLAB_ATOMIC))) {
		ptrace(("Cannot allocate cache entry for device\n"));
		return (ENOMEM);
	}
	bzero(dp, sizeof(dp_t));
	if ((dp->next = *dpp))
		dp->next->prev = &dp->next;
	dp->prev = dpp;
	*dpp = dp;
	dp->id.dev = *devp;
	dp->rq = RD(q);
	dp->wq = WR(q);
	dp->mq = RD(q);
	dp->rq->q_ptr = dp;
	dp->wq->q_ptr = dp;
	return (0);
}
static int ua_close(queue_t * q, int flag, cred_t * crp)
{
	dp_t *dp = (dp_t *) q->q_ptr;
	if ((*(dp->prev) = dp->next))
		dp->next->prev = dp->next;
	dp->prev = NULL;
	dp->next = NULL;
	if (dp->bid)
		unbufcall(dp->bid);
	dp->rq->q_ptr = NULL;
	dp->wq->q_ptr = NULL;
	fixme(("Make sure that we are not referenced...\n"));
	kmem_cache_free(ua_pp_cachep, dp);
	return (0);
}

/*
 *  =========================================================================
 *
 *  Lis Driver Initialization
 *
 *  =========================================================================
 */
static int ua_init(void)
{
	int rtn;
	if (!ua_u_minfo.mi_idnum) {
		if ((rtn = ua_init_caches()))
			return (-rtn);
		if ((rtn =
		     lis_register_strdev(UA_CMAJOR, &ua_info, UA_NMINOR,
					 ua_u_minfo.mi_idname)) < 0) {
			ua_u_minfo.mi_idnum = 0;
			rare();
			cmn_err(CE_NOTE, "ua: couldn't register driver\n");
			return (-rtn);
			ua_u_minfo.mi_idnum = rtn;
		}
	}
	return (0);
}
static void ua_terminate(void)
{
	if (ua_u_minfo.mi_idnum) {
		if ((ua_u_minfo.mi_idnum = lis_unregister_strdev(ua_u_minfo.mi_idnum))) {
			ua_u_minfo.mi_idnum = 0;
			rare();
			cmn_err(CE_WARN, "ua: couldn't unregsiter driver\n");
		}
	}
}

/*
 *  =========================================================================
 *
 *  Kernel Module Initialization
 *
 *  =========================================================================
 */
int init_module(void)
{
	int err;
	ua_init();
	return (0);
}
void cleanup_module(void)
{
	ua_terminate();
	return;
}


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

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

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