summaryrefslogtreecommitdiffstats
path: root/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'channel.c')
-rw-r--r--channel.c257
1 files changed, 257 insertions, 0 deletions
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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "main.h"
+#include <unistd.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+extern "C" {
+#include <net_l2.h>
+}
+
+#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);
+}
+