/*****************************************************************************\ ** ** ** 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); }