|
|
|
@ -671,11 +671,15 @@ void isdn_destroy(isdn_t *isdn_ep)
|
|
|
|
|
|
|
|
|
|
timer_exit(&isdn_ep->l2establish_timer);
|
|
|
|
|
|
|
|
|
|
timer_exit(&isdn_ep->clock_timer);
|
|
|
|
|
|
|
|
|
|
free(isdn_ep);
|
|
|
|
|
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "ISDN instance destroyed\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void clock_timeout(void *data);
|
|
|
|
|
|
|
|
|
|
/* initialization and configuration to isdn interface instance */
|
|
|
|
|
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int local_tones, int serving_location)
|
|
|
|
|
{
|
|
|
|
@ -875,18 +879,19 @@ static void im_control(int sock, uint32_t op, uint32_t channel, uint32_t p1, uin
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send IMCTRLREQ to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int bchannel_kernel_sock_receive_cb(struct osmo_fd *ofd, unsigned int when);
|
|
|
|
|
|
|
|
|
|
/* create B-channel stack */
|
|
|
|
|
static int bchannel_create(isdn_t *isdn_ep, int index)
|
|
|
|
|
{
|
|
|
|
|
int channel = index + 1 + (index >= 15);
|
|
|
|
|
struct sockaddr_mISDN addr;
|
|
|
|
|
int flags;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->l2sock) {
|
|
|
|
|
if (isdn_ep->b_sock[index] > 0) {
|
|
|
|
|
if (isdn_ep->b_sock[index].ofd.fd > 0) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
@ -900,26 +905,31 @@ static int bchannel_create(isdn_t *isdn_ep, int index)
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
isdn_ep->b_sock[index] = rc;
|
|
|
|
|
isdn_ep->b_sock[index].ofd.fd = rc;
|
|
|
|
|
|
|
|
|
|
/* set nonblocking io */
|
|
|
|
|
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
|
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
|
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
|
|
|
|
|
/* register */
|
|
|
|
|
isdn_ep->b_sock[index].isdn_ep = isdn_ep;
|
|
|
|
|
isdn_ep->b_sock[index].index = index;
|
|
|
|
|
isdn_ep->b_sock[index].ofd.cb = bchannel_kernel_sock_receive_cb;
|
|
|
|
|
isdn_ep->b_sock[index].ofd.data = &isdn_ep->b_sock[index];
|
|
|
|
|
isdn_ep->b_sock[index].ofd.when = OSMO_FD_READ;
|
|
|
|
|
osmo_fd_register(&isdn_ep->b_sock[index].ofd);
|
|
|
|
|
|
|
|
|
|
/* bind socket to bchannel */
|
|
|
|
|
addr.family = AF_ISDN;
|
|
|
|
|
addr.dev = isdn_ep->portnum;
|
|
|
|
|
addr.channel = channel;
|
|
|
|
|
rc = bind(isdn_ep->b_sock[index], (struct sockaddr *)&addr, sizeof(addr));
|
|
|
|
|
rc = bind(isdn_ep->b_sock[index].ofd.fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
|
|
|
if (rc < 0) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
|
|
|
|
|
close(isdn_ep->b_sock[index]);
|
|
|
|
|
/* unregister and close */
|
|
|
|
|
osmo_fd_unregister(&isdn_ep->b_sock[index].ofd);
|
|
|
|
|
close(isdn_ep->b_sock[index].ofd.fd);
|
|
|
|
|
return -errno;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "created socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "created socket #%d for B-channel %d\n", isdn_ep->b_sock[index].ofd.fd, channel);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -932,14 +942,14 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->l2sock) {
|
|
|
|
|
if (isdn_ep->b_sock[index] <= 0)
|
|
|
|
|
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
|
|
|
|
|
act.id = 0;
|
|
|
|
|
rc = sendto(isdn_ep->b_sock[index], &act, MISDN_HEADER_LEN, 0, NULL, 0);
|
|
|
|
|
rc = sendto(isdn_ep->b_sock[index].ofd.fd, &act, MISDN_HEADER_LEN, 0, NULL, 0);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index], channel);
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index].ofd.fd, channel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->l2inst) {
|
|
|
|
@ -964,10 +974,10 @@ static void bchannel_configure(isdn_t *isdn_ep, int index)
|
|
|
|
|
call_t *call;
|
|
|
|
|
int handle;
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->b_sock[index] <= 0)
|
|
|
|
|
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
handle = isdn_ep->b_sock[index];
|
|
|
|
|
handle = isdn_ep->b_sock[index].ofd.fd;
|
|
|
|
|
call = isdn_ep->b_call[index];
|
|
|
|
|
|
|
|
|
|
/* set PCM bridge features */
|
|
|
|
@ -1007,13 +1017,15 @@ static void bchannel_destroy(isdn_t *isdn_ep, int index)
|
|
|
|
|
int channel = index + 1 + (index >= 15);
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->l2sock) {
|
|
|
|
|
if (isdn_ep->b_sock[index] <= 0)
|
|
|
|
|
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index].ofd.fd, channel);
|
|
|
|
|
|
|
|
|
|
close(isdn_ep->b_sock[index]);
|
|
|
|
|
isdn_ep->b_sock[index] = 0;
|
|
|
|
|
/* unregister and close */
|
|
|
|
|
osmo_fd_unregister(&isdn_ep->b_sock[index].ofd);
|
|
|
|
|
close(isdn_ep->b_sock[index].ofd.fd);
|
|
|
|
|
isdn_ep->b_sock[index].ofd.fd = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->l2inst) {
|
|
|
|
@ -1226,18 +1238,26 @@ static void bchannel_rx_tx(isdn_t *isdn_ep, int index, struct mISDNhead *hh, uns
|
|
|
|
|
static void bchannel_confirm(isdn_t *isdn_ep, int index);
|
|
|
|
|
|
|
|
|
|
/* handle frames from B-channel (kernel socket) */
|
|
|
|
|
static int bchannel_kernel_sock_receive(isdn_t *isdn_ep, int index)
|
|
|
|
|
static int bchannel_kernel_sock_receive_cb(struct osmo_fd *ofd, unsigned int when)
|
|
|
|
|
{
|
|
|
|
|
struct isdn_b_sock *b_sock = ofd->data;
|
|
|
|
|
int index = b_sock->index;
|
|
|
|
|
isdn_t *isdn_ep = b_sock->isdn_ep;
|
|
|
|
|
int channel = index + 1 + (index >= 15);
|
|
|
|
|
unsigned char buffer[2048+MISDN_HEADER_LEN];
|
|
|
|
|
struct mISDNhead *hh = (struct mISDNhead *)buffer;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
rc = recv(isdn_ep->b_sock[index], buffer, sizeof(buffer), 0);
|
|
|
|
|
if (!(when & OSMO_FD_READ)) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "this should never happen!\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = recv(ofd->fd, buffer, sizeof(buffer), 0);
|
|
|
|
|
if (rc < 0) {
|
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
|
return 0;
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "read error B-channel data (socket #%d errno=%d:%s)\n", isdn_ep->b_sock[index], errno, strerror(errno));
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "read error B-channel data (socket #%d errno=%d:%s)\n", ofd->fd, errno, strerror(errno));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rc < (int)MISDN_HEADER_LEN) {
|
|
|
|
@ -1318,9 +1338,9 @@ void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *da
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void b_timer_timeout(struct timer *timer)
|
|
|
|
|
static void b_timer_timeout(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct b_timer_inst *ti = timer->priv;
|
|
|
|
|
struct b_timer_inst *ti = data;
|
|
|
|
|
|
|
|
|
|
bchannel_event(ti->isdn_ep, ti->index, B_EVENT_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
@ -1618,9 +1638,9 @@ static void bchannel_rx_tx(isdn_t *isdn_ep, int index, struct mISDNhead *hh, uns
|
|
|
|
|
if (call->isdn_ep->ph_socket)
|
|
|
|
|
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, offset + len);
|
|
|
|
|
else
|
|
|
|
|
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + offset + len, 0);
|
|
|
|
|
rc = send(call->isdn_ep->b_sock[call->b_index].ofd.fd, buf, MISDN_HEADER_LEN + offset + len, 0);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index].ofd.fd, errno, strerror(errno));
|
|
|
|
|
else
|
|
|
|
|
call->b_transmitting = 1;
|
|
|
|
|
}
|
|
|
|
@ -1643,18 +1663,6 @@ static void bchannel_confirm(isdn_t *isdn_ep, int index)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void isdn_rtp_work(isdn_t *isdn_ep)
|
|
|
|
|
{
|
|
|
|
|
call_t *call;
|
|
|
|
|
|
|
|
|
|
call = isdn_ep->call_list;
|
|
|
|
|
while (call) {
|
|
|
|
|
if (call->cc_session)
|
|
|
|
|
osmo_cc_session_handle(call->cc_session, call);
|
|
|
|
|
call = call->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* send audio from RTP to B-channel's jitter buffer */
|
|
|
|
|
void rtp_receive(struct osmo_cc_session_codec *codec, uint8_t __attribute__((unused)) marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)
|
|
|
|
|
{
|
|
|
|
@ -1716,6 +1724,10 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
|
|
|
|
|
mqueue_tail(&isdn_ep->upqueue, mb);
|
|
|
|
|
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
|
|
|
|
|
|
|
|
|
/* wake main thread */
|
|
|
|
|
char wakeup = 0;
|
|
|
|
|
write(isdn_ep->upqueue_pipe[1], &wakeup, 1);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1745,7 +1757,8 @@ int mISDN_getportbyname(isdn_t *isdn_ep, int cnt, const char *portname)
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void l2establish_timeout(struct timer *timer);
|
|
|
|
|
static void l2establish_timeout(void *data);
|
|
|
|
|
static int isdn_upqueue_cb(struct osmo_fd *ofd, unsigned int what);
|
|
|
|
|
|
|
|
|
|
/* open mISDN port */
|
|
|
|
|
int isdn_open(isdn_t *isdn_ep)
|
|
|
|
@ -1766,6 +1779,16 @@ int isdn_open(isdn_t *isdn_ep)
|
|
|
|
|
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
|
|
|
|
|
mqueue_init(&isdn_ep->upqueue);
|
|
|
|
|
isdn_ep->upqueue_initialized = 1;
|
|
|
|
|
rc = pipe(isdn_ep->upqueue_pipe);
|
|
|
|
|
if (rc < 0) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create pipe errno=%d:%s. (Please fix!)\n", errno, strerror(errno));
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
isdn_ep->upqueue_ofd.fd = isdn_ep->upqueue_pipe[0];
|
|
|
|
|
isdn_ep->upqueue_ofd.cb = isdn_upqueue_cb;
|
|
|
|
|
isdn_ep->upqueue_ofd.data = isdn_ep;
|
|
|
|
|
isdn_ep->upqueue_ofd.when = OSMO_FD_READ;
|
|
|
|
|
osmo_fd_register(&isdn_ep->upqueue_ofd);
|
|
|
|
|
|
|
|
|
|
/* port number given ? */
|
|
|
|
|
for (i = 0; i < (int)strlen(portname); i++){
|
|
|
|
@ -1878,6 +1901,8 @@ int isdn_open(isdn_t *isdn_ep)
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer_init(&isdn_ep->clock_timer, clock_timeout, isdn_ep);
|
|
|
|
|
|
|
|
|
|
timer_init(&isdn_ep->l2establish_timer, l2establish_timeout, isdn_ep);
|
|
|
|
|
|
|
|
|
|
isdn_ep->l1link = -1;
|
|
|
|
@ -1975,7 +2000,7 @@ void isdn_close(isdn_t *isdn_ep)
|
|
|
|
|
|
|
|
|
|
/* free bchannels */
|
|
|
|
|
for (i = 0; i < isdn_ep->b_num; i++) {
|
|
|
|
|
if (isdn_ep->b_sock[i] > 0) {
|
|
|
|
|
if (isdn_ep->b_sock[i].ofd.fd > 0) {
|
|
|
|
|
bchannel_destroy(isdn_ep, i);
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "freeing %s port %s bchannel (index %d).\n", (isdn_ep->ntmode) ? "NT" : "TE", isdn_ep->portname, i);
|
|
|
|
|
}
|
|
|
|
@ -1988,9 +2013,18 @@ void isdn_close(isdn_t *isdn_ep)
|
|
|
|
|
close_layer3(isdn_ep->ml3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* purge upqueue */
|
|
|
|
|
/* purge and remove upqueue */
|
|
|
|
|
if (isdn_ep->upqueue_initialized)
|
|
|
|
|
mqueue_purge(&isdn_ep->upqueue);
|
|
|
|
|
if (isdn_ep->upqueue_pipe[0] > 0) {
|
|
|
|
|
osmo_fd_unregister(&isdn_ep->upqueue_ofd);
|
|
|
|
|
close(isdn_ep->upqueue_pipe[0]);
|
|
|
|
|
isdn_ep->upqueue_pipe[0] = 0;
|
|
|
|
|
}
|
|
|
|
|
if (isdn_ep->upqueue_pipe[1] > 0) {
|
|
|
|
|
close(isdn_ep->upqueue_pipe[1]);
|
|
|
|
|
isdn_ep->upqueue_pipe[1] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->portname) {
|
|
|
|
|
free(isdn_ep->portname);
|
|
|
|
@ -2009,116 +2043,120 @@ void isdn_close(isdn_t *isdn_ep)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* receive message from ISDN protocol stack (out of queue) */
|
|
|
|
|
int isdn_dchannel_work(isdn_t *isdn_ep)
|
|
|
|
|
/* receive message from ISDN protocol stack (out of the upqueue) */
|
|
|
|
|
static int isdn_upqueue_cb(struct osmo_fd *ofd, unsigned __attribute__((unused)) int what)
|
|
|
|
|
{
|
|
|
|
|
isdn_t *isdn_ep = ofd->data;
|
|
|
|
|
struct mbuffer *mb;
|
|
|
|
|
struct l3_msg *l3m;
|
|
|
|
|
int w = 0;
|
|
|
|
|
|
|
|
|
|
char wakeup = 0;
|
|
|
|
|
read(ofd->fd, &wakeup, 1);
|
|
|
|
|
|
|
|
|
|
again:
|
|
|
|
|
/* handle queued up-messages (d-channel) */
|
|
|
|
|
pthread_mutex_lock(&isdn_ep->upqueue_lock);
|
|
|
|
|
mb = mdequeue(&isdn_ep->upqueue);
|
|
|
|
|
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
|
|
|
|
if (mb) {
|
|
|
|
|
w |= 1;
|
|
|
|
|
l3m = &mb->l3;
|
|
|
|
|
switch(l3m->type) {
|
|
|
|
|
case MPH_ACTIVATE_IND:
|
|
|
|
|
if (isdn_ep->l1link != 1) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes active\n");
|
|
|
|
|
isdn_ep->l1link = 1;
|
|
|
|
|
}
|
|
|
|
|
if (!mb)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
l3m = &mb->l3;
|
|
|
|
|
switch(l3m->type) {
|
|
|
|
|
case MPH_ACTIVATE_IND:
|
|
|
|
|
if (isdn_ep->l1link != 1) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes active\n");
|
|
|
|
|
isdn_ep->l1link = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MPH_DEACTIVATE_IND:
|
|
|
|
|
if (isdn_ep->l1link != 0) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes inactive\n");
|
|
|
|
|
isdn_ep->l1link = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MPH_INFORMATION_IND:
|
|
|
|
|
switch (l3m->pid) {
|
|
|
|
|
case L1_SIGNAL_LOS_ON:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received LOS\n");
|
|
|
|
|
isdn_ep->los = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MPH_DEACTIVATE_IND:
|
|
|
|
|
if (isdn_ep->l1link != 0) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes inactive\n");
|
|
|
|
|
isdn_ep->l1link = 0;
|
|
|
|
|
}
|
|
|
|
|
case L1_SIGNAL_LOS_OFF:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "LOS is gone\n");
|
|
|
|
|
isdn_ep->los = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MPH_INFORMATION_IND:
|
|
|
|
|
switch (l3m->pid) {
|
|
|
|
|
case L1_SIGNAL_LOS_ON:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received LOS\n");
|
|
|
|
|
isdn_ep->los = 1;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_LOS_OFF:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "LOS is gone\n");
|
|
|
|
|
isdn_ep->los = 0;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_AIS_ON:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received AIS\n");
|
|
|
|
|
isdn_ep->ais = 1;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_AIS_OFF:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "AIS is gone\n");
|
|
|
|
|
isdn_ep->ais = 0;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_RDI_ON:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received RDI\n");
|
|
|
|
|
isdn_ep->rdi = 1;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_RDI_OFF:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "RDI is gone\n");
|
|
|
|
|
isdn_ep->rdi = 0;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_SLIP_TX:
|
|
|
|
|
isdn_ep->slip_tx++;
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received TX slip #%d\n", isdn_ep->slip_tx);
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_SLIP_RX:
|
|
|
|
|
isdn_ep->slip_rx++;
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received RX slip #%d\n", isdn_ep->slip_rx);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case L1_SIGNAL_AIS_ON:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received AIS\n");
|
|
|
|
|
isdn_ep->ais = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MT_L2ESTABLISH:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes active (tei = %d)\n", l3m->pid);
|
|
|
|
|
isdn_ep->l2link = 1;
|
|
|
|
|
if (l3m->pid < 128)
|
|
|
|
|
isdn_ep->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
|
|
|
|
|
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
|
|
|
|
if (timer_running(&isdn_ep->l2establish_timer))
|
|
|
|
|
timer_stop(&isdn_ep->l2establish_timer);
|
|
|
|
|
}
|
|
|
|
|
case L1_SIGNAL_AIS_OFF:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "AIS is gone\n");
|
|
|
|
|
isdn_ep->ais = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MT_L2RELEASE:
|
|
|
|
|
if (l3m->pid < 128)
|
|
|
|
|
isdn_ep->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
|
|
|
|
|
if (!timer_running(&isdn_ep->l2establish_timer)) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes inactive (tei = %d)\n", l3m->pid);
|
|
|
|
|
/* down if not nt-ptmp */
|
|
|
|
|
if (!isdn_ep->ntmode || isdn_ep->ptp)
|
|
|
|
|
isdn_ep->l2link = 0;
|
|
|
|
|
}
|
|
|
|
|
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
|
|
|
|
if (!timer_running(&isdn_ep->l2establish_timer) && isdn_ep->l2hold) {
|
|
|
|
|
timer_start(&isdn_ep->l2establish_timer, 5.0); /* 5 seconds */
|
|
|
|
|
isdn_ep->ml3->to_layer3(isdn_ep->ml3, MT_L2ESTABLISH, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case L1_SIGNAL_RDI_ON:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received RDI\n");
|
|
|
|
|
isdn_ep->rdi = 1;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_RDI_OFF:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "RDI is gone\n");
|
|
|
|
|
isdn_ep->rdi = 0;
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_SLIP_TX:
|
|
|
|
|
isdn_ep->slip_tx++;
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received TX slip #%d\n", isdn_ep->slip_tx);
|
|
|
|
|
break;
|
|
|
|
|
case L1_SIGNAL_SLIP_RX:
|
|
|
|
|
isdn_ep->slip_rx++;
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "received RX slip #%d\n", isdn_ep->slip_rx);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* l3-data is sent to DSS1 handling */
|
|
|
|
|
dss1_receive(isdn_ep, l3m->type, l3m->pid, l3m);
|
|
|
|
|
case MT_L2ESTABLISH:
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes active (tei = %d)\n", l3m->pid);
|
|
|
|
|
isdn_ep->l2link = 1;
|
|
|
|
|
if (l3m->pid < 128)
|
|
|
|
|
isdn_ep->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
|
|
|
|
|
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
|
|
|
|
if (timer_running(&isdn_ep->l2establish_timer))
|
|
|
|
|
timer_stop(&isdn_ep->l2establish_timer);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MT_L2RELEASE:
|
|
|
|
|
if (l3m->pid < 128)
|
|
|
|
|
isdn_ep->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
|
|
|
|
|
if (!timer_running(&isdn_ep->l2establish_timer)) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes inactive (tei = %d)\n", l3m->pid);
|
|
|
|
|
/* down if not nt-ptmp */
|
|
|
|
|
if (!isdn_ep->ntmode || isdn_ep->ptp)
|
|
|
|
|
isdn_ep->l2link = 0;
|
|
|
|
|
}
|
|
|
|
|
/* free message */
|
|
|
|
|
free_l3_msg(l3m);
|
|
|
|
|
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
|
|
|
|
if (!timer_running(&isdn_ep->l2establish_timer) && isdn_ep->l2hold) {
|
|
|
|
|
timer_start(&isdn_ep->l2establish_timer, 5.0); /* 5 seconds */
|
|
|
|
|
isdn_ep->ml3->to_layer3(isdn_ep->ml3, MT_L2ESTABLISH, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* l3-data is sent to DSS1 handling */
|
|
|
|
|
dss1_receive(isdn_ep, l3m->type, l3m->pid, l3m);
|
|
|
|
|
}
|
|
|
|
|
/* free message */
|
|
|
|
|
free_l3_msg(l3m);
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* l2 establish timer fires */
|
|
|
|
|
static void l2establish_timeout(struct timer *timer)
|
|
|
|
|
static void l2establish_timeout(void *data)
|
|
|
|
|
{
|
|
|
|
|
isdn_t *isdn_ep = timer->priv;
|
|
|
|
|
isdn_t *isdn_ep = data;
|
|
|
|
|
|
|
|
|
|
if (isdn_ep->l2hold && (isdn_ep->ptp || !isdn_ep->ntmode)) {
|
|
|
|
|
PDEBUG(DISDN, DEBUG_DEBUG, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", isdn_ep->portnum);
|
|
|
|
@ -2127,25 +2165,20 @@ static void l2establish_timeout(struct timer *timer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void isdn_bchannel_work(isdn_t *isdn_ep)
|
|
|
|
|
{
|
|
|
|
|
int w, i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < isdn_ep->b_num; i++) {
|
|
|
|
|
do {
|
|
|
|
|
if (isdn_ep->b_sock[i] > 0)
|
|
|
|
|
w = bchannel_kernel_sock_receive(isdn_ep, i);
|
|
|
|
|
else
|
|
|
|
|
w = 0;
|
|
|
|
|
} while (w);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* local clock to generate hold tone
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define COMFORT_NOISE (0.02 * SPEECH_LEVEL) /* audio level of comfort noise (relative to ISDN level) */
|
|
|
|
|
#define CHUNK_DURATION 0.020
|
|
|
|
|
#define CHUNK_LENGTH 160
|
|
|
|
|
|
|
|
|
|
void hold_clock(isdn_t *isdn_ep, int len)
|
|
|
|
|
static void clock_timeout(void *data)
|
|
|
|
|
{
|
|
|
|
|
isdn_t *isdn_ep = data;
|
|
|
|
|
int len = CHUNK_LENGTH;
|
|
|
|
|
call_t *call;
|
|
|
|
|
int any = 0;
|
|
|
|
|
|
|
|
|
|
call = isdn_ep->call_list;
|
|
|
|
|
while (call) {
|
|
|
|
@ -2165,7 +2198,40 @@ void hold_clock(isdn_t *isdn_ep, int len)
|
|
|
|
|
g711_encode_ulaw_flipped((uint8_t *)noise, len * 2, &data, &len, NULL);
|
|
|
|
|
osmo_cc_rtp_send(call->codec, data, len, 0, 1, len, call);
|
|
|
|
|
free(data);
|
|
|
|
|
any = 1;
|
|
|
|
|
}
|
|
|
|
|
call = call->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* restart clock if there is still any call that requires it */
|
|
|
|
|
if (any) {
|
|
|
|
|
double now;
|
|
|
|
|
|
|
|
|
|
/* restart timer to wait for next 20ms */
|
|
|
|
|
now = get_time();
|
|
|
|
|
/* if there is too much jitter or if last_time_clock is not set */
|
|
|
|
|
if (now - isdn_ep->last_time_clock >= 0.1)
|
|
|
|
|
isdn_ep->last_time_clock = now;
|
|
|
|
|
/* advance clock */
|
|
|
|
|
isdn_ep->last_time_clock += CHUNK_DURATION;
|
|
|
|
|
/* if there is too much jitter */
|
|
|
|
|
if (isdn_ep->last_time_clock < now)
|
|
|
|
|
isdn_ep->last_time_clock = now;
|
|
|
|
|
timer_start(&isdn_ep->clock_timer, isdn_ep->last_time_clock - now);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void enable_hold_clock(isdn_t *isdn_ep)
|
|
|
|
|
{
|
|
|
|
|
double now;
|
|
|
|
|
|
|
|
|
|
/* already running, so keep running without restart */
|
|
|
|
|
if (timer_running(&isdn_ep->clock_timer))
|
|
|
|
|
return;
|
|
|
|
|
/* start timer to wait for 20ms */
|
|
|
|
|
now = get_time();
|
|
|
|
|
isdn_ep->last_time_clock = now + CHUNK_DURATION;
|
|
|
|
|
timer_start(&isdn_ep->clock_timer, CHUNK_DURATION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|