2020-01-25 07:50:20 +00:00
/* layer 1/2 handling
*
* ( C ) 2020 by Andreas Eversberg < jolly @ eversberg . eu >
* All Rights Reserved
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2022-08-19 14:27:41 +00:00
/* Transmit algorithm:
*
* Transmit data is taken from jitter buffer .
*
2023-03-04 17:47:19 +00:00
* When data is received from b - channel the first time , two chunks of data are transmitted to ISDN interface .
2022-08-19 14:27:41 +00:00
*
* When more data is received from b - channel , this extra chunk is transmitted to ISDN interface .
*
* This way the FIFO is kept with data all the time , to prevent underrund in hope that this application does not stall .
*
* The function that receives data and transmits data is bchannel_rx_tx ( ) .
*
* The jitter of received chunk is checked and debug is displayed accordingly .
*
*/
2020-01-25 07:50:20 +00:00
# include <stdio.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <stdint.h>
# include <stdlib.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <stddef.h>
# include <mISDN/mbuffer.h>
2024-01-09 11:24:14 +00:00
# include "../liblogging/logging.h"
# include <osmocom/core/select.h>
# include <osmocom/cc/session.h>
# include <osmocom/cc/rtp.h>
# include <osmocom/cc/g711.h>
2020-01-25 07:50:20 +00:00
# include "isdn.h"
# include "dss1.h"
# include "ie.h"
2022-06-24 17:58:41 +00:00
# include "bridge.h"
2020-01-25 07:50:20 +00:00
# ifndef u_char
# define u_char unsigned char
# endif
# include <mISDN/mlayer3.h>
# include <mISDN/q931.h>
2022-03-27 14:30:19 +00:00
# include "../libmisdn/socket.h"
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
static double get_time ( void )
{
static struct timespec tv ;
clock_gettime ( CLOCK_REALTIME , & tv ) ;
return ( double ) tv . tv_sec + ( double ) tv . tv_nsec / 1000000000.0 ;
}
2020-01-25 07:50:20 +00:00
# define B_TIMER_ACTIVATING 1 // seconds
# define B_TIMER_DEACTIVATING 1 // seconds
/*
* Channel selection
*/
/* set default out_channel */
static void default_out_channel ( isdn_t * isdn_ep )
{
struct select_channel * selchannel ;
2023-08-19 08:55:19 +00:00
if ( isdn_ep - > ntmode )
isdn_ep - > out_channel_exclusive = 1 ;
2020-01-25 07:50:20 +00:00
selchannel = calloc ( 1 , sizeof ( struct select_channel ) ) ;
if ( isdn_ep - > ntmode )
selchannel - > channel = CHANNEL_FREE ;
else
selchannel - > channel = CHANNEL_ANY ;
isdn_ep - > out_channel = selchannel ;
/* additional channel selection for multipoint NT ports */
if ( ! isdn_ep - > ptp & & isdn_ep - > ntmode ) {
selchannel - > next = calloc ( 1 , sizeof ( struct select_channel ) ) ;
selchannel = selchannel - > next ;
selchannel - > channel = CHANNEL_NO ; // call waiting
}
}
/* set default in_channel */
static void default_in_channel ( isdn_t * isdn_ep )
{
struct select_channel * selchannel ;
selchannel = calloc ( 1 , sizeof ( struct select_channel ) ) ;
selchannel - > channel = CHANNEL_FREE ;
isdn_ep - > in_channel = selchannel ;
}
/* parse string for a positive number */
static int get_number ( char * value )
{
int val = 0 ;
char text [ 10 ] ;
val = atoi ( value ) ;
sprintf ( text , " %d " , val ) ;
if ( ! strcmp ( value , text ) )
return val ;
return - 1 ;
}
/* remove element from buffer
* and return pointer to next element in buffer */
2021-01-01 21:13:47 +00:00
static char * get_separated ( char * buffer )
2020-01-25 07:50:20 +00:00
{
while ( * buffer ) {
2021-01-01 21:13:47 +00:00
if ( * buffer = = ' , ' | | * buffer < = 32 ) { /* separate */
2020-01-25 07:50:20 +00:00
* buffer + + = ' \0 ' ;
while ( ( * buffer > ' \0 ' & & * buffer < = 32 ) | | * buffer = = ' , ' )
buffer + + ;
return ( buffer ) ;
}
buffer + + ;
}
return ( buffer ) ;
}
/* parse outgoing channel list */
static int parse_out_channel ( isdn_t * isdn_ep , const char * _list )
{
char list [ strlen ( _list ) + 1 ] ;
struct select_channel * selchannel , * * selchannel_p = & isdn_ep - > out_channel ;
int val ;
char * p , * el ;
strcpy ( list , _list ) ;
p = list ;
while ( * p ) {
el = p ;
2021-01-01 21:13:47 +00:00
p = get_separated ( p ) ;
2020-01-25 07:50:20 +00:00
if ( ! strcasecmp ( el , " force " ) ) {
isdn_ep - > out_channel_exclusive = 1 ;
if ( isdn_ep - > out_channel ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Error outgoing channel string: value 'force' may only appear as first element in list. \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 1 ) ;
}
} else
if ( ! strcasecmp ( el , " any " ) ) {
val = CHANNEL_ANY ;
goto selchannel ;
} else
if ( ! strcasecmp ( el , " free " ) ) {
val = CHANNEL_FREE ;
goto selchannel ;
} else
if ( ! strcasecmp ( el , " no " ) ) {
val = CHANNEL_NO ;
goto selchannel ;
} else {
val = get_number ( el ) ;
if ( val = = - 1 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Error outgoing channel string: expecting a comma separated list of 'force', 'any', 'free', 'no' and any channel number. \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 1 ) ;
}
if ( val < 1 | | val = = 16 | | val > 126 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Error outgoing channel string: channel '%d' out of range. \n " , val ) ;
2020-01-25 07:50:20 +00:00
return ( - 1 ) ;
}
selchannel :
/* add to select-channel list */
selchannel = calloc ( 1 , sizeof ( struct select_channel ) ) ;
/* set value */
selchannel - > channel = val ;
/* tail port */
* selchannel_p = selchannel ;
selchannel_p = & ( ( * selchannel_p ) - > next ) ;
}
}
return ( 0 ) ;
}
/* parse incoming channel list */
static int parse_in_channel ( isdn_t * isdn_ep , const char * _list )
{
char list [ strlen ( _list ) + 1 ] ;
struct select_channel * selchannel , * * selchannel_p = & isdn_ep - > in_channel ;
int val ;
char * p , * el ;
strcpy ( list , _list ) ;
p = list ;
while ( * p ) {
el = p ;
2021-01-01 21:13:47 +00:00
p = get_separated ( p ) ;
2020-01-25 07:50:20 +00:00
if ( isdn_ep - > in_channel ) if ( isdn_ep - > in_channel - > channel = = CHANNEL_FREE ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Error incoming channel list: values behind 'free' keyword have no effect. \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 1 ) ;
}
if ( ! strcasecmp ( el , " free " ) ) {
val = CHANNEL_FREE ;
goto selchannel ;
} else {
val = get_number ( el ) ;
if ( val = = - 1 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Error incoming channel list: expectng a comma separated list of channel numbers and 'free'. \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 1 ) ;
}
if ( val < 1 | | val = = 16 | | val > 126 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Error incoming channel list: channel '%d' out of range. \n " , val ) ;
2020-01-25 07:50:20 +00:00
return ( - 1 ) ;
}
selchannel :
/* add to select-channel list */
selchannel = calloc ( 1 , sizeof ( struct select_channel ) ) ;
/* set value */
selchannel - > channel = val ;
/* tail port */
* selchannel_p = selchannel ;
selchannel_p = & ( ( * selchannel_p ) - > next ) ;
}
}
return ( 0 ) ;
}
/* hunt bchannel for incoming setup */
int hunt_bchannel_in ( isdn_t * isdn_ep , int channel , int exclusive )
{
struct select_channel * selchannel ;
int i ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (incoming call) \n " ) ;
2020-01-25 07:50:20 +00:00
if ( exclusive < 0 )
exclusive = 0 ;
if ( channel = = CHANNEL_NO )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = no-channel \n " ) ;
2020-01-25 07:50:20 +00:00
else if ( channel > 0 )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = channel %d%s \n " , channel , exclusive ? " (forced) " : " " ) ;
2020-01-25 07:50:20 +00:00
else
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = any channel \n " ) ;
2020-01-25 07:50:20 +00:00
if ( channel = = CHANNEL_NO & & ! isdn_ep - > ntmode ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = incoming call-waiting not supported for TE-mode \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 6 ) ; // channel unacceptable
}
if ( channel < = 0 ) /* not given, no channel, whatever.. */
channel = CHANNEL_ANY ; /* any channel */
if ( isdn_ep - > b_reserved > = isdn_ep - > b_num ) { // of out chan..
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = all channels are reserved \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 34 ) ; // no channel
}
if ( channel = = CHANNEL_ANY )
goto get_from_list ;
if ( channel > 0 ) {
/* check for given channel in selection list */
selchannel = isdn_ep - > in_channel ;
while ( selchannel ) {
if ( selchannel - > channel = = channel | | selchannel - > channel = = CHANNEL_FREE )
break ;
selchannel = selchannel - > next ;
}
if ( ! selchannel )
channel = 0 ;
/* exclusive channel requests must be in the list */
if ( exclusive ) {
/* no exclusive channel */
if ( ! channel ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = exclusively requested channel not in list \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 6 ) ; // channel unacceptable
}
/* get index for channel */
i = channel - 1 - ( channel > = 17 ) ;
if ( i < 0 | | i > = isdn_ep - > b_num | | channel = = 16 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = exclusively requested channel outside interface range \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 6 ) ; // channel unacceptable
}
/* check if busy */
if ( isdn_ep - > b_call [ i ] = = NULL )
goto use_channel ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = exclusively requested channel is busy \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 6 ) ; // channel unacceptable
}
/* requested channels in list will be used */
if ( channel ) {
/* get index for channel */
i = channel - 1 - ( channel > = 17 ) ;
if ( i < 0 | | i > = isdn_ep - > b_num | | channel = = 16 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> quested channel %d outside interface range \n " , channel ) ;
2020-01-25 07:50:20 +00:00
} else /* if inside range (else) check if available */
if ( isdn_ep - > b_call [ i ] = = NULL )
goto use_channel ;
}
/* if channel is not available or not in list, it must be searched */
get_from_list :
/* check for first free channel in list */
channel = 0 ;
selchannel = isdn_ep - > in_channel ;
while ( selchannel ) {
switch ( selchannel - > channel ) {
case CHANNEL_FREE : /* free channel */
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> hunting free channel \n " ) ;
2020-01-25 07:50:20 +00:00
if ( isdn_ep - > b_reserved > = isdn_ep - > b_num )
2021-01-01 21:13:47 +00:00
break ; /* all channel in use or reserved */
2020-01-25 07:50:20 +00:00
/* find channel */
i = 0 ;
while ( i < isdn_ep - > b_num ) {
if ( isdn_ep - > b_call [ i ] = = NULL ) {
channel = i + 1 + ( i > = 15 ) ;
break ;
}
i + + ;
}
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> hunting channel %d \n " , selchannel - > channel ) ;
2020-01-25 07:50:20 +00:00
if ( selchannel - > channel < 1 | | selchannel - > channel = = 16 )
break ; /* invalid channels */
i = selchannel - > channel - 1 - ( selchannel - > channel > = 17 ) ;
if ( i > = isdn_ep - > b_num )
break ; /* channel not in port */
if ( isdn_ep - > b_call [ i ] = = NULL ) {
channel = selchannel - > channel ;
break ;
}
break ;
}
if ( channel )
break ; /* found channel */
selchannel = selchannel - > next ;
}
if ( ! channel ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = no channel available \n " ) ;
2020-01-25 07:50:20 +00:00
return ( - 6 ) ; // channel unacceptable
}
}
use_channel :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = channel available \n " ) ;
LOGP ( DISDN , LOGL_DEBUG , " -> connect to channel %d \n " , channel ) ;
2020-01-25 07:50:20 +00:00
return ( channel ) ;
}
/* hunt bchannel for outgoing setup */
int hunt_bchannel_out ( isdn_t * isdn_ep , int * channel , int * exclusive )
{
struct select_channel * selchannel ;
int i ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (outgoing call) \n " ) ;
2020-01-25 07:50:20 +00:00
/* see if link is up on PTP*/
if ( isdn_ep - > l2hold & & isdn_ep - > l2link < 1 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = layer 2 is down \n " ) ;
2020-01-25 07:50:20 +00:00
return - 27 ;
}
/* check for channel form selection list */
* exclusive = isdn_ep - > out_channel_exclusive ;
* channel = 0 ;
selchannel = isdn_ep - > out_channel ;
while ( selchannel ) {
switch ( selchannel - > channel ) {
case CHANNEL_FREE : /* free channel */
if ( isdn_ep - > b_reserved > = isdn_ep - > b_num )
2021-01-01 21:13:47 +00:00
break ; /* all channel in use or reserved */
2020-01-25 07:50:20 +00:00
/* find channel */
i = 0 ;
while ( i < isdn_ep - > b_num ) {
if ( isdn_ep - > b_call [ i ] = = NULL ) {
* channel = i + 1 + ( i > = 15 ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = free channel %d \n " , * channel ) ;
2020-01-25 07:50:20 +00:00
break ;
}
i + + ;
}
if ( * channel )
break ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> no free channel found \n " ) ;
2020-01-25 07:50:20 +00:00
break ;
case CHANNEL_ANY : /* don't ask for channel */
if ( isdn_ep - > b_reserved > = isdn_ep - > b_num ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> cannot ask for any channel, because all channel are reserved \n " ) ;
2021-01-01 21:13:47 +00:00
break ; /* all channel in use or reserved */
2020-01-25 07:50:20 +00:00
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = any channel \n " ) ;
2020-01-25 07:50:20 +00:00
* channel = CHANNEL_ANY ;
break ;
case CHANNEL_NO : /* call waiting */
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = no channel \n " ) ;
2020-01-25 07:50:20 +00:00
* channel = CHANNEL_NO ;
break ;
default :
if ( selchannel - > channel < 1 | | selchannel - > channel = = 16 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> channel %d is out of range \n " , selchannel - > channel ) ;
2020-01-25 07:50:20 +00:00
break ; /* invalid channels */
}
i = selchannel - > channel - 1 - ( selchannel - > channel > = 17 ) ;
if ( i > = isdn_ep - > b_num ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> channel %d is out of range \n " , selchannel - > channel ) ;
2020-01-25 07:50:20 +00:00
break ; /* channel not in port */
}
if ( isdn_ep - > b_call [ i ] = = NULL ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = channel %d \n " , selchannel - > channel ) ;
2020-01-25 07:50:20 +00:00
* channel = selchannel - > channel ;
break ;
}
break ;
}
if ( * channel )
break ; /* found channel */
selchannel = selchannel - > next ;
}
if ( * channel )
return 0 ;
/* if channel was found, return channel */
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = no channel found \n " ) ;
2020-01-25 07:50:20 +00:00
return - 34 ;
}
/* open channel of incoming setup */
int open_bchannel_in ( call_t * call , int channel , int exclusive )
{
int rc ;
rc = seize_bchannel ( call , channel , exclusive ) ;
if ( rc < 0 )
return rc ;
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
return 0 ;
}
/* open channel of outgoing setup */
int open_bchannel_out ( call_t * call , unsigned int cmd , int channel , int exclusive )
{
int rc ;
/* correct exclusive to 0, if no explicit channel was given */
if ( exclusive < 0 | | channel < = 0 )
exclusive = 0 ;
/* select scenario */
if ( call - > b_channel & & call - > b_exclusive ) {
/*** we gave an exclusive channel (or if we are done) ***/
/* if not first reply, we are done */
if ( call - > state ! = ISDN_STATE_OUT_SETUP )
return ( 0 ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (reply from outgoing call) \n " ) ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = %d (forced) \n " , call - > b_channel ) ;
LOGP ( DISDN , LOGL_DEBUG , ( channel > = 0 ) ? " -> reply = %d \n " : " -> reply = (none) \n " , channel ) ;
2020-01-25 07:50:20 +00:00
/* if give channel not accepted or not equal */
if ( channel ! = - 1 & & call - > b_channel ! = channel ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = forced channel not accepted \n " ) ;
2020-01-25 07:50:20 +00:00
return - 44 ;
}
rc = seize_bchannel ( call , channel , 1 ) ; // exclusively
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " result = requested channel not available anymore \n " ) ;
2020-01-25 07:50:20 +00:00
return - 47 ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = channel was accepted \n " ) ;
2020-01-25 07:50:20 +00:00
/* activate our exclusive channel */
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
} else
if ( call - > b_channel ) {
/*** we gave a non-exclusive channel ***/
/* if not first reply, we are done */
if ( call - > state ! = ISDN_STATE_OUT_SETUP )
return ( 0 ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (reply from outgoing call) \n " ) ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = %d (suggest) \n " , call - > b_channel ) ;
LOGP ( DISDN , LOGL_DEBUG , ( channel > = 0 ) ? " -> reply = %d \n " : " -> reply = (none) \n " , channel ) ;
2020-01-25 07:50:20 +00:00
/* if channel was accepted as given */
if ( channel = = - 1 | | call - > b_channel = = channel ) {
call - > b_exclusive = 1 ; // we are done
2022-05-01 08:10:35 +00:00
/* if channel was accepted, seize_bchannel shall simply return, because given channel is already set */
rc = seize_bchannel ( call , call - > b_channel , 1 ) ; // exclusively
2020-01-25 07:50:20 +00:00
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel not available \n " ) ;
2020-01-25 07:50:20 +00:00
return - 47 ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = channel was accepted as given \n " ) ;
2020-01-25 07:50:20 +00:00
/* activate channel accepted by remote */
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
return ( 0 ) ;
}
/* if channel value is faulty */
if ( channel < = 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = illegal reply \n " ) ;
2020-01-25 07:50:20 +00:00
return - 111 ; // protocol error
}
2022-05-01 08:10:35 +00:00
/* if channel was not accepted, try to get a different one */
2020-01-25 07:50:20 +00:00
rc = seize_bchannel ( call , channel , 1 ) ; // exclusively
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel not available \n " ) ;
2020-01-25 07:50:20 +00:00
return - 47 ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel accepted \n " ) ;
2020-01-25 07:50:20 +00:00
/* activate channel given by remote */
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
} else
if ( call - > b_reserve ) {
/*** we sent 'any channel acceptable' ***/
/* if not first reply, we are done */
if ( call - > state ! = ISDN_STATE_OUT_SETUP )
return ( 0 ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (reply from outgoing call) \n " ) ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = any \n " ) ;
LOGP ( DISDN , LOGL_DEBUG , ( channel > = 0 ) ? " -> reply = %d \n " : " -> reply = (none) \n " , channel ) ;
2020-01-25 07:50:20 +00:00
/* if no channel was replied */
if ( channel < = 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = no channel, protocol error \n " ) ;
2020-01-25 07:50:20 +00:00
return - 111 ; // protocol error
}
/* we will see, if our received channel is available */
rc = seize_bchannel ( call , channel , 1 ) ; // exclusively
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel not available \n " ) ;
2020-01-25 07:50:20 +00:00
return - 47 ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel accepted \n " ) ;
2020-01-25 07:50:20 +00:00
/* activate channel given by remote */
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
} else {
/*** we sent 'no channel available' ***/
/* if not the first reply, but a connect, we are forced */
if ( cmd = = MT_CONNECT & & call - > state ! = ISDN_STATE_OUT_SETUP ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (connect reply from outgoing call) \n " ) ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = no channel \n " ) ;
LOGP ( DISDN , LOGL_DEBUG , ( channel > = 0 ) ? " -> reply %d%s \n " : " -> reply (none) \n " , channel , exclusive ? " (forced) " : " " ) ;
2020-01-25 07:50:20 +00:00
if ( channel > 0 ) {
goto use_from_connect ;
}
rc = seize_bchannel ( call , CHANNEL_ANY , 0 ) ; // any channel
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = no channel available during call-waiting \n " ) ;
2020-01-25 07:50:20 +00:00
return - 34 ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = using channel %d \n " , call - > b_channel ) ;
2020-01-25 07:50:20 +00:00
call - > b_exclusive = 1 ; // we are done
/* activate channel given by remote */
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
return ( 0 ) ;
}
/* if not first reply, we are done */
if ( call - > state ! = ISDN_STATE_OUT_SETUP )
return ( 0 ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Channel Selection (reply from outgoing call) \n " ) ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> request = no channel \n " ) ;
LOGP ( DISDN , LOGL_DEBUG , ( channel > = 0 ) ? " -> reply = %d \n " : " -> reply = (none) \n " , channel ) ;
2020-01-25 07:50:20 +00:00
/* if first reply has no channel, we are done */
if ( channel < = 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = no channel until connect \n " ) ;
2020-01-25 07:50:20 +00:00
return ( 0 ) ;
}
/* we will see, if our received channel is available */
use_from_connect :
rc = seize_bchannel ( call , channel , exclusive ) ;
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel not available \n " ) ;
2020-01-25 07:50:20 +00:00
return - 47 ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " -> result = replied channel accepted \n " ) ;
2020-01-25 07:50:20 +00:00
call - > b_exclusive = 1 ; // we are done
/* activate channel given by remote */
bchannel_event ( call - > isdn_ep , call - > b_index , B_EVENT_USE ) ;
}
return ( 0 ) ;
}
/*
* ISDN instance
*/
/* create isdn interface instance */
isdn_t * isdn_create ( void )
{
isdn_t * isdn_ep ;
isdn_ep = calloc ( 1 , sizeof ( * isdn_ep ) ) ;
if ( ! isdn_ep ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " No memory! \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
if ( pthread_mutex_init ( & isdn_ep - > upqueue_lock , NULL ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Cannot init mutex! \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " ISDN instance created \n " ) ;
2020-01-25 07:50:20 +00:00
return isdn_ep ;
}
/* destroy isdn interface instance and free all resource */
void isdn_destroy ( isdn_t * isdn_ep )
{
struct msn_list * msn ;
2022-03-27 14:30:19 +00:00
/* destroy all calls */
while ( isdn_ep - > call_list )
call_destroy ( isdn_ep - > call_list ) ;
2020-01-25 07:50:20 +00:00
/* remove stack instance */
isdn_close ( isdn_ep ) ;
/* close mISDN socket */
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock )
close ( isdn_ep - > l2sock ) ;
if ( isdn_ep - > l2inst )
mISDN_base_release ( isdn_ep - > l2inst ) ;
2020-01-25 07:50:20 +00:00
/* free msn list */
while ( isdn_ep - > msn_list ) {
msn = isdn_ep - > msn_list ;
isdn_ep - > msn_list = msn - > next ;
free ( msn ) ;
}
pthread_mutex_destroy ( & isdn_ep - > upqueue_lock ) ;
2024-01-09 11:24:14 +00:00
osmo_timer_del ( & isdn_ep - > l2establish_timer ) ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
osmo_timer_del ( & isdn_ep - > clock_timer ) ;
2023-01-21 17:11:20 +00:00
2020-01-25 07:50:20 +00:00
free ( isdn_ep ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " ISDN instance destroyed \n " ) ;
2020-01-25 07:50:20 +00:00
}
2023-01-21 17:11:20 +00:00
static void clock_timeout ( void * data ) ;
2020-01-25 07:50:20 +00:00
/* initialization and configuration to isdn interface instance */
2024-01-09 12:28:05 +00:00
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 , int aocd , int aocs )
2020-01-25 07:50:20 +00:00
{
int rc ;
2022-03-27 14:30:19 +00:00
void * mui ;
2020-01-25 07:50:20 +00:00
2022-03-27 14:30:19 +00:00
if ( ! ph_socket ) {
/* open mISDN socket */
rc = socket ( PF_ISDN , SOCK_RAW , ISDN_P_BASE ) ;
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Cannot open mISDN due to errno=%d:%s. (Does your Kernel support socket based mISDN? Protocol family is %d.) \n " , errno , strerror ( errno ) , PF_ISDN ) ;
2022-03-27 14:30:19 +00:00
return - errno ;
}
isdn_ep - > l2sock = rc ;
} else {
isdn_ep - > ph_socket = ph_socket ;
/* open mISDN user space */
rc = mISDN_base_create ( & mui , ISDN_P_BASE ) ;
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Cannot open mISDN due to errno=%d:%s. (Please fix!) \n " , errno , strerror ( errno ) ) ;
2022-03-27 14:30:19 +00:00
return - errno ;
}
isdn_ep - > l2inst = mui ;
portname = " 0 " ;
2020-01-25 07:50:20 +00:00
}
/* store settings */
isdn_ep - > law = law ;
isdn_ep - > portname = strdup ( portname ) ;
isdn_ep - > ntmode = ntmode ;
isdn_ep - > ptp = ptp ;
isdn_ep - > l1hold = layer1hold ;
isdn_ep - > l2hold = layer2hold ;
isdn_ep - > timeouts = timeouts ;
isdn_ep - > tx_delay = tx_delay ;
isdn_ep - > local_tones = local_tones ;
isdn_ep - > serving_location = serving_location ;
2024-01-09 12:28:05 +00:00
isdn_ep - > aocd = aocd ;
isdn_ep - > aocs = aocs ;
2020-01-25 07:50:20 +00:00
/* channel selection list */
if ( channel_out ) {
rc = parse_out_channel ( isdn_ep , channel_out ) ;
if ( rc < 0 )
return rc ;
} else
default_out_channel ( isdn_ep ) ;
if ( channel_in ) {
rc = parse_in_channel ( isdn_ep , channel_in ) ;
if ( rc < 0 )
return rc ;
} else
default_in_channel ( isdn_ep ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " ISDN instance initialized \n " ) ;
2020-01-25 07:50:20 +00:00
return 0 ;
}
/* add MSN number */
void isdn_add_msn ( isdn_t * isdn_ep , const char * msn )
{
struct msn_list * m , * * m_p ;
m = calloc ( 1 , sizeof ( * m ) + strlen ( msn ) + 1 ) ;
if ( ! m ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " No memory! \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
m_p = & isdn_ep - > msn_list ;
while ( * m_p )
m_p = & ( ( * m_p ) - > next ) ;
* m_p = m ;
strcpy ( m - > msn , msn ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " added MSDN number '%s' \n " , msn ) ;
2020-01-25 07:50:20 +00:00
}
/*
* call instance
*/
2022-06-24 17:58:41 +00:00
call_t * call_create ( isdn_t * isdn_ep , int direction , int channel , int exclusive , int mode )
2020-01-25 07:50:20 +00:00
{
call_t * call , * * call_p ;
call = calloc ( 1 , sizeof ( * call ) ) ;
if ( ! call ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " No memory! \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
call_p = & isdn_ep - > call_list ;
while ( * call_p )
call_p = & ( ( * call_p ) - > next ) ;
* call_p = call ;
call - > isdn_ep = isdn_ep ;
2022-06-24 17:58:41 +00:00
call - > direction = direction ;
2020-01-25 07:50:20 +00:00
call - > b_index = - 1 ;
call - > b_channel = 0 ;
call - > b_exclusive = 0 ;
call - > b_reserve = 0 ;
call - > b_mode = mode ;
call - > hold = 0 ;
2022-08-19 14:27:41 +00:00
call - > isdn_tone . tone = 0 ;
2020-01-25 07:50:20 +00:00
/* if any channel requested by constructor */
if ( channel = = CHANNEL_ANY ) {
/* reserve channel */
call - > b_reserve = 1 ;
isdn_ep - > b_reserved + + ;
}
/* reserve channel */
if ( channel > 0 ) // only if constructor was called with a channel resevation
seize_bchannel ( call , channel , exclusive ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Created new call on port #%d:%s \n " , isdn_ep - > portnum , isdn_ep - > portname ) ;
2020-01-25 07:50:20 +00:00
return call ;
}
2022-08-19 14:27:41 +00:00
void call_create_jitter ( call_t * call , int data )
{
isdn_t * isdn_ep = call - > isdn_ep ;
int rc ;
/* allocate jitter buffer */
if ( isdn_ep - > tx_delay )
rc = jitter_create ( & call - > tx_dejitter , " tx " , 8000 , sizeof ( uint8_t ) , ( double ) isdn_ep - > tx_delay / 1000.0 , ( double ) isdn_ep - > tx_delay / 1000.0 * 2.0 , JITTER_FLAG_NONE ) ;
else if ( data )
rc = jitter_create ( & call - > tx_dejitter , " tx " , 8000 , sizeof ( uint8_t ) , JITTER_DATA ) ;
else
rc = jitter_create ( & call - > tx_dejitter , " tx " , 8000 , sizeof ( uint8_t ) , JITTER_AUDIO ) ;
if ( rc < 0 )
abort ( ) ;
rc = jitter_create ( & call - > conf_dejitter , " conference " , 8000 , sizeof ( int16_t ) , JITTER_AUDIO ) ;
if ( rc < 0 )
abort ( ) ;
}
2020-01-25 07:50:20 +00:00
void call_destroy ( call_t * call )
{
call_t * * call_p ;
2022-08-19 14:27:41 +00:00
/* be sure to clean up bridge on server */
bridge_socket_client_update ( call , 0 ) ;
2020-01-25 07:50:20 +00:00
/* free jitter buffer */
2022-08-19 14:27:41 +00:00
jitter_destroy ( & call - > tx_dejitter ) ;
jitter_destroy ( & call - > conf_dejitter ) ;
2020-01-25 07:50:20 +00:00
/* remove B-channel relation */
drop_bchannel ( call ) ;
/* free session description */
if ( call - > cc_session )
osmo_cc_free_session ( call - > cc_session ) ;
free ( ( char * ) call - > sdp ) ;
2024-01-09 12:28:05 +00:00
/* remove metering timer, if still active */
osmo_timer_del ( & call - > aocd_unit_timer ) ;
2020-01-25 07:50:20 +00:00
/* detach */
call_p = & call - > isdn_ep - > call_list ;
while ( * call_p ) {
if ( * call_p = = call )
break ;
call_p = & ( ( * call_p ) - > next ) ;
}
* call_p = call - > next ;
free ( call ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " destroyed call instance \n " ) ;
2020-01-25 07:50:20 +00:00
}
/*
* bchannel handling
*/
2022-08-19 14:27:41 +00:00
/* send control information to the channel (HFC hardware bridging) */
static void im_control ( int sock , uint32_t op , uint32_t channel , uint32_t p1 , uint32_t p2 )
2020-01-25 07:50:20 +00:00
{
2022-08-19 14:27:41 +00:00
struct mISDN_ctrl_req cq ;
2020-01-25 07:50:20 +00:00
int rc ;
if ( sock < 0 )
return ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " sending IMCTRLREQ 0x%08x, %d, 0x%02x, 0x%02x \n " , op , channel , p1 , p2 ) ;
2020-01-25 07:50:20 +00:00
2022-08-19 14:27:41 +00:00
cq . op = op ;
cq . channel = channel ;
cq . p1 = p1 ;
cq . p2 = p2 ;
rc = ioctl ( sock , IMCTRLREQ , & cq ) ;
if ( rc < 0 )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Failed to send IMCTRLREQ to socket %d (errno=%d:%s) \n " , sock , errno , strerror ( errno ) ) ;
2020-01-25 07:50:20 +00:00
}
2023-01-21 17:11:20 +00:00
static int bchannel_kernel_sock_receive_cb ( struct osmo_fd * ofd , unsigned int when ) ;
2020-01-25 07:50:20 +00:00
/* 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 rc ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock ) {
2023-01-21 17:11:20 +00:00
if ( isdn_ep - > b_sock [ index ] . ofd . fd > 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Socket already created for index %d \n " , index ) ;
2022-03-27 14:30:19 +00:00
return - EIO ;
}
2020-01-25 07:50:20 +00:00
2022-03-27 14:30:19 +00:00
/* open socket */
if ( isdn_ep - > b_mode [ index ] = = B_MODE_HDLC ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_NOTICE , " Use B-Channel with HDLC!!! \n " ) ;
2022-03-27 14:30:19 +00:00
}
2022-08-19 14:27:41 +00:00
rc = socket ( PF_ISDN , SOCK_DGRAM , ( isdn_ep - > b_mode [ index ] = = B_MODE_HDLC ) ? ISDN_P_B_HDLC : ISDN_P_B_RAW ) ;
2022-03-27 14:30:19 +00:00
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko? \n " , index ) ;
2022-03-27 14:30:19 +00:00
return ( 0 ) ;
}
2023-01-21 17:11:20 +00:00
isdn_ep - > b_sock [ index ] . ofd . fd = rc ;
2022-03-27 14:30:19 +00:00
2023-01-21 17:11:20 +00:00
/* 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 ) ;
2022-03-27 14:30:19 +00:00
/* bind socket to bchannel */
addr . family = AF_ISDN ;
addr . dev = isdn_ep - > portnum ;
addr . channel = channel ;
2023-01-21 17:11:20 +00:00
rc = bind ( isdn_ep - > b_sock [ index ] . ofd . fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
2022-03-27 14:30:19 +00:00
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko? \n " , index , errno ) ;
2023-01-21 17:11:20 +00:00
/* unregister and close */
osmo_fd_unregister ( & isdn_ep - > b_sock [ index ] . ofd ) ;
close ( isdn_ep - > b_sock [ index ] . ofd . fd ) ;
2022-03-27 14:30:19 +00:00
return - errno ;
}
}
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " created socket #%d for B-channel %d \n " , isdn_ep - > b_sock [ index ] . ofd . fd , channel ) ;
2020-01-25 07:50:20 +00:00
return 0 ;
}
/* activate or deactivate B-channel */
static void bchannel_activate ( isdn_t * isdn_ep , int index , int activate , int timeout )
{
struct mISDNhead act ;
int channel = index + 1 + ( index > = 15 ) ;
int rc ;
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock ) {
2023-01-21 17:11:20 +00:00
if ( isdn_ep - > b_sock [ index ] . ofd . fd < = 0 )
2022-03-27 14:30:19 +00:00
return ;
2020-01-25 07:50:20 +00:00
2022-03-27 14:30:19 +00:00
act . prim = ( activate ) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ ;
act . id = 0 ;
2023-01-21 17:11:20 +00:00
rc = sendto ( isdn_ep - > b_sock [ index ] . ofd . fd , & act , MISDN_HEADER_LEN , 0 , NULL , 0 ) ;
2022-03-27 14:30:19 +00:00
if ( rc < 0 )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Failed to send to socket #%d, of B-channel %d \n " , isdn_ep - > b_sock [ index ] . ofd . fd , channel ) ;
2022-03-27 14:30:19 +00:00
}
2020-01-25 07:50:20 +00:00
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2inst ) {
uint8_t mode = PH_MODE_TRANS ;
if ( isdn_ep - > b_mode [ index ] = = B_MODE_HDLC ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_NOTICE , " Use B-Channel with HDLC!!! \n " ) ;
2022-03-27 14:30:19 +00:00
mode = PH_MODE_HDLC ;
}
ph_socket_tx_msg ( isdn_ep - > ph_socket , channel , ( activate ) ? PH_PRIM_ACT_REQ : PH_PRIM_DACT_REQ , & mode , 1 ) ;
}
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " %s B-channel %d%s \n " , ( activate ) ? " activating " : " deactivating " , channel , ( timeout ) ? " after timeout recovery " : " " ) ;
2020-01-25 07:50:20 +00:00
/* reset rx buffer */
isdn_ep - > b_buffer_pos [ index ] = 0 ;
}
/* configure B-channel */
static void bchannel_configure ( isdn_t * isdn_ep , int index )
{
2022-08-19 14:27:41 +00:00
int channel = index + 1 + ( index > = 15 ) ;
2020-01-25 07:50:20 +00:00
call_t * call ;
2022-08-19 14:27:41 +00:00
int handle ;
2020-01-25 07:50:20 +00:00
2023-01-21 17:11:20 +00:00
if ( isdn_ep - > b_sock [ index ] . ofd . fd < = 0 )
2020-01-25 07:50:20 +00:00
return ;
2023-01-21 17:11:20 +00:00
handle = isdn_ep - > b_sock [ index ] . ofd . fd ;
2020-01-25 07:50:20 +00:00
call = isdn_ep - > b_call [ index ] ;
2022-08-19 14:27:41 +00:00
/* set PCM bridge features */
if ( call - > bridge_enabled )
im_control ( handle , MISDN_CTRL_HFC_PCM_CONN , channel , call - > bridge_slot_tx | ( call - > bridge_bank_tx < < 8 ) , call - > bridge_slot_rx | ( call - > bridge_bank_rx < < 8 ) ) ;
else
im_control ( handle , MISDN_CTRL_HFC_PCM_DISC , channel , 0 , 0 ) ;
2020-01-25 07:50:20 +00:00
}
2022-08-19 14:27:41 +00:00
void bchannel_bridge ( call_t * call , int pcm_bridge , int rx_slot , int tx_slot , int rx_bank , int tx_bank )
2020-01-25 07:50:20 +00:00
{
2022-08-19 14:27:41 +00:00
/* bridge enabled */
call - > bridge_enabled = pcm_bridge ;
call - > bridge_bank_tx = tx_bank ;
call - > bridge_slot_tx = tx_slot ;
call - > bridge_bank_rx = rx_bank ;
call - > bridge_slot_rx = rx_slot ;
bchannel_configure ( call - > isdn_ep , call - > b_index ) ;
}
2020-01-25 07:50:20 +00:00
2022-08-19 14:27:41 +00:00
void bchannel_tone ( call_t * call , int tone )
{
2020-01-25 07:50:20 +00:00
if ( call - > b_index < 0 )
return ;
int mode = call - > isdn_ep - > b_mode [ call - > b_index ] ;
if ( mode ! = B_MODE_TRANSPARENT )
return ;
2022-08-19 14:27:41 +00:00
isdn_tone_set ( & call - > isdn_tone , tone ) ;
2020-01-25 07:50:20 +00:00
}
/* destroy B-channel stack */
static void bchannel_destroy ( isdn_t * isdn_ep , int index )
{
int channel = index + 1 + ( index > = 15 ) ;
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock ) {
2023-01-21 17:11:20 +00:00
if ( isdn_ep - > b_sock [ index ] . ofd . fd < = 0 )
2022-03-27 14:30:19 +00:00
return ;
2020-01-25 07:50:20 +00:00
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " destroyed socket #%d for B-channel %d \n " , isdn_ep - > b_sock [ index ] . ofd . fd , channel ) ;
2020-01-25 07:50:20 +00:00
2023-01-21 17:11:20 +00:00
/* 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 ;
2022-03-27 14:30:19 +00:00
}
if ( isdn_ep - > l2inst ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " destroyed B-channel %d \n " , channel ) ;
2022-03-27 14:30:19 +00:00
}
2020-01-25 07:50:20 +00:00
}
/*
* bchannel procedure
* - - - - - - - - - - - - - - - - - -
*
* A bchannel goes through the following states in this order :
*
* - B_STATE_IDLE
* No one is using the bchannel .
* It is available and not linked to call instance , nor reserved .
*
* - B_STATE_ACTIVATING
* The bchannel stack is created and an activation request is sent .
* It MAY be linked to a call , but already unlinked due to call release .
*
* - B_STATE_ACTIVE
2021-01-01 21:13:47 +00:00
* The bchannel is active and configured for the need of the call .
* Also it is linked to a call , otherwise it would be deactivated .
2020-01-25 07:50:20 +00:00
*
* - B_STATE_DEACTIVATING
* The bchannel is in deactivating state , due to deactivation request .
* It may be linked to a call , that likes to reactivate it .
*
* - B_STATE_IDLE
* See above .
* After deactivating bchannel , and if not used , the bchannel becomes idle again .
*
* A bchannel can have the following events :
*
* - B_EVENT_USE
* A bchannel is required by a call instance .
*
* - B_EVENT_ACTIVATED
* The bchannel beomes active .
*
* - B_EVENT_DROP
* The bchannel is not required by a call anymore
*
* - B_EVENT_DEACTIVATED
* The bchannel becomes inactive .
*
* All actions taken on these events depend on the current bchannel ' s state and
2021-01-01 21:13:47 +00:00
* whether it is linked to a call instance .
2020-01-25 07:50:20 +00:00
*
*/
/* process bchannel events */
void bchannel_event ( isdn_t * isdn_ep , int index , int event )
{
call_t * call ;
int state ;
int channel ;
int timer = - 1 ; // no change
channel = index + 1 + ( index > = 15 ) ;
call = isdn_ep - > b_call [ index ] ;
state = isdn_ep - > b_state [ index ] ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " handling event %d at state %d for B-channel %d \n " , event , state , channel ) ;
2020-01-25 07:50:20 +00:00
switch ( event ) {
case B_EVENT_USE :
/* call must be linked in order to allow activation */
if ( ! call ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " bchannel must be linked to a call instance \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
switch ( state ) {
case B_STATE_IDLE :
/* create stack and send activation request */
if ( bchannel_create ( isdn_ep , index ) = = 0 ) {
bchannel_activate ( isdn_ep , index , 1 , 0 ) ;
state = B_STATE_ACTIVATING ;
timer = B_TIMER_ACTIVATING ;
}
break ;
case B_STATE_ACTIVATING :
/* do nothing, because it is already activating */
break ;
default :
2021-01-01 21:13:47 +00:00
/* problems that might occur:
2020-01-25 07:50:20 +00:00
* B_EVENT_USE is received when channel already in use .
*/
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Illegal event %d at state %d, please correct. \n " , event , state ) ;
2020-01-25 07:50:20 +00:00
}
break ;
case B_EVENT_ACTIVATED :
timer = 0 ;
switch ( state ) {
case B_STATE_ACTIVATING :
if ( call ) {
/* bchannel is active and used by a call instance, so we configure bchannel */
bchannel_configure ( isdn_ep , index ) ;
state = B_STATE_ACTIVE ;
2022-08-19 14:27:41 +00:00
call - > b_rx_time = 0.0 ;
call - > b_transmitting = 0 ;
2020-01-25 07:50:20 +00:00
//FIXME: init buffer state for delay
} else {
/* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
bchannel_activate ( isdn_ep , index , 0 , 0 ) ;
state = B_STATE_DEACTIVATING ;
timer = B_TIMER_DEACTIVATING ;
}
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Illegal event %d at state %d, please correct. \n " , event , state ) ;
2020-01-25 07:50:20 +00:00
}
break ;
case B_EVENT_DROP :
if ( ! call ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " bchannel must be linked to a call instance \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
switch ( state ) {
case B_STATE_IDLE :
/* bchannel is idle due to an error, so we do nothing */
break ;
case B_STATE_ACTIVATING :
/* do nothing because we must wait until bchanenl is active before deactivating */
break ;
case B_STATE_ACTIVE :
/* bchannel is active, so we deactivate */
bchannel_activate ( isdn_ep , index , 0 , 0 ) ;
state = B_STATE_DEACTIVATING ;
timer = B_TIMER_DEACTIVATING ;
break ;
case B_STATE_DEACTIVATING :
/* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Illegal event %d at state %d, please correct. \n " , event , state ) ;
2020-01-25 07:50:20 +00:00
}
break ;
case B_EVENT_DEACTIVATED :
timer = 0 ;
switch ( state ) {
case B_STATE_IDLE :
/* ignore due to deactivation confirm after unloading */
break ;
case B_STATE_DEACTIVATING :
bchannel_destroy ( isdn_ep , index ) ;
state = B_STATE_IDLE ;
if ( call ) {
2021-01-01 21:13:47 +00:00
/* bchannel is now deactivate, but is required by call instance, so we reactivate */
2020-01-25 07:50:20 +00:00
if ( bchannel_create ( isdn_ep , index ) = = 0 ) {
bchannel_activate ( isdn_ep , index , 1 , 0 ) ;
state = B_STATE_ACTIVATING ;
timer = B_TIMER_ACTIVATING ;
}
}
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Illegal event %d at state %d, please correct. \n " , event , state ) ;
2020-01-25 07:50:20 +00:00
}
break ;
case B_EVENT_TIMEOUT :
timer = 0 ;
switch ( state ) {
case B_STATE_IDLE :
/* ignore due to deactivation confirm after unloading */
break ;
case B_STATE_ACTIVATING :
bchannel_activate ( isdn_ep , index , 1 , 1 ) ;
timer = B_TIMER_ACTIVATING ;
break ;
case B_STATE_DEACTIVATING :
bchannel_activate ( isdn_ep , index , 0 , 1 ) ;
timer = B_TIMER_DEACTIVATING ;
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Illegal event %d at state %d, please correct. \n " , event , state ) ;
2020-01-25 07:50:20 +00:00
}
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Illegal event %d, please correct. \n " , event ) ;
2020-01-25 07:50:20 +00:00
}
isdn_ep - > b_state [ index ] = state ;
if ( timer = = 0 )
2024-01-09 11:24:14 +00:00
osmo_timer_del ( & isdn_ep - > b_timer [ index ] ) ;
2020-01-25 07:50:20 +00:00
else if ( timer > 0 )
2024-01-09 11:24:14 +00:00
osmo_timer_schedule ( & isdn_ep - > b_timer [ index ] , timer , 0 ) ;
2020-01-25 07:50:20 +00:00
}
2022-08-19 14:27:41 +00:00
static void bchannel_rx_tx ( isdn_t * isdn_ep , int index , struct mISDNhead * hh , unsigned char * data , int len ) ;
static void bchannel_confirm ( isdn_t * isdn_ep , int index ) ;
2020-01-25 07:50:20 +00:00
2022-03-27 14:30:19 +00:00
/* handle frames from B-channel (kernel socket) */
2023-01-21 17:11:20 +00:00
static int bchannel_kernel_sock_receive_cb ( struct osmo_fd * ofd , unsigned int when )
2020-01-25 07:50:20 +00:00
{
2023-01-21 17:11:20 +00:00
struct isdn_b_sock * b_sock = ofd - > data ;
int index = b_sock - > index ;
isdn_t * isdn_ep = b_sock - > isdn_ep ;
2020-01-25 07:50:20 +00:00
int channel = index + 1 + ( index > = 15 ) ;
unsigned char buffer [ 2048 + MISDN_HEADER_LEN ] ;
struct mISDNhead * hh = ( struct mISDNhead * ) buffer ;
int rc ;
2023-01-21 17:11:20 +00:00
if ( ! ( when & OSMO_FD_READ ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " this should never happen! \n " ) ;
2023-01-21 17:11:20 +00:00
return 0 ;
}
rc = recv ( ofd - > fd , buffer , sizeof ( buffer ) , 0 ) ;
2020-01-25 07:50:20 +00:00
if ( rc < 0 ) {
if ( errno = = EAGAIN )
return 0 ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " read error B-channel data (socket #%d errno=%d:%s) \n " , ofd - > fd , errno , strerror ( errno ) ) ;
2020-01-25 07:50:20 +00:00
return 0 ;
}
if ( rc < ( int ) MISDN_HEADER_LEN ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " read short frame, got %d, expected %d \n " , rc , ( int ) MISDN_HEADER_LEN ) ;
2020-01-25 07:50:20 +00:00
return 0 ;
}
switch ( hh - > prim ) {
/* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF :
2022-08-19 14:27:41 +00:00
if ( isdn_ep - > b_call [ index ] )
bchannel_confirm ( isdn_ep , index ) ;
2020-01-25 07:50:20 +00:00
break ;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND :
case DL_DATA_IND :
case PH_DATA_REQ :
case DL_DATA_REQ :
case PH_CONTROL_IND :
if ( isdn_ep - > b_call [ index ] )
2022-08-19 14:27:41 +00:00
bchannel_rx_tx ( isdn_ep , index , hh , buffer + MISDN_HEADER_LEN , rc - MISDN_HEADER_LEN ) ;
2020-01-25 07:50:20 +00:00
else
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " b-channel is not associated to a call (channel %d), ignoring. \n " , channel ) ;
2020-01-25 07:50:20 +00:00
break ;
case PH_ACTIVATE_IND :
case DL_ESTABLISH_IND :
case PH_ACTIVATE_CNF :
case DL_ESTABLISH_CNF :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " DL_ESTABLISH confirm: bchannel is now activated (channel %d). \n " , channel ) ;
2020-01-25 07:50:20 +00:00
bchannel_event ( isdn_ep , index , B_EVENT_ACTIVATED ) ;
break ;
case PH_DEACTIVATE_IND :
case DL_RELEASE_IND :
case PH_DEACTIVATE_CNF :
case DL_RELEASE_CNF :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " DL_RELEASE confirm: bchannel is now de-activated (channel %d). \n " , channel ) ;
2020-01-25 07:50:20 +00:00
bchannel_event ( isdn_ep , index , B_EVENT_DEACTIVATED ) ;
break ;
default :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " child message not handled: prim(0x%x) channel(%d) msg->len(%d) \n " , hh - > prim , channel , rc - ( int ) MISDN_HEADER_LEN ) ;
2020-01-25 07:50:20 +00:00
}
return 1 ;
}
2022-03-27 14:30:19 +00:00
/* handle data frames from B-channel (ph_socket) */
void bchannel_ph_sock_receive ( void * priv , int channel , uint8_t prim , uint8_t * data , int length )
{
isdn_t * isdn_ep = ( isdn_t * ) priv ;
int index = channel - 1 - ( channel > 16 ) ;
if ( index < 0 | | index > 127 )
return ;
switch ( prim ) {
2022-08-19 14:27:41 +00:00
case PH_PRIM_DATA_CNF :
if ( isdn_ep - > b_call [ index ] )
bchannel_confirm ( isdn_ep , index ) ;
break ;
2022-03-27 14:30:19 +00:00
case PH_PRIM_DATA_IND :
if ( isdn_ep - > b_call [ index ] ) {
struct mISDNhead hh = { . prim = PH_DATA_IND } ;
2022-08-19 14:27:41 +00:00
bchannel_rx_tx ( isdn_ep , index , & hh , data , length ) ;
2022-03-27 14:30:19 +00:00
} else
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " b-channel is not associated to a call (channel %d), ignoring. \n " , channel ) ;
2022-03-27 14:30:19 +00:00
break ;
case PH_PRIM_ACT_IND :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " PH_PRIM_ACT_IND: bchannel is now activated (channel %d). \n " , channel ) ;
2022-03-27 14:30:19 +00:00
bchannel_event ( isdn_ep , index , B_EVENT_ACTIVATED ) ;
break ;
case PH_PRIM_DACT_IND :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " PH_PRIM_DACT_IND: bchannel is now deactivated (channel %d). \n " , channel ) ;
2022-03-27 14:30:19 +00:00
bchannel_event ( isdn_ep , index , B_EVENT_DEACTIVATED ) ;
break ;
}
}
2023-01-21 17:11:20 +00:00
static void b_timer_timeout ( void * data )
2020-01-25 07:50:20 +00:00
{
2023-01-21 17:11:20 +00:00
struct b_timer_inst * ti = data ;
2020-01-25 07:50:20 +00:00
bchannel_event ( ti - > isdn_ep , ti - > index , B_EVENT_TIMEOUT ) ;
}
/*
* check for available channel and reserve + set it .
* give channel number or SEL_CHANNEL_ANY or SEL_CHANNEL_NO
2021-01-01 21:13:47 +00:00
* give exclusive flag
2020-01-25 07:50:20 +00:00
* returns - ( cause value ) or x = channel x or 0 = no channel
* NOTE : no activation is done here
*/
int seize_bchannel ( call_t * call , int channel , int exclusive )
{
isdn_t * isdn_ep ;
int index ;
isdn_ep = call - > isdn_ep ;
/* the channel is what we already have */
if ( call - > b_channel = = channel )
return channel ;
/* if channel already in use, release it */
if ( call - > b_channel )
drop_bchannel ( call ) ;
/* if CHANNEL_NO */
if ( channel = = CHANNEL_NO | | channel = = 0 )
return 0 ;
/* is channel out of range ? */
if ( channel = = 16
| | ( channel > isdn_ep - > b_num & & channel < 16 )
| | ( ( channel - 1 ) > isdn_ep - > b_num & & channel > 16 ) ) /* channel-1 because channel 16 is not counted */
return - 6 ; /* channel unacceptable */
/* request exclusive channel */
if ( exclusive & & channel > 0 ) {
index = channel - 1 - ( channel > 16 ) ;
if ( isdn_ep - > b_call [ index ] )
return - 44 ; /* requested channel not available */
goto seize ;
}
/* ask for channel */
if ( channel > 0 ) {
index = channel - 1 - ( channel > 16 ) ;
if ( ! isdn_ep - > b_call [ index ] )
goto seize ;
}
/* search for channel */
for ( index = 0 ; index < isdn_ep - > b_num ; index + + ) {
if ( ! isdn_ep - > b_call [ index ] ) {
channel = index + 1 + ( index > = 15 ) ;
goto seize ;
}
}
return - 34 ; /* no free channel */
seize :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " seizing bchannel %d (index %d) \n " , channel , index ) ;
2020-01-25 07:50:20 +00:00
/* link Port, set parameters */
isdn_ep - > b_call [ index ] = call ;
isdn_ep - > b_mode [ index ] = call - > b_mode ;
call - > b_index = index ;
call - > b_channel = channel ;
call - > b_exclusive = exclusive ;
/* reserve channel */
if ( ! call - > b_reserve ) {
call - > b_reserve = 1 ;
isdn_ep - > b_reserved + + ;
}
return channel ;
}
/*
* drop reserved channel and unset it .
* deactivation is also done
*/
void drop_bchannel ( call_t * call )
{
isdn_t * isdn_ep ;
isdn_ep = call - > isdn_ep ;
/* unreserve channel */
if ( call - > b_reserve ) {
isdn_ep - > b_reserved - - ;
call - > b_reserve = 0 ;
}
/* if not in use */
if ( call - > b_index < 0 )
return ;
if ( ! call - > b_channel )
return ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " dropping bchannel %d (index %d) \n " , call - > b_channel , call - > b_index ) ;
2020-01-25 07:50:20 +00:00
if ( isdn_ep - > b_state [ call - > b_index ] ! = B_STATE_IDLE )
bchannel_event ( isdn_ep , call - > b_index , B_EVENT_DROP ) ;
isdn_ep - > b_call [ call - > b_index ] = NULL ;
isdn_ep - > b_mode [ call - > b_index ] = 0 ;
call - > b_index = - 1 ;
call - > b_channel = 0 ;
call - > b_exclusive = 0 ;
}
static void send_to_rtp ( call_t * call , unsigned char * data , int len )
{
call_t * other ;
if ( ! call | | ! call - > audio_path )
return ;
if ( call - > conference_3pty ) {
2022-08-19 14:27:41 +00:00
int16_t * audio_local ;
2020-01-25 07:50:20 +00:00
int audio_len ;
2022-08-19 14:27:41 +00:00
int16_t audio_mix [ len ] , audio_remote_active [ len ] , audio_remote_hold [ len ] ;
int32_t spl ;
2020-01-25 07:50:20 +00:00
int i ;
/* there should be no call on hold with audio coming from */
if ( call - > hold )
return ;
/* convert local audio from interface to samples */
if ( call - > isdn_ep - > law = = ' a ' )
2022-12-04 10:02:58 +00:00
g711_decode_alaw_flipped ( data , len , ( uint8_t * * ) & audio_local , & audio_len , NULL ) ;
2020-01-25 07:50:20 +00:00
else
2022-12-04 10:02:58 +00:00
g711_decode_ulaw_flipped ( data , len , ( uint8_t * * ) & audio_local , & audio_len , NULL ) ;
2020-01-25 07:50:20 +00:00
// don't free audio, because we need that later when encoding
/* convert remote RTP to samples */
2022-08-19 14:27:41 +00:00
jitter_load ( & call - > conf_dejitter , audio_remote_active , len ) ;
2020-01-25 07:50:20 +00:00
/* search other party on hold */
other = call - > isdn_ep - > call_list ;
while ( other ) {
if ( other ! = call
& & other - > l3_ces = = call - > l3_ces
& & other - > hold & & other - > conference_3pty )
break ;
other = other - > next ;
}
/* convert remote RTP to samples */
if ( other )
2022-08-19 14:27:41 +00:00
jitter_load ( & other - > conf_dejitter , audio_remote_hold , len ) ;
2020-01-25 07:50:20 +00:00
else
2022-08-19 14:27:41 +00:00
memset ( audio_remote_hold , 0 , sizeof ( * audio_remote_hold ) * len ) ;
2020-01-25 07:50:20 +00:00
/* mix audio for local interface and forward */
2022-08-19 14:27:41 +00:00
for ( i = 0 ; i < len ; i + + ) {
spl = ( int32_t ) audio_remote_active [ i ] + ( int32_t ) audio_remote_hold [ i ] ; /* both remote parties */
if ( spl < - 32767 )
spl = - 32767 ;
if ( spl > 32767 )
spl = 32767 ;
audio_mix [ i ] = spl ;
}
2020-01-25 07:50:20 +00:00
if ( call - > isdn_ep - > law = = ' a ' )
2022-12-04 10:02:58 +00:00
g711_encode_alaw_flipped ( ( uint8_t * ) audio_mix , audio_len , & data , & len , NULL ) ;
2020-01-25 07:50:20 +00:00
else
2022-12-04 10:02:58 +00:00
g711_encode_ulaw_flipped ( ( uint8_t * ) audio_mix , audio_len , & data , & len , NULL ) ;
2022-08-19 14:27:41 +00:00
if ( call - > b_index > = 0 & & call - > b_transmitting ) {
jitter_save ( & call - > tx_dejitter , data , len , 0 , 0 , 0 , 0 ) ;
2020-01-25 07:50:20 +00:00
}
free ( data ) ;
/* mix audio for (active) remote interface and forward */
2022-08-19 14:27:41 +00:00
for ( i = 0 ; i < len ; i + + ) {
spl = audio_local [ i ] + audio_remote_hold [ i ] ; /* local + remote (on hold) party */
if ( spl < - 32767 )
spl = - 32767 ;
if ( spl > 32767 )
spl = 32767 ;
audio_mix [ i ] = spl ;
}
2020-01-25 07:50:20 +00:00
if ( call - > isdn_ep - > law = = ' a ' )
2022-12-04 10:02:58 +00:00
g711_encode_alaw_flipped ( ( uint8_t * ) audio_mix , audio_len , & data , & len , NULL ) ;
2020-01-25 07:50:20 +00:00
else
2022-12-04 10:02:58 +00:00
g711_encode_ulaw_flipped ( ( uint8_t * ) audio_mix , audio_len , & data , & len , NULL ) ;
osmo_cc_rtp_send ( call - > codec , data , len , 0 , 1 , len , call ) ;
2020-01-25 07:50:20 +00:00
free ( data ) ;
/* mix audio for (hold) remote interface and forward */
if ( other ) {
2022-08-19 14:27:41 +00:00
for ( i = 0 ; i < len ; i + + ) {
spl = audio_local [ i ] + audio_remote_active [ i ] ; /* local + remote (active) party */
if ( spl < - 32767 )
spl = - 32767 ;
if ( spl > 32767 )
spl = 32767 ;
audio_mix [ i ] = spl ;
}
2020-01-25 07:50:20 +00:00
if ( call - > isdn_ep - > law = = ' a ' )
2022-12-04 10:02:58 +00:00
g711_encode_alaw_flipped ( ( uint8_t * ) audio_mix , audio_len , & data , & len , NULL ) ;
2020-01-25 07:50:20 +00:00
else
2022-12-04 10:02:58 +00:00
g711_encode_ulaw_flipped ( ( uint8_t * ) audio_mix , audio_len , & data , & len , NULL ) ;
osmo_cc_rtp_send ( other - > codec , data , len , 0 , 1 , len , other ) ;
2020-01-25 07:50:20 +00:00
free ( data ) ;
}
2022-08-19 14:27:41 +00:00
free ( audio_local ) ;
2020-01-25 07:50:20 +00:00
return ;
}
2022-06-24 17:58:41 +00:00
/* bridging, don't forward */
2022-08-19 14:27:41 +00:00
if ( call - > bridge_enabled )
2022-06-24 17:58:41 +00:00
return ;
2022-12-04 10:02:58 +00:00
osmo_cc_rtp_send ( call - > codec , data , len , 0 , 1 , len , call ) ;
2020-01-25 07:50:20 +00:00
}
2022-08-19 14:27:41 +00:00
/* receive audio and control from B-channel, transmit data from jitter buffer accoring to received length */
static void bchannel_rx_tx ( isdn_t * isdn_ep , int index , struct mISDNhead * hh , unsigned char * data , int len )
2020-01-25 07:50:20 +00:00
{
uint8_t * buffer = isdn_ep - > b_buffer [ index ] ;
int * buffer_pos = & ( isdn_ep - > b_buffer_pos [ index ] ) ;
2022-08-19 14:27:41 +00:00
call_t * call = isdn_ep - > b_call [ index ] ;
int i ;
2020-01-25 07:50:20 +00:00
if ( hh - > prim = = PH_CONTROL_IND ) {
if ( len < 4 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " SHORT READ OF PH_CONTROL INDICATION \n " ) ;
2020-01-25 07:50:20 +00:00
return ;
}
return ;
}
2022-08-19 14:27:41 +00:00
if ( hh - > prim ! = PH_DATA_IND )
2020-01-25 07:50:20 +00:00
return ;
2022-08-19 14:27:41 +00:00
if ( ! call ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Dropping b-channel data from channel without call. \n " ) ;
2022-08-19 14:27:41 +00:00
return ;
}
if ( isdn_ep - > b_state [ index ] ! = B_STATE_ACTIVE ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Dropping b-channel data from inactive channel. \n " ) ;
2022-08-19 14:27:41 +00:00
return ;
}
/* no transmission when bridging and playing no tones */
if ( call - > bridge_enabled & & ! call - > isdn_tone . tone ) {
call - > b_transmitting = 0 ;
* buffer_pos = 0 ;
return ;
}
/* check jitter of receved stream from ISDN */
double now = get_time ( ) ;
if ( call - > b_rx_time ) {
double elapsed = now - call - > b_rx_time ;
if ( ( int ) ( elapsed * 8000.0 ) - len > len / 4 )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Data received %d samples, time elapsed %d samples \n " , len , ( int ) ( elapsed * 8000.0 ) ) ;
2022-08-19 14:27:41 +00:00
}
call - > b_rx_time = now ;
/* add to buffer and send via RTP */
for ( i = 0 ; i < len ; i + + ) {
buffer [ ( * buffer_pos ) + + ] = data [ i ] ;
2020-01-25 07:50:20 +00:00
if ( * buffer_pos = = 160 ) {
* buffer_pos = 0 ;
2022-08-19 14:27:41 +00:00
send_to_rtp ( call , buffer , 160 ) ;
2020-01-25 07:50:20 +00:00
}
}
2022-08-19 14:27:41 +00:00
/* prepare ISDN TX buffer */
2023-03-04 17:47:19 +00:00
unsigned char buf [ MISDN_HEADER_LEN + len ] ;
2022-08-19 14:27:41 +00:00
struct mISDNhead * frm = ( struct mISDNhead * ) buf ;
int rc = 0 ;
frm - > prim = PH_DATA_REQ ;
frm - > id = 0 ;
/* load from TX jitter buffer and optionally overload with tones */
2023-03-04 17:47:19 +00:00
jitter_load ( & call - > tx_dejitter , buf + MISDN_HEADER_LEN , len ) ;
isdn_tone_copy ( & call - > isdn_tone , buf + MISDN_HEADER_LEN , len ) ;
if ( ! call - > b_transmitting ) {
unsigned char init_buf [ MISDN_HEADER_LEN + len ] ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " First received b-channel data, filling FIFO with two chunks of %d bytes. \n " , len ) ;
2023-03-04 17:47:19 +00:00
memcpy ( init_buf , frm , MISDN_HEADER_LEN ) ;
memset ( init_buf + MISDN_HEADER_LEN , 0xff , len ) ;
/* forward to interface */
if ( call - > isdn_ep - > ph_socket )
ph_socket_tx_msg ( call - > isdn_ep - > ph_socket , call - > b_channel , PH_PRIM_DATA_REQ , init_buf + MISDN_HEADER_LEN , len ) ;
else
rc = send ( call - > isdn_ep - > b_sock [ call - > b_index ] . ofd . fd , init_buf , MISDN_HEADER_LEN + len , 0 ) ;
call - > b_transmitting = 1 ;
}
2022-08-19 14:27:41 +00:00
/* forward to interface */
if ( call - > isdn_ep - > ph_socket )
2023-03-04 17:47:19 +00:00
ph_socket_tx_msg ( call - > isdn_ep - > ph_socket , call - > b_channel , PH_PRIM_DATA_REQ , buf + MISDN_HEADER_LEN , len ) ;
2022-08-19 14:27:41 +00:00
else
2023-03-04 17:47:19 +00:00
rc = send ( call - > isdn_ep - > b_sock [ call - > b_index ] . ofd . fd , buf , MISDN_HEADER_LEN + len , 0 ) ;
2022-08-19 14:27:41 +00:00
if ( rc < 0 )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_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 ) ) ;
2022-08-19 14:27:41 +00:00
}
/* receive confirm from bchannel */
static void bchannel_confirm ( isdn_t * isdn_ep , int index )
{
call_t * call = isdn_ep - > b_call [ index ] ;
if ( ! call ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Ignoring b-channel confirm of channel without call. \n " ) ;
2022-08-19 14:27:41 +00:00
return ;
}
double now = get_time ( ) ;
if ( call - > b_rx_time ) {
double elapsed = now - call - > b_rx_time ;
if ( elapsed > 4 )
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Data confirmed, time elapsed %d samples \n " , ( int ) ( elapsed * 8000.0 ) ) ;
2022-08-19 14:27:41 +00:00
}
2020-01-25 07:50:20 +00:00
}
2022-08-19 14:27:41 +00:00
/* send audio from RTP to B-channel's jitter buffer */
2022-10-30 15:14:17 +00:00
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 )
2020-01-25 07:50:20 +00:00
{
call_t * call = codec - > media - > session - > priv ;
/* conference parties store their audio in jitter buffer */
if ( call - > conference_3pty ) {
int16_t * audio ;
int audio_len ;
/* alaw/ulaw to linear */
if ( call - > isdn_ep - > law = = ' a ' )
2022-12-04 10:02:58 +00:00
g711_decode_alaw_flipped ( data , len , ( uint8_t * * ) & audio , & audio_len , NULL ) ;
2020-01-25 07:50:20 +00:00
else
2022-12-04 10:02:58 +00:00
g711_decode_ulaw_flipped ( data , len , ( uint8_t * * ) & audio , & audio_len , NULL ) ;
2020-01-25 07:50:20 +00:00
/* enqueue data to jitter buffer */
2022-08-19 14:27:41 +00:00
jitter_save ( & call - > conf_dejitter , audio , len , 1 , sequence_number , timestamp , ssrc ) ;
free ( audio ) ;
2020-01-25 07:50:20 +00:00
return ;
}
2022-06-24 17:58:41 +00:00
/* bridging, don't forward */
2022-08-19 14:27:41 +00:00
if ( call - > bridge_enabled )
return ;
/* not yet b_transmitting on bchannel */
if ( ! call - > b_transmitting )
return ;
/* ignore voice, if call is on hold */
if ( call - > hold )
2022-06-24 17:58:41 +00:00
return ;
2020-01-25 07:50:20 +00:00
/* no conference, just forward to ISDN interface */
2022-08-19 14:27:41 +00:00
jitter_save ( & call - > tx_dejitter , data , len , 1 , sequence_number , timestamp , ssrc ) ;
2020-01-25 07:50:20 +00:00
}
/*
* isdn stack handling
*/
int do_layer3 ( struct mlayer3 * ml3 , unsigned int cmd , unsigned int pid , struct l3_msg * l3m )
{
isdn_t * isdn_ep = ( isdn_t * ) ml3 - > priv ;
struct mbuffer * mb ;
/* queue message, create, if required */
if ( ! l3m ) {
l3m = alloc_l3_msg ( ) ;
if ( ! l3m ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " No memory for layer 3 message \n " ) ;
2020-01-25 07:50:20 +00:00
abort ( ) ;
}
}
mb = container_of ( l3m , struct mbuffer , l3 ) ;
l3m - > type = cmd ;
l3m - > pid = pid ;
pthread_mutex_lock ( & isdn_ep - > upqueue_lock ) ;
mqueue_tail ( & isdn_ep - > upqueue , mb ) ;
pthread_mutex_unlock ( & isdn_ep - > upqueue_lock ) ;
2023-01-21 17:11:20 +00:00
/* wake main thread */
char wakeup = 0 ;
write ( isdn_ep - > upqueue_pipe [ 1 ] , & wakeup , 1 ) ;
2020-01-25 07:50:20 +00:00
return 0 ;
}
2022-03-27 14:30:19 +00:00
int mISDN_getportbyname ( isdn_t * isdn_ep , int cnt , const char * portname )
2020-01-25 07:50:20 +00:00
{
struct mISDN_devinfo devinfo ;
int port = 0 , rc ;
memset ( & devinfo , 0 , sizeof ( devinfo ) ) ;
/* resolve name */
while ( port < cnt ) {
devinfo . id = port ;
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock )
rc = ioctl ( isdn_ep - > l2sock , IMGETDEVINFO , & devinfo ) ;
if ( isdn_ep - > l2inst )
rc = mISDN_base_ioctl ( isdn_ep - > l2inst , IMGETDEVINFO , & devinfo ) ;
2020-01-25 07:50:20 +00:00
if ( rc < 0 )
return rc ;
if ( ! strcasecmp ( devinfo . name , portname ) )
break ;
port + + ;
}
if ( port = = cnt )
return - EIO ;
return port ;
}
2023-01-21 17:11:20 +00:00
static void l2establish_timeout ( void * data ) ;
static int isdn_upqueue_cb ( struct osmo_fd * ofd , unsigned int what ) ;
2020-01-25 07:50:20 +00:00
/* open mISDN port */
int isdn_open ( isdn_t * isdn_ep )
{
const char * portname = isdn_ep - > portname ;
int portnum ;
int ptp = isdn_ep - > ptp ;
int force_nt = isdn_ep - > ntmode ;
int l1hold = isdn_ep - > l1hold ;
int l2hold = isdn_ep - > l2hold ;
int i , cnt ;
int pri , bri ;
int nt , te ;
struct mISDN_devinfo devinfo ;
unsigned int protocol , prop ;
2022-03-27 14:30:19 +00:00
int rc = 0 ;
2020-01-25 07:50:20 +00:00
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init ( & isdn_ep - > upqueue ) ;
isdn_ep - > upqueue_initialized = 1 ;
2023-01-21 17:11:20 +00:00
rc = pipe ( isdn_ep - > upqueue_pipe ) ;
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Failed to create pipe errno=%d:%s. (Please fix!) \n " , errno , strerror ( errno ) ) ;
2023-01-21 17:11:20 +00:00
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 ) ;
2020-01-25 07:50:20 +00:00
/* port number given ? */
for ( i = 0 ; i < ( int ) strlen ( portname ) ; i + + ) {
if ( portname [ i ] < ' 0 ' | | portname [ i ] > ' 9 ' )
break ;
}
if ( i = = ( int ) strlen ( portname ) )
portnum = atoi ( portname ) ;
else
portnum = - 1 ;
memset ( & devinfo , 0 , sizeof ( devinfo ) ) ;
/* check port counts */
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock )
rc = ioctl ( isdn_ep - > l2sock , IMGETCOUNT , & cnt ) ;
if ( isdn_ep - > l2inst )
rc = mISDN_base_ioctl ( isdn_ep - > l2inst , IMGETCOUNT , & cnt ) ;
2020-01-25 07:50:20 +00:00
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed errno = %d) \n " , errno ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
if ( cnt < = 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Found no card. Please be sure to load card drivers. \n " ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
if ( portnum < 0 ) {
2022-03-27 14:30:19 +00:00
portnum = mISDN_getportbyname ( isdn_ep , cnt , portname ) ;
2020-01-25 07:50:20 +00:00
if ( portnum < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port name '%s' not found, use 'misdn_info' tool to list all existing ports. \n " , portname ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
// note: 'portnum' has now the port number
}
if ( portnum > cnt | | portnum < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port (%d) given at 'ports' (options.conf) is out of existing port range (%d-%d) \n " , portnum , 0 , cnt ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
/* get port attributes */
pri = bri = nt = te = 0 ;
devinfo . id = portnum ;
2022-03-27 14:30:19 +00:00
if ( isdn_ep - > l2sock )
rc = ioctl ( isdn_ep - > l2sock , IMGETDEVINFO , & devinfo ) ;
if ( isdn_ep - > l2inst )
rc = mISDN_base_ioctl ( isdn_ep - > l2inst , IMGETDEVINFO , & devinfo ) ;
2020-01-25 07:50:20 +00:00
if ( rc < 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Cannot get device information for port %d. (ioctl IMGETDEVINFO failed errno=%d) \n " , portnum , errno ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
if ( devinfo . Dprotocols & ( 1 < < ISDN_P_TE_S0 ) ) {
bri = 1 ;
te = 1 ;
}
if ( devinfo . Dprotocols & ( 1 < < ISDN_P_NT_S0 ) ) {
bri = 1 ;
nt = 1 ;
}
if ( devinfo . Dprotocols & ( 1 < < ISDN_P_TE_E1 ) ) {
pri = 1 ;
te = 1 ;
}
if ( devinfo . Dprotocols & ( 1 < < ISDN_P_NT_E1 ) ) {
pri = 1 ;
nt = 1 ;
}
if ( force_nt & & ! nt ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d does not support NT-mode \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
if ( bri & & pri ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d supports BRI and PRI?? What kind of controller is that?. (Can't use this!) \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
if ( ! bri & & ! pri ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d does not support BRI nor PRI \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
if ( ! nt & & ! te ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d does not support NT-mode nor TE-mode! \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
/* set NT by turning off TE */
if ( force_nt & & nt )
te = 0 ;
/* if TE an NT is supported (and not forced to NT), turn off NT */
if ( te & & nt )
nt = 0 ;
2021-01-01 21:13:47 +00:00
/* check for continuous channelmap with no bchannel on slot 16 */
2020-01-25 07:50:20 +00:00
if ( test_channelmap ( 0 , devinfo . channelmap ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d provides channel 0, but we cannot access it! \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
i = 1 ;
while ( i < ( int ) devinfo . nrbchan + 1 ) {
if ( i = = 16 ) {
if ( test_channelmap ( i , devinfo . channelmap ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d provides bchannel 16. Please upgrade mISDN, if this port is mISDN loopback interface. \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
} else {
if ( ! test_channelmap ( i , devinfo . channelmap ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " Port %d has no channel on slot %d! \n " , portnum , i ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
}
i + + ;
}
2024-01-09 11:24:14 +00:00
osmo_timer_setup ( & isdn_ep - > clock_timer , clock_timeout , isdn_ep ) ;
2023-01-21 17:11:20 +00:00
2024-01-09 11:24:14 +00:00
osmo_timer_setup ( & isdn_ep - > l2establish_timer , l2establish_timeout , isdn_ep ) ;
2020-01-25 07:50:20 +00:00
isdn_ep - > l1link = - 1 ;
isdn_ep - > l2link = - 1 ;
/* if pri, must set PTP */
if ( pri )
ptp = 1 ;
/* set l2hold */
switch ( l2hold ) {
case - 1 : // off
l2hold = 0 ;
break ;
case 1 : // on
l2hold = 1 ;
break ;
default :
if ( ptp )
l2hold = 1 ;
else
l2hold = 0 ;
break ;
}
2021-01-01 21:13:47 +00:00
/* allocate resources of port */
2020-01-25 07:50:20 +00:00
protocol = ( nt ) ? L3_PROTOCOL_DSS1_NET : L3_PROTOCOL_DSS1_USER ;
prop = ( 1 < < MISDN_FLG_L2_CLEAN ) ;
if ( ptp ) // ptp forced
prop | = ( 1 < < MISDN_FLG_PTP ) ;
if ( nt ) // supports hold/retrieve on nt-mode
prop | = ( 1 < < MISDN_FLG_NET_HOLD ) ;
if ( l1hold ) // supports layer 1 hold
prop | = ( 1 < < MISDN_FLG_L1_HOLD ) ;
if ( l2hold ) // supports layer 2 hold
prop | = ( 1 < < MISDN_FLG_L2_HOLD ) ;
/* open layer 3 */
isdn_ep - > ml3 = open_layer3 ( portnum , protocol , prop , do_layer3 , isdn_ep ) ;
if ( ! isdn_ep - > ml3 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_ERROR , " open_layer3() failed for port %d \n " , portnum ) ;
2020-01-25 07:50:20 +00:00
goto error ;
}
isdn_ep - > b_num = devinfo . nrbchan ;
2022-03-27 14:30:19 +00:00
if ( ! isdn_ep - > b_num )
isdn_ep - > b_num = ( pri ) ? 30 : 2 ;
2020-01-25 07:50:20 +00:00
isdn_ep - > portnum = portnum ;
if ( isdn_ep - > portname )
free ( isdn_ep - > portname ) ;
isdn_ep - > portname = strdup ( devinfo . name ) ;
2022-08-19 14:27:41 +00:00
if ( ! strncmp ( isdn_ep - > portname , " hfc-4s. " , 7 )
| | ! strncmp ( isdn_ep - > portname , " hfc-8s. " , 7 )
| | ! strncmp ( isdn_ep - > portname , " hfc-e1. " , 7 ) ) {
/* cards that support hardware bridging */
isdn_ep - > bridge_possible = 1 ;
isdn_ep - > bridge_cardnum = strtoul ( isdn_ep - > portname + 7 , NULL , 10 ) ;
isdn_ep - > bridge_portnum = portnum ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_INFO , " Port can use HFC bridge of card %d. \n " , isdn_ep - > bridge_cardnum ) ;
2022-08-19 14:27:41 +00:00
}
2020-01-25 07:50:20 +00:00
isdn_ep - > ntmode = nt ;
isdn_ep - > pri = pri ;
isdn_ep - > ptp = ptp ;
isdn_ep - > l1hold = l1hold ;
isdn_ep - > l2hold = l2hold ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " Port has %d b-channels. \n " , isdn_ep - > b_num ) ;
2020-01-25 07:50:20 +00:00
for ( i = 0 ; i < isdn_ep - > b_num ; i + + ) {
isdn_ep - > b_state [ i ] = B_STATE_IDLE ;
2024-01-09 11:24:14 +00:00
osmo_timer_setup ( & isdn_ep - > b_timer [ i ] , b_timer_timeout , & isdn_ep - > b_timer_inst ) ;
2020-01-25 07:50:20 +00:00
isdn_ep - > b_timer_inst [ i ] . isdn_ep = isdn_ep ;
isdn_ep - > b_timer_inst [ i ] . index = i ;
}
/* if ptp, pull up the link */
if ( isdn_ep - > l2hold & & ( isdn_ep - > ptp | | ! isdn_ep - > ntmode ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " reqzest layer 2 to be establised for tei 0 \n " ) ;
osmo_timer_schedule ( & isdn_ep - > l2establish_timer , 5 , 0 ) ; /* 5 seconds */
2020-01-25 07:50:20 +00:00
}
/* for nt-mode ptmp the link is always up */
if ( isdn_ep - > ntmode & & ! isdn_ep - > ptp )
isdn_ep - > l2link = 1 ;
return 0 ;
error :
isdn_close ( isdn_ep ) ;
return - EINVAL ;
}
/* close mISDN port */
void isdn_close ( isdn_t * isdn_ep )
{
int i ;
struct select_channel * selchannel ;
/* free bchannels */
for ( i = 0 ; i < isdn_ep - > b_num ; i + + ) {
2023-01-21 17:11:20 +00:00
if ( isdn_ep - > b_sock [ i ] . ofd . fd > 0 ) {
2020-01-25 07:50:20 +00:00
bchannel_destroy ( isdn_ep , i ) ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " freeing %s port %s bchannel (index %d). \n " , ( isdn_ep - > ntmode ) ? " NT " : " TE " , isdn_ep - > portname , i ) ;
2020-01-25 07:50:20 +00:00
}
2024-01-09 11:24:14 +00:00
osmo_timer_del ( & isdn_ep - > b_timer [ i ] ) ;
2020-01-25 07:50:20 +00:00
}
2024-01-09 11:24:14 +00:00
osmo_timer_del ( & isdn_ep - > l2establish_timer ) ;
2020-01-25 07:50:20 +00:00
/* close layer 3, if open */
if ( isdn_ep - > ml3 ) {
close_layer3 ( isdn_ep - > ml3 ) ;
}
2023-01-21 17:11:20 +00:00
/* purge and remove upqueue */
2020-01-25 07:50:20 +00:00
if ( isdn_ep - > upqueue_initialized )
mqueue_purge ( & isdn_ep - > upqueue ) ;
2023-01-21 17:11:20 +00:00
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 ;
}
2020-01-25 07:50:20 +00:00
if ( isdn_ep - > portname ) {
free ( isdn_ep - > portname ) ;
isdn_ep - > portname = NULL ;
}
while ( isdn_ep - > in_channel ) {
selchannel = isdn_ep - > in_channel ;
isdn_ep - > in_channel = selchannel - > next ;
free ( selchannel ) ;
}
while ( isdn_ep - > out_channel ) {
selchannel = isdn_ep - > out_channel ;
isdn_ep - > out_channel = selchannel - > next ;
free ( selchannel ) ;
}
}
2023-01-21 17:11:20 +00:00
/* receive message from ISDN protocol stack (out of the upqueue) */
static int isdn_upqueue_cb ( struct osmo_fd * ofd , unsigned __attribute__ ( ( unused ) ) int what )
2020-01-25 07:50:20 +00:00
{
2023-01-21 17:11:20 +00:00
isdn_t * isdn_ep = ofd - > data ;
2020-01-25 07:50:20 +00:00
struct mbuffer * mb ;
struct l3_msg * l3m ;
2023-01-21 17:11:20 +00:00
char wakeup = 0 ;
read ( ofd - > fd , & wakeup , 1 ) ;
again :
2020-01-25 07:50:20 +00:00
/* 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 ) ;
2023-01-21 17:11:20 +00:00
if ( ! mb )
return 0 ;
l3m = & mb - > l3 ;
switch ( l3m - > type ) {
case MPH_ACTIVATE_IND :
if ( isdn_ep - > l1link ! = 1 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_INFO , " layer 1 becomes active \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > l1link = 1 ;
}
break ;
case MPH_DEACTIVATE_IND :
if ( isdn_ep - > l1link ! = 0 ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_INFO , " layer 1 becomes inactive \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > l1link = 0 ;
}
break ;
case MPH_INFORMATION_IND :
switch ( l3m - > pid ) {
case L1_SIGNAL_LOS_ON :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " received LOS \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > los = 1 ;
2020-01-25 07:50:20 +00:00
break ;
2023-01-21 17:11:20 +00:00
case L1_SIGNAL_LOS_OFF :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " LOS is gone \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > los = 0 ;
2020-01-25 07:50:20 +00:00
break ;
2023-01-21 17:11:20 +00:00
case L1_SIGNAL_AIS_ON :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " received AIS \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > ais = 1 ;
2020-01-25 07:50:20 +00:00
break ;
2023-01-21 17:11:20 +00:00
case L1_SIGNAL_AIS_OFF :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " AIS is gone \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > ais = 0 ;
2020-01-25 07:50:20 +00:00
break ;
2023-01-21 17:11:20 +00:00
case L1_SIGNAL_RDI_ON :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " received RDI \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > rdi = 1 ;
break ;
case L1_SIGNAL_RDI_OFF :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " RDI is gone \n " ) ;
2023-01-21 17:11:20 +00:00
isdn_ep - > rdi = 0 ;
break ;
case L1_SIGNAL_SLIP_TX :
isdn_ep - > slip_tx + + ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " received TX slip #%d \n " , isdn_ep - > slip_tx ) ;
2023-01-21 17:11:20 +00:00
break ;
case L1_SIGNAL_SLIP_RX :
isdn_ep - > slip_rx + + ;
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " received RX slip #%d \n " , isdn_ep - > slip_rx ) ;
2020-01-25 07:50:20 +00:00
break ;
2023-01-21 17:11:20 +00:00
}
break ;
2020-01-25 07:50:20 +00:00
2023-01-21 17:11:20 +00:00
case MT_L2ESTABLISH :
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_INFO , " layer 2 becomes active (tei = %d) \n " , l3m - > pid ) ;
2023-01-21 17:11:20 +00:00
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 ) {
2024-01-09 11:24:14 +00:00
if ( osmo_timer_pending ( & isdn_ep - > l2establish_timer ) )
osmo_timer_del ( & isdn_ep - > l2establish_timer ) ;
2023-01-21 17:11:20 +00:00
}
break ;
case MT_L2RELEASE :
if ( l3m - > pid < 128 )
isdn_ep - > l2mask [ l3m - > pid > > 3 ] & = ~ ( 1 < < ( l3m - > pid & 7 ) ) ;
2024-01-09 11:24:14 +00:00
if ( ! osmo_timer_pending ( & isdn_ep - > l2establish_timer ) ) {
LOGP ( DISDN , LOGL_INFO , " layer 2 becomes inactive (tei = %d) \n " , l3m - > pid ) ;
2023-01-21 17:11:20 +00:00
/* down if not nt-ptmp */
if ( ! isdn_ep - > ntmode | | isdn_ep - > ptp )
isdn_ep - > l2link = 0 ;
2020-01-25 07:50:20 +00:00
}
2023-01-21 17:11:20 +00:00
if ( ( ! isdn_ep - > ntmode | | isdn_ep - > ptp ) & & l3m - > pid < 127 ) {
2024-01-09 11:24:14 +00:00
if ( ! osmo_timer_pending ( & isdn_ep - > l2establish_timer ) & & isdn_ep - > l2hold ) {
osmo_timer_schedule ( & isdn_ep - > l2establish_timer , 5 , 0 ) ; /* 5 seconds */
2023-01-21 17:11:20 +00:00
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 ) ;
2020-01-25 07:50:20 +00:00
}
2023-01-21 17:11:20 +00:00
/* free message */
free_l3_msg ( l3m ) ;
2020-01-25 07:50:20 +00:00
2023-01-21 17:11:20 +00:00
goto again ;
2020-01-25 07:50:20 +00:00
}
/* l2 establish timer fires */
2023-01-21 17:11:20 +00:00
static void l2establish_timeout ( void * data )
2020-01-25 07:50:20 +00:00
{
2023-01-21 17:11:20 +00:00
isdn_t * isdn_ep = data ;
2020-01-25 07:50:20 +00:00
if ( isdn_ep - > l2hold & & ( isdn_ep - > ptp | | ! isdn_ep - > ntmode ) ) {
2024-01-09 11:24:14 +00:00
LOGP ( DISDN , LOGL_DEBUG , " the L2 establish timer expired, we try to establish the link portnum=%d. \n " , isdn_ep - > portnum ) ;
2020-01-25 07:50:20 +00:00
isdn_ep - > ml3 - > to_layer3 ( isdn_ep - > ml3 , MT_L2ESTABLISH , 0 , NULL ) ;
2024-01-09 11:24:14 +00:00
osmo_timer_schedule ( & isdn_ep - > l2establish_timer , 5 , 0 ) ; /* 5 seconds */
2020-01-25 07:50:20 +00:00
}
}
2023-01-21 17:11:20 +00:00
/*
* local clock to generate hold tone
*/
2022-10-30 15:14:17 +00:00
# define COMFORT_NOISE (0.02 * SPEECH_LEVEL) /* audio level of comfort noise (relative to ISDN level) */
2023-01-21 17:11:20 +00:00
# define CHUNK_DURATION 0.020
# define CHUNK_LENGTH 160
2022-10-30 15:14:17 +00:00
2023-01-21 17:11:20 +00:00
static void clock_timeout ( void * data )
2022-10-30 15:14:17 +00:00
{
2023-01-21 17:11:20 +00:00
isdn_t * isdn_ep = data ;
int len = CHUNK_LENGTH ;
2022-10-30 15:14:17 +00:00
call_t * call ;
2023-01-21 17:11:20 +00:00
int any = 0 ;
2022-10-30 15:14:17 +00:00
call = isdn_ep - > call_list ;
while ( call ) {
if ( ( call - > state = = ISDN_STATE_SUSPENDED | | call - > hold ) & & call - > codec ) {
int16_t noise [ len ] ;
uint8_t * data ;
int i ;
int16_t r ;
for ( i = 0 ; i < len ; i + + ) {
r = random ( ) ;
noise [ i ] = ( double ) r * COMFORT_NOISE ;
}
if ( call - > isdn_ep - > law = = ' a ' )
2022-12-04 10:02:58 +00:00
g711_encode_alaw_flipped ( ( uint8_t * ) noise , len * 2 , & data , & len , NULL ) ;
2022-10-30 15:14:17 +00:00
else
2022-12-04 10:02:58 +00:00
g711_encode_ulaw_flipped ( ( uint8_t * ) noise , len * 2 , & data , & len , NULL ) ;
osmo_cc_rtp_send ( call - > codec , data , len , 0 , 1 , len , call ) ;
2022-10-30 15:14:17 +00:00
free ( data ) ;
2023-01-21 17:11:20 +00:00
any = 1 ;
2022-10-30 15:14:17 +00:00
}
call = call - > next ;
}
2023-01-21 17:11:20 +00:00
/* 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 ;
2024-01-09 11:24:14 +00:00
osmo_timer_schedule ( & isdn_ep - > clock_timer , 0 , ( isdn_ep - > last_time_clock - now ) * 1000000 ) ;
2023-01-21 17:11:20 +00:00
}
}
void enable_hold_clock ( isdn_t * isdn_ep )
{
double now ;
/* already running, so keep running without restart */
2024-01-09 11:24:14 +00:00
if ( osmo_timer_pending ( & isdn_ep - > clock_timer ) )
2023-01-21 17:11:20 +00:00
return ;
/* start timer to wait for 20ms */
now = get_time ( ) ;
isdn_ep - > last_time_clock = now + CHUNK_DURATION ;
2024-01-09 11:24:14 +00:00
osmo_timer_schedule ( & isdn_ep - > clock_timer , 0 , CHUNK_DURATION * 1000000 ) ;
2022-10-30 15:14:17 +00:00
}
2023-01-21 17:11:20 +00:00