677 lines
18 KiB
C
677 lines
18 KiB
C
/*
|
|
* application.c
|
|
*
|
|
* Written by Karsten Keil <kkeil@linux-pingi.de>
|
|
*
|
|
* Copyright (C) 2011 Karsten Keil <kkeil@linux-pingi.de>
|
|
*
|
|
* This program is free software, distributed under the terms of
|
|
* the GNU General Public License Version 2 as published by the
|
|
* Free Software Foundation. See the LICENSE file included with
|
|
* this package for more details.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include "m_capi.h"
|
|
#include "mc_buffer.h"
|
|
|
|
static struct mCAPIobj AppRoot;
|
|
|
|
/* not in capi header files yet */
|
|
void capi_freeapplid(unsigned);
|
|
|
|
int mApplication_init(void)
|
|
{
|
|
int ret;
|
|
|
|
memset(&AppRoot, 0, sizeof(AppRoot));
|
|
ret = init_cobj(&AppRoot, NULL, Cot_Root, 0, 0);
|
|
return ret;
|
|
}
|
|
|
|
static void app_sendcontrol(struct mApplication *appl, int cmd)
|
|
{
|
|
int ret;
|
|
|
|
if (appl->cpipe[1] > 0) {
|
|
ret = write(appl->cpipe[1], &cmd, sizeof(cmd));
|
|
if (ret < sizeof(cmd))
|
|
eprint("%s: refcount %d cannot write cmd=%x to controlpipe(%d) ret=%d - %s\n",
|
|
CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt, cmd, appl->cpipe[1], ret, strerror(errno));
|
|
} else
|
|
eprint("%s: refcount %d cannot write cmd=%x - control pipe closed\n",
|
|
CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt, cmd);
|
|
}
|
|
|
|
struct mApplication *RegisterApplication(uint16_t ApplId, uint32_t MaxB3Connection, uint32_t MaxB3Blks, uint32_t MaxSizeB3)
|
|
{
|
|
struct mApplication *appl;
|
|
int ret;
|
|
|
|
appl = calloc(1, sizeof(*appl));
|
|
if (appl) {
|
|
appl->lcl = calloc(mI_ControllerCount, sizeof(void *));
|
|
if (appl->lcl) {
|
|
appl->cobj.id2 = ApplId;
|
|
ret = init_cobj_registered(&appl->cobj, &AppRoot, Cot_Application, 0);
|
|
if (ret) {
|
|
eprint("Appl %d: Error on init CapiObj - %s\n", ApplId, strerror(ret));
|
|
free(appl->lcl);
|
|
free(appl);
|
|
appl = NULL;
|
|
} else {
|
|
if (ret) {
|
|
wprint("Application %d already registered\n", ApplId);
|
|
put_cobj(&AppRoot);
|
|
free(appl->lcl);
|
|
free(appl);
|
|
appl = NULL;
|
|
} else {
|
|
appl->MaxB3Con = MaxB3Connection;
|
|
appl->MaxB3Blk = MaxB3Blks;
|
|
appl->MaxB3Size = MaxSizeB3;
|
|
appl->cpipe[0] = -1;
|
|
appl->cpipe[1] = -1;
|
|
}
|
|
}
|
|
} else {
|
|
eprint("Appl %d: No memory for lController array\n", ApplId);
|
|
free(appl);
|
|
appl = NULL;
|
|
}
|
|
} else {
|
|
eprint("Appl %d: No memory for application (%zd bytes)\n", ApplId, sizeof(*appl));
|
|
}
|
|
return appl;
|
|
}
|
|
|
|
int register_lController(struct mApplication *appl, struct lController *lc)
|
|
{
|
|
unsigned int i;
|
|
|
|
i = lc->cobj.id - 1;
|
|
if (i >= mI_ControllerCount) {
|
|
eprint("%s: Register invalid controller ID:%d\n", CAPIobjIDstr(&appl->cobj), lc->cobj.id);
|
|
return -EINVAL;
|
|
}
|
|
if (appl->lcl[i]) {
|
|
eprint("%s: controller idx %d ID:%d\already registered\n", CAPIobjIDstr(&appl->cobj), i, lc->cobj.id);
|
|
return -EBUSY;
|
|
}
|
|
if (get_cobj(&lc->cobj)) {
|
|
appl->lcl[i] = lc;
|
|
} else {
|
|
eprint("%s: controller idx %d cannot get controller object %s\n", CAPIobjIDstr(&appl->cobj), i, CAPIobjIDstr(&lc->cobj));
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Release the Application
|
|
*
|
|
* depending who initiate this we cannot release imediatly, if
|
|
* any AppPlci is still in use.
|
|
*
|
|
* @who: 0 - a AppPlci is released in state APPL_STATE_RELEASE
|
|
* 1 - Application is released from CAPI application
|
|
* 2 - the controller is resetted
|
|
* 3 - the controller is removed
|
|
* 4 - the CAPI module will be unload
|
|
*/
|
|
void ReleaseApplication(struct mApplication *appl, int unregister)
|
|
{
|
|
int ret;
|
|
unsigned int i;
|
|
|
|
pthread_rwlock_wrlock(&appl->cobj.lock);
|
|
if (appl->cobj.cleaned) {
|
|
pthread_rwlock_unlock(&appl->cobj.lock);
|
|
wprint("%s: already cleaned\n", CAPIobjIDstr(&appl->cobj));
|
|
return;
|
|
} else
|
|
appl->cobj.cleaned = 1;
|
|
|
|
appl->unregistered = unregister;
|
|
|
|
if (appl->cpipe[0] > -1 && appl->cpipe[1] > -1) {
|
|
wprint("%s appl->cpipe(%d, %d) still open - reuse fds\n", CAPIobjIDstr(&appl->cobj), appl->cpipe[0], appl->cpipe[1]);
|
|
} else {
|
|
ret = pipe2(appl->cpipe, O_NONBLOCK);
|
|
if (ret)
|
|
eprint("%s: Cannot open control pipe - %s\n", CAPIobjIDstr(&appl->cobj), strerror(errno));
|
|
else
|
|
dprint(MIDEBUG_CONTROLLER, "create appl->cpipe(%d, %d)\n", appl->cpipe[0], appl->cpipe[1]);
|
|
}
|
|
dprint(MIDEBUG_CONTROLLER, "close appl->fd %d\n", appl->fd);
|
|
close(appl->fd);
|
|
appl->fd = -1;
|
|
|
|
pthread_rwlock_unlock(&appl->cobj.lock);
|
|
|
|
/* Signal assigned logical controllers Application is gone */
|
|
for (i = 0; i < mI_ControllerCount; i++) {
|
|
if (appl->lcl[i]) {
|
|
release_lController(appl->lcl[i]);
|
|
cleanup_lController(appl->lcl[i]);
|
|
}
|
|
}
|
|
dprint(MIDEBUG_CAPIMSG, "%s: cleaning done refcnt:%d\n", CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt);
|
|
app_sendcontrol(appl, MI_PUT_APPLICATION);
|
|
}
|
|
|
|
int ReleaseAllApplications(void)
|
|
{
|
|
struct mApplication *appl;
|
|
struct mCAPIobj *co;
|
|
int ret, cnt = 0, fd;
|
|
|
|
co = get_next_cobj(&AppRoot, NULL);
|
|
while (co) {
|
|
appl = container_of(co, struct mApplication, cobj);
|
|
fd = appl->fd;
|
|
ReleaseApplication(appl, 0);
|
|
ret = mIcapi_mainpoll_releaseApp(fd, appl->cpipe[0]);
|
|
if (ret < 0)
|
|
eprint("%s mainpoll not released\n", CAPIobjIDstr(&appl->cobj));
|
|
co = get_next_cobj(&AppRoot, co);
|
|
cnt++;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
void Free_Application(struct mCAPIobj *co)
|
|
{
|
|
unsigned int i;
|
|
struct mApplication *appl = container_of(co, struct mApplication, cobj);
|
|
struct lController *lc;
|
|
|
|
delist_cobj(&appl->cobj);
|
|
if (appl->lcl) {
|
|
for (i = 0; i < mI_ControllerCount; i++) {
|
|
lc = appl->lcl[i];
|
|
appl->lcl[i] = NULL;
|
|
if (lc) {
|
|
release_lController(lc);
|
|
Free_lController(&lc->cobj);
|
|
}
|
|
}
|
|
}
|
|
if (!appl->unregistered) /* filedescriptor was closed */
|
|
capi_freeapplid(appl->cobj.id2);
|
|
dprint(MIDEBUG_CONTROLLER, "close appl->fd %d\n", appl->fd);
|
|
if (appl->fd > 0)
|
|
close(appl->fd);
|
|
appl->fd = -1;
|
|
dprint(MIDEBUG_CONTROLLER, "close appl->cpipe(%d, %d)\n", appl->cpipe[0], appl->cpipe[1]);
|
|
if (appl->cpipe[1] > 0)
|
|
close(appl->cpipe[1]);
|
|
appl->cpipe[1] = -1;
|
|
if (appl->cpipe[0] > 0)
|
|
close(appl->cpipe[0]);
|
|
appl->cpipe[0] = -1;
|
|
|
|
put_cobj(appl->cobj.parent);
|
|
appl->cobj.parent = NULL;
|
|
iprint("%s: refcnt=%d freed\n", CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt);
|
|
pthread_rwlock_destroy(&appl->cobj.lock);
|
|
if (appl->lcl)
|
|
free(appl->lcl);
|
|
appl->lcl = NULL;
|
|
free_capiobject(&appl->cobj, appl);
|
|
}
|
|
|
|
void dump_applications(void)
|
|
{
|
|
struct mApplication *ap;
|
|
struct mCAPIobj *co;
|
|
unsigned int i;
|
|
|
|
if (pthread_rwlock_tryrdlock(&AppRoot.lock)) {
|
|
wprint("Cannot read lock application list for dumping\n");
|
|
return;
|
|
}
|
|
co = AppRoot.listhead;
|
|
while (co) {
|
|
ap = container_of(co, struct mApplication, cobj);
|
|
iprint("%s: MaxB3Con:%d MaxB3Blk:%d MaxB3Size:%d\n", CAPIobjIDstr(&ap->cobj),
|
|
ap->MaxB3Con, ap->MaxB3Blk, ap->MaxB3Size);
|
|
iprint("%s: Refs:%d cleaned:%s unregistered:%s cpipe(%d, %d)\n", CAPIobjIDstr(&ap->cobj),
|
|
ap->cobj.refcnt, ap->cobj.cleaned ? "yes" : "no", ap->unregistered ? "yes" : "no",
|
|
ap->cpipe[0], ap->cpipe[1]);
|
|
for (i = 0; i < mI_ControllerCount; i++) {
|
|
if (ap->lcl[i]) {
|
|
dump_lcontroller(ap->lcl[i]);
|
|
ap->lcl[i]->listed = 1;
|
|
}
|
|
}
|
|
co = co->next;
|
|
}
|
|
pthread_rwlock_unlock(&AppRoot.lock);
|
|
}
|
|
|
|
void Put_Application_cleaned(struct mCAPIobj *co)
|
|
{
|
|
struct mApplication *appl = container_of(co, struct mApplication, cobj);
|
|
|
|
if (appl->cobj.cleaned && appl->cpipe[1] > 0)
|
|
app_sendcontrol(appl, MI_PUT_APPLICATION);
|
|
}
|
|
|
|
void delisten_application(struct lController *lc)
|
|
{
|
|
unsigned int i;
|
|
struct mApplication *appl;
|
|
|
|
appl = lc->Appl;
|
|
if (!appl) {
|
|
wprint("Appl not linked\n");
|
|
return;
|
|
}
|
|
lc->Appl = NULL;
|
|
i = lc->cobj.id;
|
|
i--;
|
|
if (i < mI_ControllerCount) {
|
|
if (appl->lcl[i])
|
|
put_cobj(&lc->cobj);
|
|
appl->lcl[i] = NULL;
|
|
}
|
|
put_cobj(&appl->cobj);
|
|
}
|
|
|
|
struct lController *get_lController(struct mApplication *appl, unsigned int cont)
|
|
{
|
|
struct lController *lc;
|
|
|
|
if (cont > 0 && cont <= mI_ControllerCount)
|
|
lc = appl->lcl[cont - 1];
|
|
else {
|
|
wprint("%s: wrong controller id %d (max %d)\n", CAPIobjIDstr(&appl->cobj), cont, mI_ControllerCount);
|
|
lc = NULL;
|
|
}
|
|
if (lc) {
|
|
if (!get_cobj(&lc->cobj)) {
|
|
wprint("%s: cannot get controller object %s\n", CAPIobjIDstr(&appl->cobj), CAPIobjIDstr(&lc->cobj));
|
|
lc = NULL;
|
|
}
|
|
}
|
|
return lc;
|
|
}
|
|
|
|
static struct lController *find_lController(struct mApplication *appl, unsigned int cont)
|
|
{
|
|
struct lController *lc;
|
|
|
|
if (cont > 0 && cont <= mI_ControllerCount)
|
|
lc = appl->lcl[cont - 1];
|
|
else {
|
|
wprint("%s: wrong controller id %d (max %d)\n", CAPIobjIDstr(&appl->cobj), cont, mI_ControllerCount);
|
|
lc = NULL;
|
|
}
|
|
return lc;
|
|
}
|
|
|
|
void SendMessage2Application(struct mApplication *appl, struct mc_buf *mc)
|
|
{
|
|
int ret;
|
|
|
|
if (mI_debug_mask & MIDEBUG_CAPIMSG)
|
|
mCapi_message2str(mc);
|
|
ret = send(appl->fd, mc->rb, mc->len, 0);
|
|
if (ret != mc->len)
|
|
wprint("Message send error len=%d ret=%d - %s\n", mc->len, ret, strerror(errno));
|
|
}
|
|
|
|
void SendCmsg2Application(struct mApplication *appl, struct mc_buf *mc)
|
|
{
|
|
int ret;
|
|
|
|
if (appl->cobj.cleaned || appl->fd < 0) {
|
|
/* Application is gone so we need answer INDICATIONS to avoid blocking the state machine */
|
|
wprint("%s: Cannot send %s to released application\n", CAPIobjIDstr(&appl->cobj),
|
|
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
|
|
if (mc->cmsg.Subcommand != CAPI_IND)
|
|
return;
|
|
switch(mc->cmsg.Command) {
|
|
// for NCCI state machine
|
|
case CAPI_CONNECT_B3:
|
|
mc->cmsg.Reject = 2;
|
|
case CAPI_CONNECT_B3_ACTIVE:
|
|
case CAPI_DISCONNECT_B3:
|
|
break;
|
|
// for PLCI state machine
|
|
case CAPI_CONNECT:
|
|
mc->cmsg.Reject = 2;
|
|
case CAPI_CONNECT_ACTIVE:
|
|
case CAPI_DISCONNECT:
|
|
break;
|
|
case CAPI_FACILITY:
|
|
case CAPI_MANUFACTURER:
|
|
case CAPI_INFO:
|
|
wprint("%s %s ignored\n", CAPIobjIDstr(&appl->cobj),
|
|
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
|
|
return;
|
|
default:
|
|
wprint("%s: %s not handled\n", CAPIobjIDstr(&appl->cobj),
|
|
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
|
|
return;
|
|
}
|
|
capi20_cmsg_answer(&mc->cmsg);
|
|
capi_cmsg2message(&mc->cmsg, mc->rb);
|
|
mc->len = CAPIMSG_LEN(mc->rb);
|
|
mc->refcnt++; /* The message is reused, so increment the refcnt to allow double free */
|
|
dprint(MIDEBUG_CONTROLLER, "%s: sent emulated answer %s to PutMessageApplication\n",
|
|
CAPIobjIDstr(&appl->cobj), capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
|
|
ret = PutMessageApplication(appl, mc);
|
|
if (ret)
|
|
dprint(MIDEBUG_CONTROLLER, "%s: sent emulated answer %s to PutMessageApplication returned=%d\n",
|
|
CAPIobjIDstr(&appl->cobj), capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand), ret);
|
|
} else {
|
|
capi_cmsg2message(&mc->cmsg, mc->rb);
|
|
mc->len = CAPIMSG_LEN(mc->rb);
|
|
if (mI_debug_mask & MIDEBUG_CAPIMSG)
|
|
mCapi_message2str(mc);
|
|
ret = send(appl->fd, mc->rb, mc->len, 0);
|
|
if (ret != mc->len)
|
|
eprint("Message send error len=%d ret=%d - %s\n", mc->len, ret, strerror(errno));
|
|
}
|
|
}
|
|
|
|
void SendCmsgAnswer2Application(struct mApplication *appl, struct mc_buf *mc, __u16 Info)
|
|
{
|
|
capi_cmsg_answer(&mc->cmsg);
|
|
mc->cmsg.Info = Info;
|
|
SendCmsg2Application(appl, mc);
|
|
}
|
|
|
|
struct lPLCI *get_lPLCI4plci(struct mApplication *appl, uint32_t id)
|
|
{
|
|
struct lPLCI *lp = NULL;;
|
|
struct lController *lc;
|
|
struct mPLCI *plci;
|
|
|
|
lc = find_lController(appl, id & 0x7f);
|
|
if (lc) {
|
|
plci = getPLCI4Id(p4lController(lc), id & 0xFFFF);
|
|
if (plci) {
|
|
lp = get_lPLCI4Id(plci, appl->cobj.id2);
|
|
put_cobj(&plci->cobj);
|
|
}
|
|
}
|
|
return lp;
|
|
}
|
|
|
|
#define CapiFacilityNotSupported 0x300b
|
|
|
|
static int FacilityMessage(struct mApplication *appl, struct pController *pc, struct mc_buf *mc)
|
|
{
|
|
int ret = CapiNoError;
|
|
struct mPLCI *plci;
|
|
struct lPLCI *lp;
|
|
struct BInstance *bi;
|
|
unsigned char tmp[64], *p;
|
|
|
|
p = tmp;
|
|
switch (mc->cmsg.FacilitySelector) {
|
|
#if 0
|
|
case 0x0000: // Handset
|
|
#endif
|
|
case 0x0001: // DTMF
|
|
dprint(MIDEBUG_CONTROLLER, "DTMF addr %06x\n", mc->cmsg.adr.adrNCCI);
|
|
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
if (plci)
|
|
put_cobj(&plci->cobj);
|
|
bi = lp ? lp->BIlink : NULL;
|
|
if (bi) {
|
|
ret = bi->from_up(bi, mc);
|
|
} else {
|
|
wprint("DTMF addr %06x lPLCI not found\n", mc->cmsg.adr.adrNCCI);
|
|
ret = CapiIllController;
|
|
}
|
|
if (lp)
|
|
put_cobj(&lp->cobj);
|
|
break;
|
|
case 0x0003: // SupplementaryServices
|
|
// ret = SupplementaryFacilityReq(appl, mc);
|
|
capimsg_setu8(p, 0, 9);
|
|
capimsg_setu16(p, 1, 0);
|
|
capimsg_setu8(p, 3, 6);
|
|
capimsg_setu16(p, 4, 0);
|
|
capimsg_setu32(p, 6, 0);
|
|
mc->cmsg.FacilityConfirmationParameter = tmp;
|
|
SendCmsgAnswer2Application(appl, mc, ret);
|
|
free_mc_buf(mc);
|
|
ret = CapiNoError;
|
|
break;
|
|
default:
|
|
ret = CapiFacilityNotSupported;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int PutMessageApplication(struct mApplication *appl, struct mc_buf *mc)
|
|
{
|
|
unsigned int id;
|
|
struct pController *pc;
|
|
struct lController *lc;
|
|
struct mPLCI *plci = NULL;
|
|
struct lPLCI *lp = NULL;
|
|
struct BInstance *bi;
|
|
uint8_t cmd, subcmd;
|
|
int ret = CapiNoError;
|
|
|
|
cmd = CAPIMSG_COMMAND(mc->rb);
|
|
subcmd = CAPIMSG_SUBCOMMAND(mc->rb);
|
|
if (cmd != CAPI_DATA_B3 && mI_debug_mask & MIDEBUG_CAPIMSG)
|
|
mCapi_message2str(mc);
|
|
if (mc->len < 12) {
|
|
eprint("message %02x/%02x %s too short (%d)\n", cmd, subcmd, capi20_cmd2str(cmd, subcmd), mc->len);
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
SendCmsgAnswer2Application(appl, mc, ret);
|
|
return ret;
|
|
}
|
|
id = CAPIMSG_CONTROL(mc->rb);
|
|
lc = get_lController(appl, id & 0x7f);
|
|
if (lc)
|
|
pc = p4lController(lc);
|
|
else
|
|
pc = get_cController(id & 0x7f);
|
|
if (!pc) {
|
|
eprint("message %x controller for id %06x not found\n", cmd, id);
|
|
}
|
|
dprint(MIDEBUG_CONTROLLER, "%s: ID:%06x cmd %02x/%02x %s\n", CAPIobjIDstr(&appl->cobj),
|
|
id, cmd, subcmd, capi20_cmd2str(cmd, subcmd));
|
|
switch (cmd) {
|
|
// for NCCI state machine
|
|
case CAPI_DATA_B3:
|
|
case CAPI_CONNECT_B3_ACTIVE:
|
|
case CAPI_RESET_B3:
|
|
mcbuf_rb2cmsg(mc);
|
|
if ((subcmd == CAPI_REQ) || (subcmd == CAPI_RESP)) {
|
|
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
bi = lp ? lp->BIlink : NULL;
|
|
if (bi) {
|
|
ret = bi->from_up(bi, mc);
|
|
} else {
|
|
wprint("%s: cmd %x (%s) %s %s BIlink not found\n", CAPIobjIDstr(&appl->cobj), cmd,
|
|
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand),
|
|
plci ? CAPIobjIDstr(&plci->cobj) : "no plci",
|
|
lp ? CAPIobjIDstr(&lp->cobj) : "no lplci");
|
|
ret = CapiIllController;
|
|
}
|
|
} else
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
break;
|
|
case CAPI_DISCONNECT_B3:
|
|
mcbuf_rb2cmsg(mc);
|
|
if ((subcmd == CAPI_REQ) || (subcmd == CAPI_RESP)) {
|
|
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
bi = lp ? lp->BIlink : NULL;
|
|
if (bi) {
|
|
ret = bi->from_up(bi, mc);
|
|
} else if (subcmd == CAPI_RESP) {
|
|
dprint(MIDEBUG_CONTROLLER, "%s: cmd %x (%s) %s %s BIlink already gone - OK\n", CAPIobjIDstr(&appl->cobj), cmd,
|
|
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand),
|
|
plci ? CAPIobjIDstr(&plci->cobj) : "no plci",
|
|
lp ? CAPIobjIDstr(&lp->cobj) : "no lplci");
|
|
ret = 1; /* free msg in calling function main_recv() */
|
|
} else {
|
|
ret = CapiIllController;
|
|
}
|
|
} else
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
break;
|
|
case CAPI_CONNECT_B3:
|
|
mcbuf_rb2cmsg(mc);
|
|
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
bi = lp ? lp->BIlink : NULL;
|
|
if (bi) {
|
|
ret = bi->from_up(bi, mc);
|
|
} else {
|
|
wprint("%s: cmd %x (%s) %s %s BIlink not found\n", CAPIobjIDstr(&appl->cobj), cmd,
|
|
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand),
|
|
plci ? CAPIobjIDstr(&plci->cobj) : "no plci",
|
|
lp ? CAPIobjIDstr(&lp->cobj) : "no lplci");
|
|
ret = CapiIllController;
|
|
}
|
|
break;
|
|
// for PLCI state machine
|
|
case CAPI_CONNECT:
|
|
case CAPI_INFO:
|
|
mcbuf_rb2cmsg(mc);
|
|
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI);
|
|
dprint(MIDEBUG_PLCI, "%s adrPLCI %06x plci:%04x ApplId %d\n", capi20_cmd2str(cmd, subcmd), mc->cmsg.adr.adrPLCI,
|
|
plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId);
|
|
if (subcmd == CAPI_REQ) {
|
|
if (plci) {
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
if (lp)
|
|
ret = lPLCISendMessage(lp, mc);
|
|
else {
|
|
wprint("%s adrPLCI %06x plci:%04x ApplId %d no plci found\n", capi20_cmd2str(cmd, subcmd),
|
|
mc->cmsg.adr.adrPLCI, plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId);
|
|
ret = CapiIllController;
|
|
}
|
|
} else {
|
|
if (!lc) {
|
|
if (pc) {
|
|
lc = addlController(appl, pc, 1);
|
|
if (!lc) {
|
|
ret = CapiMsgOSResourceErr;
|
|
break;
|
|
}
|
|
} else {
|
|
ret = CapiIllController;
|
|
break;
|
|
}
|
|
}
|
|
ret = mPLCISendMessage(lc, mc);
|
|
}
|
|
} else if (subcmd == CAPI_RESP) {
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
if (lp)
|
|
ret = lPLCISendMessage(lp, mc);
|
|
else {
|
|
wprint("%s adrPLCI %06x plci:%04x ApplId %d no plci found\n", capi20_cmd2str(cmd, subcmd),
|
|
mc->cmsg.adr.adrPLCI, plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId);
|
|
ret = CapiIllController;
|
|
}
|
|
} else
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
break;
|
|
case CAPI_ALERT:
|
|
case CAPI_CONNECT_ACTIVE:
|
|
case CAPI_DISCONNECT:
|
|
case CAPI_SELECT_B_PROTOCOL:
|
|
mcbuf_rb2cmsg(mc);
|
|
if ((subcmd == CAPI_REQ) || (subcmd == CAPI_RESP)) {
|
|
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI);
|
|
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
|
|
dprint(MIDEBUG_PLCI, "adrPLCI %06x plci:%04x ApplId %d lp %p\n", mc->cmsg.adr.adrPLCI,
|
|
plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId, lp);
|
|
if (lp)
|
|
ret = lPLCISendMessage(lp, mc);
|
|
else
|
|
ret = CapiIllController;
|
|
} else
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
break;
|
|
case CAPI_LISTEN:
|
|
if (subcmd != CAPI_REQ) {
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
break;
|
|
}
|
|
mcbuf_rb2cmsg(mc);
|
|
if (!lc) {
|
|
if (pc) {
|
|
lc = addlController(appl, pc, 0);
|
|
if (!lc) {
|
|
ret = CapiMsgOSResourceErr;
|
|
break;
|
|
}
|
|
} else {
|
|
ret = CapiIllController;
|
|
break;
|
|
}
|
|
}
|
|
if (!ret)
|
|
ret = listenRequest(lc, mc);
|
|
break;
|
|
case CAPI_FACILITY:
|
|
mcbuf_rb2cmsg(mc);
|
|
ret = FacilityMessage(appl, pc, mc);
|
|
break;
|
|
default:
|
|
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
|
|
wprint("message %x (%s)for controller id %06x not supported yet\n", cmd, capi20_cmd2str(cmd, subcmd), id);
|
|
break;
|
|
}
|
|
if (ret && subcmd != CAPI_RESP)
|
|
SendCmsgAnswer2Application(appl, mc, ret);
|
|
if (lp)
|
|
put_cobj(&lp->cobj);
|
|
if (plci)
|
|
put_cobj(&plci->cobj);
|
|
if (lc)
|
|
put_cobj(&lc->cobj);
|
|
return ret;
|
|
}
|
|
|
|
void mCapi_cmsg2str(struct mc_buf *mc)
|
|
{
|
|
char *decmsg, *line;
|
|
|
|
if (mI_debug_mask & MIDEBUG_CAPIMSG) {
|
|
decmsg = capi_cmsg2str(&mc->cmsg);
|
|
while (decmsg) {
|
|
line = strsep(&decmsg, "\n");
|
|
if (line)
|
|
dprint(MIDEBUG_CAPIMSG, "%s\n", line);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mCapi_message2str(struct mc_buf *mc)
|
|
{
|
|
char *decmsg, *line;
|
|
|
|
if (mI_debug_mask & MIDEBUG_CAPIMSG) {
|
|
decmsg = capi_message2str(mc->rb);
|
|
while (decmsg) {
|
|
line = strsep(&decmsg, "\n");
|
|
if (line)
|
|
dprint(MIDEBUG_CAPIMSG, "%s\n", line);
|
|
}
|
|
}
|
|
}
|