|
OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
| Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
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;
}
|
|||||||||||||||||||||||||||
|
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
|
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
|||||||||||||||||||||||||||