X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=channel.c;fp=channel.c;h=56d9e0d76c890b5cf613770ebef158541395c885;hp=0000000000000000000000000000000000000000;hb=701b046a45c2c79cc6d07ac3a4f84f499f7ed376;hpb=bf3c4d173ad6ecf845de2d9e6d11ab87769d0943 diff --git a/channel.c b/channel.c new file mode 100644 index 0000000..56d9e0d --- /dev/null +++ b/channel.c @@ -0,0 +1,257 @@ +/*****************************************************************************\ +** ** +** Linux Call Router ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** mISDN bchannel access (for Asterisk) ** +** ** +\*****************************************************************************/ + + +#include +#include +#include +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +} + +#if 0 +#ifndef ISDN_PID_L2_B_USER +#define ISDN_PID_L2_B_USER 0x420000ff +#endif +#ifndef ISDN_PID_L3_B_USER +#define ISDN_PID_L3_B_USER 0x430000ff +#endif +#endif +#ifndef ISDN_PID_L4_B_USER +#define ISDN_PID_L4_B_USER 0x440000ff +#endif + +/* used for udevice */ +int entity = 0; + +/* the device handler and port list */ +int mISDNdevice = -1; + + +/* open mISDN device */ +void mISDNdevice_open(void) +{ + /* open mISDNdevice if not already open */ + if (mISDNdevice < 0) + { + ret = mISDN_open(); + if (ret < 0) + { + PERROR("cannot open mISDN device ret=%d errno=%d (%s) Check for mISDN modules!\nAlso did you create \"/dev/mISDN\"? Do: \"mknod /dev/mISDN c 46 0\"\n", ret, errno, strerror(errno)); + return(NULL); + } + mISDNdevice = ret; + PDEBUG(DEBUG_ISDN, "mISDN device opened.\n"); + } +} + +/* close mISDN device */ +void mISDNdevice_close(void) +{ + if (mISDNdevice > -1) + { + mISDN_close(); + PDEBUG(DEBUG_ISDN, "mISDN device closed.\n"); + } +} + +/* create bchannel layer */ +unsigned long mISDN_createlayer(unsigned long stid) +{ + unsigned long addr; + + /* create new layer */ + PDEBUG(DEBUG_BCHANNEL, "creating new layer for bchannel stid=0%x.\n" , stid); + memset(&li, 0, sizeof(li)); + memset(&pid, 0, sizeof(pid)); + li.object_id = -1; + li.extentions = 0; + li.st = stid; + UCPY(li.name, "B L4"); + li.pid.layermask = ISDN_LAYER((4)); + li.pid.protocol[4] = ISDN_PID_L4_B_USER; + ret = mISDN_new_layer(mISDNdevice, &li); + if (ret) + { + failed_new_layer: + PERROR("mISDN_new_layer() failed to add bchannel stid=0%x.\n", stid); + goto failed; + } + addr = li.id; + if (!li.id) + { + goto failed_new_layer; + } + PDEBUG(DEBUG_BCHANNEL, "new layer (addr=0x%x)\n", addr); + + /* create new stack */ + pid.protocol[1] = ISDN_PID_L1_B_64TRANS; + pid.protocol[2] = ISDN_PID_L2_B_TRANS; + pid.protocol[3] = ISDN_PID_L3_B_DSP; + pid.protocol[4] = ISDN_PID_L4_B_USER; + pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4)); + ret = mISDN_set_stack(mISDNdevice, stid, &pid); + if (ret) + { + stack_error: + PERROR("mISDN_set_stack() failed (ret=%d) to add bchannel stid=0x%x\n", ret, stid); + mISDN_write_frame(mISDNdevice, buff, addr, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + goto failed; + } + ret = mISDN_get_setstack_ind(mISDNdevice, addr); + if (ret) + goto stack_error; + + /* get layer id */ + addr = mISDN_get_layerid(mISDNdevice, stid, 4); + if (!addr) + goto stack_error; +} + +/* destroy bchannel layer */ +void mISDN_destroylayer(unsigned long stid, unsigned long addr) +{ + /* remove our stack only if set */ + if (addr) + { + PDEBUG(DEBUG_BCHANNEL, "free stack (addr=0x%x)\n", addr); + mISDN_clear_stack(mISDNdevice, stid); + mISDN_write_frame(mISDNdevice, buff, addr | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + } +} + +/* do activation and deactivation of bchannel */ +static void mISDN_bchannelactivate(unsigned long addr, int activate) +{ + iframe_t act; + + /* activate bchannel */ + act.prim = (activate?DL_ESTABLISH:DL_RELEASE) | REQUEST; + act.addr = addr | FLG_MSG_DOWN; + act.dinfo = 0; + act.len = 0; + mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); +} + +/* handle all mISDN messages */ +int mISDN_handler(void) +{ + int ret; + msg_t *msg; + iframe_t *frm; + struct mISDNport *mISDNport; + class PmISDN *isdnport; + net_stack_t *nst; + msg_t *dmsg; + mISDNuser_head_t *hh; + int i; + + /* no device, no read */ + if (mISDNdevice < 0) + return(0); + + /* get message from kernel */ + if (!(msg = alloc_msg(MAX_MSG_SIZE))) + return(1); + ret = mISDN_read(mISDNdevice, msg->data, MAX_MSG_SIZE, 0); + if (ret < 0) + { + free_msg(msg); + if (errno == EAGAIN) + return(0); + FATAL("Failed to do mISDN_read()\n"); + } + if (!ret) + { + free_msg(msg); +// printf("%s: ERROR: mISDN_read() returns nothing\n"); + return(0); + } + msg->len = ret; + frm = (iframe_t *)msg->data; + + /* global prim */ + switch(frm->prim) + { + case MGR_DELLAYER | CONFIRM: + case MGR_INITTIMER | CONFIRM: + case MGR_ADDTIMER | CONFIRM: + case MGR_DELTIMER | CONFIRM: + case MGR_REMOVETIMER | CONFIRM: + free_msg(msg); + return(1); + } + + /* look for channel instance, that has the address of this message */ + chan = chan_first; + while(chan) + { + if (frm->addr == chan->b_addr) + break; + chan = chan->next; + } + if (!chan) + { + PERROR("message belongs to no chan: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len); + goto out; + } + + /* b-message */ + switch(frm->prim) + { + /* we don't care about confirms, we use rx data to sync tx */ + case PH_DATA | CONFIRM: + case DL_DATA | CONFIRM: + break; + + /* we receive audio data, we respond to it AND we send tones */ + case PH_DATA | INDICATION: + case DL_DATA | INDICATION: + case PH_CONTROL | INDICATION: + i = 0; + chan->bchannel_receive(frm); + break; + + case PH_ACTIVATE | INDICATION: + case DL_ESTABLISH | INDICATION: + case PH_ACTIVATE | CONFIRM: + case DL_ESTABLISH | CONFIRM: + PDEBUG(DEBUG_BCHANNEL, "DL_ESTABLISH confirm: bchannel is now activated (address 0x%x).\n", frm->addr); + chan->b_active = 1; + bchannel_event(mISDNport, i, B_EVENT_ACTIVATED); + break; + + case PH_DEACTIVATE | INDICATION: + case DL_RELEASE | INDICATION: + case PH_DEACTIVATE | CONFIRM: + case DL_RELEASE | CONFIRM: + PDEBUG(DEBUG_BCHANNEL, "DL_RELEASE confirm: bchannel is now de-activated (address 0x%x).\n", frm->addr); + chan->b_active = 0; + bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED); + break; + + default: + PERROR("child message not handled: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len); + } + + out: + free_msg(msg); + return(1); +} +