mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
* first bits of decoding facility information elements
* fail on misdn_cfg_init() if elements in the config enum don't match with the config structs in misdn_config.c * implemented first bits for encoding ISDN facility information elements via ASN.1 descriptions * using unnamed semaphore for syncing in misdn_thread * advanced fax detection: configurable detect timeout and context to jump into git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39378 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -43,8 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/config.h"
|
||||
@@ -157,7 +156,9 @@ struct chan_list {
|
||||
char ast_rd_buf[4096];
|
||||
struct ast_frame frame;
|
||||
|
||||
int faxdetect;
|
||||
int faxdetect; /* 0:no 1:yes 2:yes+nojump */
|
||||
int faxdetect_timeout;
|
||||
struct timeval faxdetect_tv;
|
||||
int faxhandled;
|
||||
|
||||
int ast_dsp;
|
||||
@@ -258,7 +259,6 @@ static struct robin_list* get_robin_position (char *group)
|
||||
/* the main schedule context for stuff like l1 watcher, overlap dial, ... */
|
||||
static struct sched_context *misdn_tasks = NULL;
|
||||
static pthread_t misdn_tasks_thread;
|
||||
static int misdn_tasks_semid;
|
||||
|
||||
static void chan_misdn_log(int level, int port, char *tmpl, ...);
|
||||
|
||||
@@ -417,15 +417,15 @@ static void print_facility( struct misdn_bchannel *bc)
|
||||
{
|
||||
switch (bc->fac_type) {
|
||||
case FACILITY_CALLDEFLECT:
|
||||
chan_misdn_log(2,bc->port," --> calldeflect: %s\n",
|
||||
chan_misdn_log(0,bc->port," --> calldeflect: %s\n",
|
||||
bc->fac.calldeflect_nr);
|
||||
break;
|
||||
case FACILITY_CENTREX:
|
||||
chan_misdn_log(2,bc->port," --> centrex: %s\n",
|
||||
chan_misdn_log(0,bc->port," --> centrex: %s\n",
|
||||
bc->fac.cnip);
|
||||
break;
|
||||
default:
|
||||
chan_misdn_log(2,bc->port," --> unknown\n");
|
||||
chan_misdn_log(0,bc->port," --> unknown\n");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -453,11 +453,6 @@ static void* misdn_tasks_thread_func (void *data)
|
||||
{
|
||||
int wait;
|
||||
struct sigaction sa;
|
||||
struct sembuf semb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = 1,
|
||||
.sem_flg = 0
|
||||
};
|
||||
|
||||
sa.sa_handler = sighandler;
|
||||
sa.sa_flags = SA_NODEFER;
|
||||
@@ -465,7 +460,7 @@ static void* misdn_tasks_thread_func (void *data)
|
||||
sigaddset(&sa.sa_mask, SIGUSR1);
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
|
||||
semop(misdn_tasks_semid, &semb, 1);
|
||||
sem_post((sem_t *)data);
|
||||
|
||||
while (1) {
|
||||
wait = ast_sched_wait(misdn_tasks);
|
||||
@@ -480,44 +475,21 @@ static void* misdn_tasks_thread_func (void *data)
|
||||
|
||||
static void misdn_tasks_init (void)
|
||||
{
|
||||
key_t key;
|
||||
union {
|
||||
int val;
|
||||
struct semid_ds *buf;
|
||||
unsigned short *array;
|
||||
struct seminfo *__buf;
|
||||
} semu;
|
||||
struct sembuf semb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = -1,
|
||||
.sem_flg = 0
|
||||
};
|
||||
sem_t blocker;
|
||||
int i = 5;
|
||||
|
||||
chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
|
||||
|
||||
key = ftok("/etc/asterisk/misdn.conf", 'E');
|
||||
if (key == -1) {
|
||||
perror("chan_misdn: Failed to create a semaphore key!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
misdn_tasks_semid = semget(key, 10, 0666 | IPC_CREAT);
|
||||
if (misdn_tasks_semid == -1) {
|
||||
perror("chan_misdn: Failed to get a semaphore!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
semu.val = 0;
|
||||
if (semctl(misdn_tasks_semid, 0, SETVAL, semu) == -1) {
|
||||
if (sem_init(&blocker, 0, 0)) {
|
||||
perror("chan_misdn: Failed to initialize semaphore!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
misdn_tasks = sched_context_create();
|
||||
pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, NULL);
|
||||
chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
|
||||
|
||||
semop(misdn_tasks_semid, &semb, 1);
|
||||
semctl(misdn_tasks_semid, 0, IPC_RMID, semu);
|
||||
misdn_tasks = sched_context_create();
|
||||
pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
|
||||
|
||||
while (sem_wait(&blocker) && --i);
|
||||
sem_destroy(&blocker);
|
||||
}
|
||||
|
||||
static void misdn_tasks_destroy (void)
|
||||
@@ -1751,6 +1723,8 @@ static int read_config(struct chan_list *ch, int orig) {
|
||||
|
||||
misdn_cfg_get( port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, BUFFERSIZE);
|
||||
|
||||
char faxdetect[BUFFERSIZE+1];
|
||||
misdn_cfg_get( port, MISDN_CFG_FAXDETECT, faxdetect, BUFFERSIZE);
|
||||
|
||||
int hdlc=0;
|
||||
misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
|
||||
@@ -1803,6 +1777,13 @@ static int read_config(struct chan_list *ch, int orig) {
|
||||
if ( orig == ORG_AST) {
|
||||
misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(int));
|
||||
|
||||
if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
|
||||
if (strstr(faxdetect, "nojump"))
|
||||
ch->faxdetect=2;
|
||||
else
|
||||
ch->faxdetect=1;
|
||||
}
|
||||
|
||||
{
|
||||
char callerid[BUFFERSIZE+1];
|
||||
misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE);
|
||||
@@ -1827,6 +1808,12 @@ static int read_config(struct chan_list *ch, int orig) {
|
||||
|
||||
ch->overlap_dial = 0;
|
||||
} else { /** ORIGINATOR MISDN **/
|
||||
if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
|
||||
if (strstr(faxdetect, "nojump"))
|
||||
ch->faxdetect=2;
|
||||
else
|
||||
ch->faxdetect=1;
|
||||
}
|
||||
|
||||
misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int));
|
||||
debug_numplan(port, bc->cpnnumplan,"CTON");
|
||||
@@ -1897,6 +1884,18 @@ static int read_config(struct chan_list *ch, int orig) {
|
||||
ast_mutex_init(&ch->overlap_tv_lock);
|
||||
} /* ORIG MISDN END */
|
||||
|
||||
ch->overlap_dial_task = -1;
|
||||
|
||||
if (ch->faxdetect) {
|
||||
misdn_cfg_get( port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
|
||||
if (!ch->dsp)
|
||||
ch->dsp = ast_dsp_new();
|
||||
if (ch->dsp)
|
||||
ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT);
|
||||
if (!ch->trans)
|
||||
ch->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2468,44 +2467,65 @@ static int misdn_hangup(struct ast_channel *ast)
|
||||
struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
|
||||
{
|
||||
struct ast_frame *f,*f2;
|
||||
if (tmp->trans)
|
||||
f2=ast_translate(tmp->trans, frame,0);
|
||||
else {
|
||||
|
||||
if (tmp->trans) {
|
||||
f2 = ast_translate(tmp->trans, frame, 0);
|
||||
f = ast_dsp_process(tmp->ast, tmp->dsp, f2);
|
||||
} else {
|
||||
chan_misdn_log(0, tmp->bc->port, "No T-Path found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = ast_dsp_process(tmp->ast, tmp->dsp, f2);
|
||||
if (f && (f->frametype == AST_FRAME_DTMF)) {
|
||||
ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c", f->subclass);
|
||||
if (f->subclass == 'f' && tmp->faxdetect) {
|
||||
/* Fax tone -- Handle and return NULL */
|
||||
struct ast_channel *ast = tmp->ast;
|
||||
if (!tmp->faxhandled) {
|
||||
tmp->faxhandled++;
|
||||
if (strcmp(ast->exten, "fax")) {
|
||||
if (ast_exists_extension(ast, ast_strlen_zero(ast->macrocontext)? ast->context : ast->macrocontext, "fax", 1, AST_CID_P(ast))) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
|
||||
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
|
||||
pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
|
||||
if (ast_async_goto(ast, ast->context, "fax", 1))
|
||||
ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, ast->context);
|
||||
} else
|
||||
ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n",ast->context, ast->exten);
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Fax already handled\n");
|
||||
|
||||
} else if ( tmp->ast_dsp) {
|
||||
chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n",f->subclass);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
if (!f || (f->frametype != AST_FRAME_DTMF))
|
||||
return frame;
|
||||
|
||||
ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c", f->subclass);
|
||||
|
||||
if (tmp->faxdetect && (f->subclass == 'f')) {
|
||||
/* Fax tone -- Handle and return NULL */
|
||||
if (!tmp->faxhandled) {
|
||||
struct ast_channel *ast = tmp->ast;
|
||||
tmp->faxhandled++;
|
||||
chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
|
||||
tmp->bc->rxgain = 0;
|
||||
isdn_lib_update_rxgain(tmp->bc);
|
||||
tmp->bc->txgain = 0;
|
||||
isdn_lib_update_txgain(tmp->bc);
|
||||
tmp->bc->ec_enable = 0;
|
||||
isdn_lib_update_ec(tmp->bc);
|
||||
isdn_lib_stop_dtmf(tmp->bc);
|
||||
switch (tmp->faxdetect) {
|
||||
case 1:
|
||||
if (strcmp(ast->exten, "fax")) {
|
||||
char *context;
|
||||
char context_tmp[BUFFERSIZE];
|
||||
misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
|
||||
context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
|
||||
if (ast_exists_extension(ast, context, "fax", 1, AST_CID_P(ast))) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
|
||||
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
|
||||
pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
|
||||
if (ast_async_goto(ast, context, "fax", 1))
|
||||
ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
|
||||
} else
|
||||
ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten);
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
|
||||
break;
|
||||
case 2:
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Fax already handled\n");
|
||||
}
|
||||
|
||||
if (tmp->ast_dsp && (f->subclass != 'f')) {
|
||||
chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass);
|
||||
}
|
||||
|
||||
frame->frametype = AST_FRAME_NULL;
|
||||
frame->subclass = 0;
|
||||
return frame;
|
||||
}
|
||||
|
||||
@@ -2519,7 +2539,7 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
|
||||
chan_misdn_log(1,0,"misdn_read called without ast\n");
|
||||
return NULL;
|
||||
}
|
||||
if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) {
|
||||
if (!(tmp=MISDN_ASTERISK_TECH_PVT(ast))) {
|
||||
chan_misdn_log(1,0,"misdn_read called without ast->pvt\n");
|
||||
return NULL;
|
||||
}
|
||||
@@ -2539,17 +2559,40 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
|
||||
tmp->frame.frametype = AST_FRAME_VOICE;
|
||||
tmp->frame.subclass = AST_FORMAT_ALAW;
|
||||
tmp->frame.datalen = len;
|
||||
tmp->frame.samples = len ;
|
||||
tmp->frame.mallocd =0 ;
|
||||
tmp->frame.offset= 0 ;
|
||||
tmp->frame.samples = len;
|
||||
tmp->frame.mallocd = 0;
|
||||
tmp->frame.offset = 0;
|
||||
tmp->frame.src = NULL;
|
||||
tmp->frame.data = tmp->ast_rd_buf ;
|
||||
tmp->frame.data = tmp->ast_rd_buf;
|
||||
|
||||
if (tmp->faxdetect || tmp->ast_dsp ) {
|
||||
return process_ast_dsp(tmp, &tmp->frame);
|
||||
if (tmp->faxdetect && !tmp->faxhandled) {
|
||||
if (tmp->faxdetect_timeout) {
|
||||
if (ast_tvzero(tmp->faxdetect_tv)) {
|
||||
tmp->faxdetect_tv = ast_tvnow();
|
||||
chan_misdn_log(2,tmp->bc->port,"faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
|
||||
return process_ast_dsp(tmp, &tmp->frame);
|
||||
} else {
|
||||
struct timeval tv_now = ast_tvnow();
|
||||
int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
|
||||
if (diff <= (tmp->faxdetect_timeout * 1000)) {
|
||||
chan_misdn_log(5,tmp->bc->port,"faxdetect: detecting ...\n");
|
||||
return process_ast_dsp(tmp, &tmp->frame);
|
||||
} else {
|
||||
chan_misdn_log(2,tmp->bc->port,"faxdetect: stopping detection (time ran out) ...\n");
|
||||
tmp->faxdetect = 0;
|
||||
return &tmp->frame;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chan_misdn_log(5,tmp->bc->port,"faxdetect: detecting ... (no timeout)\n");
|
||||
return process_ast_dsp(tmp, &tmp->frame);
|
||||
}
|
||||
} else {
|
||||
if (tmp->ast_dsp)
|
||||
return process_ast_dsp(tmp, &tmp->frame);
|
||||
else
|
||||
return &tmp->frame;
|
||||
}
|
||||
|
||||
return &tmp->frame;
|
||||
}
|
||||
|
||||
|
||||
@@ -2629,7 +2672,6 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
|
||||
}
|
||||
|
||||
chan_misdn_log(9, ch->bc->port, "Sending :%d bytes 2 MISDN\n",frame->samples);
|
||||
|
||||
if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) {
|
||||
/* Buffered Transmit (triggert by read from isdn side)*/
|
||||
if (misdn_jb_fill(ch->jb,frame->data,frame->samples) < 0) {
|
||||
@@ -3586,6 +3628,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
|
||||
case EVENT_PORT_ALARM:
|
||||
case EVENT_RETRIEVE:
|
||||
case EVENT_NEW_BC:
|
||||
case EVENT_FACILITY:
|
||||
break;
|
||||
case EVENT_RELEASE_COMPLETE:
|
||||
chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n");
|
||||
@@ -4442,6 +4485,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
|
||||
struct ast_channel *bridged=AST_BRIDGED_P(ch->ast);
|
||||
struct chan_list *ch;
|
||||
|
||||
misdn_lib_send_event(bc, EVENT_DISCONNECT);
|
||||
|
||||
if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
|
||||
ch=MISDN_ASTERISK_TECH_PVT(bridged);
|
||||
/*ch->state=MISDN_FACILITY_DEFLECTED;*/
|
||||
@@ -4455,7 +4500,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
|
||||
|
||||
break;
|
||||
default:
|
||||
chan_misdn_log(1, bc->port," --> not yet handled\n");
|
||||
chan_misdn_log(0, bc->port," --> not yet handled: facility type:%p\n", bc->fac_type);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -4550,8 +4595,10 @@ static int load_module(void *mod)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
misdn_cfg_init(max_ports);
|
||||
if (misdn_cfg_init(max_ports)) {
|
||||
ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
|
||||
return -1;
|
||||
}
|
||||
g_config_initialized=1;
|
||||
|
||||
misdn_debug = (int *)malloc(sizeof(int) * (max_ports+1));
|
||||
@@ -4891,6 +4938,7 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
|
||||
case 'f':
|
||||
chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
|
||||
ch->faxdetect=1;
|
||||
misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
@@ -4921,7 +4969,6 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
|
||||
if (ch->faxdetect || ch->ast_dsp) {
|
||||
|
||||
if (!ch->dsp) ch->dsp = ast_dsp_new();
|
||||
if (ch->dsp) ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT| DSP_FEATURE_FAX_DETECT);
|
||||
if (!ch->trans) ch->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW);
|
||||
|
@@ -11,14 +11,14 @@ CFLAGS += -fPIC
|
||||
endif
|
||||
SOURCES = isdn_lib.c isdn_msg_parser.c
|
||||
OBJDIR = .
|
||||
OBJS = isdn_lib.o isdn_msg_parser.o fac.o
|
||||
OBJS = isdn_lib.o isdn_msg_parser.o fac.o asn1.o
|
||||
|
||||
ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libbnec.so),)
|
||||
CFLAGS+=-DBEROEC_VERSION=1
|
||||
CFLAGS+=-DWITH_BEROEC
|
||||
endif
|
||||
|
||||
|
||||
CFLAGS+=-DFACILITY_DEBUG
|
||||
|
||||
all: chan_misdn_lib.a
|
||||
|
||||
|
181
channels/misdn/asn1.c
Normal file
181
channels/misdn/asn1.c
Normal file
@@ -0,0 +1,181 @@
|
||||
|
||||
#include "asn1.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** ASN.1 Encoding
|
||||
*/
|
||||
|
||||
int _enc_null (__u8 *dest, int tag)
|
||||
{
|
||||
dest[0] = tag;
|
||||
dest[1] = 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int _enc_bool (__u8 *dest, __u32 i, int tag)
|
||||
{
|
||||
dest[0] = tag;
|
||||
dest[1] = 1;
|
||||
dest[2] = i ? 1:0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
int _enc_int (__u8 *dest, __u32 i, int tag)
|
||||
{
|
||||
__u8 *p;
|
||||
dest[0] = tag;
|
||||
p = &dest[2];
|
||||
do {
|
||||
*p++ = i;
|
||||
i >>= 8;
|
||||
} while (i);
|
||||
dest[1] = p - &dest[2];
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
int _enc_enum (__u8 *dest, __u32 i, int tag)
|
||||
{
|
||||
__u8 *p;
|
||||
|
||||
dest[0] = tag;
|
||||
p = &dest[2];
|
||||
do {
|
||||
*p++ = i;
|
||||
i >>= 8;
|
||||
} while (i);
|
||||
dest[1] = p - &dest[2];
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
int _enc_num_string (__u8 *dest, __u8 *nd, __u8 len, int tag)
|
||||
{
|
||||
__u8 *p;
|
||||
int i;
|
||||
|
||||
dest[0] = tag;
|
||||
p = &dest[2];
|
||||
for (i = 0; i < len; i++)
|
||||
*p++ = *nd++;
|
||||
dest[1] = p - &dest[2];
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
int _enc_sequence_start (__u8 *dest, __u8 **id, int tag)
|
||||
{
|
||||
dest[0] = tag;
|
||||
*id = &dest[1];
|
||||
return 2;
|
||||
}
|
||||
|
||||
int _enc_sequence_end (__u8 *dest, __u8 *id, int tag_dummy)
|
||||
{
|
||||
*id = dest - id - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** ASN.1 Decoding
|
||||
*/
|
||||
|
||||
#define CHECK_P \
|
||||
do { \
|
||||
if (p >= end) \
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
#define CallASN1(ret, p, end, todo) \
|
||||
do { \
|
||||
ret = todo; \
|
||||
if (ret < 0) { \
|
||||
return -1; \
|
||||
} \
|
||||
p += ret; \
|
||||
} while (0)
|
||||
|
||||
#define INIT \
|
||||
int len, ret; \
|
||||
__u8 *begin = p; \
|
||||
if (tag) \
|
||||
*tag = *p; \
|
||||
p++; \
|
||||
CallASN1(ret, p, end, dec_len(p, &len)); \
|
||||
if (len >= 0) { \
|
||||
if (p + len > end) \
|
||||
return -1; \
|
||||
end = p + len; \
|
||||
}
|
||||
|
||||
int _dec_null (__u8 *p, __u8 *end, int *tag)
|
||||
{
|
||||
INIT;
|
||||
return p - begin;
|
||||
}
|
||||
|
||||
int _dec_bool (__u8 *p, __u8 *end, int *i, int *tag)
|
||||
{
|
||||
INIT;
|
||||
*i = 0;
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
*i = (*i >> 8) + *p;
|
||||
p++;
|
||||
}
|
||||
return p - begin;
|
||||
}
|
||||
|
||||
int _dec_int (__u8 *p, __u8 *end, int *i, int *tag)
|
||||
{
|
||||
INIT;
|
||||
|
||||
*i = 0;
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
*i = (*i << 8) + *p;
|
||||
p++;
|
||||
}
|
||||
return p - begin;
|
||||
}
|
||||
|
||||
int _dec_enum (__u8 *p, __u8 *end, int *i, int *tag)
|
||||
{
|
||||
INIT;
|
||||
|
||||
*i = 0;
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
*i = (*i << 8) + *p;
|
||||
p++;
|
||||
}
|
||||
return p - begin;
|
||||
}
|
||||
|
||||
int _dec_num_string (__u8 *p, __u8 *end, char *str, int *tag)
|
||||
{
|
||||
INIT;
|
||||
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
*str++ = *p;
|
||||
p++;
|
||||
}
|
||||
*str = 0;
|
||||
return p - begin;
|
||||
}
|
||||
|
||||
int _dec_octet_string (__u8 *p, __u8 *end, char *str, int *tag)
|
||||
{
|
||||
return _dec_num_string(p, end, str, tag);
|
||||
}
|
||||
|
||||
int _dec_sequence (__u8 *p, __u8 *end, int *tag)
|
||||
{
|
||||
INIT;
|
||||
return p - begin;
|
||||
}
|
||||
|
||||
int dec_len (__u8 *p, int *len)
|
||||
{
|
||||
*len = *p;
|
||||
return 1;
|
||||
}
|
72
channels/misdn/asn1.h
Normal file
72
channels/misdn/asn1.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef __ASN1_H__
|
||||
#define __ASN1_H__
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
/*
|
||||
** ASN.1 Tags
|
||||
*/
|
||||
|
||||
#define ASN1_TAG_BOOLEAN (0x01)
|
||||
#define ASN1_TAG_INTEGER (0x02)
|
||||
#define ASN1_TAG_BIT_STRING (0x03)
|
||||
#define ASN1_TAG_OCTET_STRING (0x04)
|
||||
#define ASN1_TAG_NULL (0x05)
|
||||
#define ASN1_TAG_OBJECT_IDENTIFIER (0x06)
|
||||
#define ASN1_TAG_ENUM (0x0a)
|
||||
#define ASN1_TAG_SEQUENCE (0x30)
|
||||
#define ASN1_TAG_SET (0x31)
|
||||
#define ASN1_TAG_NUMERIC_STRING (0x12)
|
||||
#define ASN1_TAG_PRINTABLE_STRING (0x13)
|
||||
#define ASN1_TAG_IA5_STRING (0x16)
|
||||
#define ASN1_TAG_UTC_TIME (0x17)
|
||||
#define ASN1_TAG_CONSTRUCTED (0x20)
|
||||
#define ASN1_TAG_CONTEXT_SPECIFIC (0x80)
|
||||
#define ASN1_TAG_EXPLICIT (0x100)
|
||||
#define ASN1_TAG_OPT (0x200)
|
||||
#define ASN1_NOT_TAGGED (0x400)
|
||||
|
||||
/*
|
||||
** ASN.1 Encoding
|
||||
*/
|
||||
|
||||
#define enc_null(dest) _enc_null(dest,ASN1_TAG_NULL)
|
||||
#define enc_bool(dest,i) _enc_bool(dest,i,ASN1_TAG_BOOLEAN)
|
||||
#define enc_int(dest,i) _enc_int(dest,i,ASN1_TAG_INTEGER)
|
||||
#define enc_enum(dest,i) _enc_enum(dest,i,ASN1_TAG_ENUM)
|
||||
#define enc_num_string(dest,num,len) _enc_num_string(dest,num,len,ASN1_TAG_NUMERIC_STRING)
|
||||
#define enc_sequence_start(dest,id) _enc_sequence_start(dest,id,ASN1_TAG_SEQUENCE)
|
||||
#define enc_sequence_end(dest,id) _enc_sequence_end(dest,id,ASN1_TAG_SEQUENCE)
|
||||
|
||||
int _enc_null (__u8 *dest, int tag);
|
||||
int _enc_bool (__u8 *dest, __u32 i, int tag);
|
||||
int _enc_int (__u8 *dest, __u32 i, int tag);
|
||||
int _enc_enum (__u8 *dest, __u32 i, int tag);
|
||||
int _enc_num_string (__u8 *dest, __u8 *nd, __u8 len, int tag);
|
||||
int _enc_sequence_start (__u8 *dest, __u8 **id, int tag);
|
||||
int _enc_sequence_end (__u8 *dest, __u8 *id, int tag_dummy);
|
||||
|
||||
/*
|
||||
** ASN.1 Decoding
|
||||
*/
|
||||
|
||||
#define dec_null(p, end) _dec_null (p, end, NULL);
|
||||
#define dec_bool(p, end,i) _dec_bool (p, end, i, NULL)
|
||||
#define dec_int(p, end,i) _dec_int (p, end, i, NULL)
|
||||
#define dec_enum(p, end,i) _dec_enum (p, end, i, NULL)
|
||||
#define dec_num_string(p, end,str) _dec_num_string (p, end, str, NULL)
|
||||
#define dec_octet_string(p, end,str) _dec_octet_string (p, end, str, NULL)
|
||||
#define dec_sequence(p, end) _dec_sequence (p, end, NULL)
|
||||
|
||||
int _dec_null (__u8 *p, __u8 *end, int *tag);
|
||||
int _dec_bool (__u8 *p, __u8 *end, int *i, int *tag);
|
||||
int _dec_int (__u8 *p, __u8 *end, int *i, int *tag);
|
||||
int _dec_enum (__u8 *p, __u8 *end, int *i, int *tag);
|
||||
int _dec_num_string (__u8 *p, __u8 *end, char *str, int *tag);
|
||||
int _dec_octet_string (__u8 *p, __u8 *end, char *str, int *tag);
|
||||
int _dec_sequence (__u8 *p, __u8 *end, int *tag);
|
||||
|
||||
int dec_len (__u8 *p, int *len);
|
||||
|
||||
#endif
|
||||
|
@@ -75,6 +75,8 @@ enum misdn_cfg_elements {
|
||||
MISDN_CFG_OVERLAP_DIAL, /* int (bool)*/
|
||||
MISDN_CFG_MSNS, /* char[] */
|
||||
MISDN_CFG_FAXDETECT, /* char[] */
|
||||
MISDN_CFG_FAXDETECT_CONTEXT, /* char[] */
|
||||
MISDN_CFG_FAXDETECT_TIMEOUT, /* int */
|
||||
MISDN_CFG_PTP, /* int (bool) */
|
||||
MISDN_CFG_LAST,
|
||||
|
||||
@@ -100,7 +102,7 @@ enum misdn_cfg_method {
|
||||
};
|
||||
|
||||
/* you must call misdn_cfg_init before any other function of this header file */
|
||||
void misdn_cfg_init(int max_ports);
|
||||
int misdn_cfg_init(int max_ports);
|
||||
void misdn_cfg_reload(void);
|
||||
void misdn_cfg_destroy(void);
|
||||
|
||||
|
@@ -1,313 +1,267 @@
|
||||
|
||||
#include "isdn_lib_intern.h"
|
||||
#include "isdn_lib.h"
|
||||
#include "fac.h"
|
||||
#include "asn1.h"
|
||||
|
||||
#include "string.h"
|
||||
#if 0
|
||||
+-------------------------------
|
||||
| IE_IDENTIFIER
|
||||
+-------------------------------
|
||||
| {length}
|
||||
+-------------------------------
|
||||
| +---------------------------
|
||||
| | SERVICE_DISCRIMINATOR
|
||||
| +---------------------------
|
||||
| | COMPONENT_TYPE_TAG
|
||||
| +---------------------------
|
||||
| | {length}
|
||||
| +---------------------------
|
||||
| | +-----------------------
|
||||
| | | INVOKE_IDENTIFIER_TAG (0x2)
|
||||
| | +-----------------------
|
||||
| | | {length} (0x1)
|
||||
| | +-----------------------
|
||||
| | | {value} (odd integer 0-127)
|
||||
| | +-----------------------
|
||||
| | +-----------------------
|
||||
| | | OPERATION_VALUE_TAG (0x2)
|
||||
| | +-----------------------
|
||||
| | | {length} (0x1)
|
||||
| | +-----------------------
|
||||
| | | {value}
|
||||
| | +-----------------------
|
||||
| | +-----------------------
|
||||
| | | ASN.1 data
|
||||
+---+---+-----------------------
|
||||
#endif
|
||||
|
||||
enum {
|
||||
SUPPLEMENTARY_SERVICE = 0x91,
|
||||
} SERVICE_DISCRIMINATOR;
|
||||
|
||||
enum {
|
||||
INVOKE = 0xa1,
|
||||
RETURN_RESULT = 0xa2,
|
||||
RETURN_ERROR = 0xa3,
|
||||
REJECT = 0xa4,
|
||||
} COMPONENT_TYPE_TAG;
|
||||
|
||||
enum {
|
||||
INVOKE_IDENTIFIER = 0x02,
|
||||
LINKED_IDENTIFIER = 0x80,
|
||||
NULL_IDENTIFIER = 0x05,
|
||||
} INVOKE_IDENTIFIER_TAG;
|
||||
|
||||
#define CENTREX_ID 0xa1
|
||||
#define CALLDEFLECT_ID 0xa1
|
||||
enum {
|
||||
OPERATION_VALUE = 0x02,
|
||||
} OPERATION_VALUE_TAG;
|
||||
|
||||
/**
|
||||
This file covers the encoding and decoding of facility messages and
|
||||
facility information elements.
|
||||
enum {
|
||||
VALUE_QUERY = 0x8c,
|
||||
SET_VALUE = 0x8d,
|
||||
REQUEST_FEATURE = 0x8f,
|
||||
ABORT = 0xbe,
|
||||
REDIRECT_CALL = 0xce,
|
||||
CALLING_PARTY_TO_HOLD = 0xcf,
|
||||
CALLING_PARTY_FROM_HOLD = 0x50,
|
||||
DROP_TARGET_PARTY = 0xd1,
|
||||
USER_DATA_TRANSFER = 0xd3,
|
||||
APP_SPECIFIC_STATUS = 0xd2,
|
||||
|
||||
There will be 2 Functions as Interface:
|
||||
/* not from document */
|
||||
CALL_DEFLECT = 0x0d,
|
||||
AOC = 0x22,
|
||||
} OPERATION_CODE;
|
||||
|
||||
fac_enc( char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc)
|
||||
fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc);
|
||||
enum {
|
||||
Q931_IE_TAG = 0x40,
|
||||
} ARGUMENT_TAG;
|
||||
|
||||
Those will either read the union facility or fill it.
|
||||
|
||||
internally, we will have deconding and encoding functions for each facility
|
||||
IE.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
/* support stuff */
|
||||
static void strnncpy(unsigned char *dest, unsigned char *src, int len, int dst_len)
|
||||
#ifdef FACILITY_DEBUG
|
||||
#define FAC_DUMP(fac,len,bc) fac_dump(fac,len,bc)
|
||||
#include <ctype.h>
|
||||
static void fac_dump (__u8 *facility, unsigned int fac_len, struct misdn_bchannel *bc)
|
||||
{
|
||||
if (len > dst_len-1)
|
||||
len = dst_len-1;
|
||||
strncpy((char *)dest, (char *)src, len);
|
||||
dest[len] = '\0';
|
||||
int i;
|
||||
cb_log(0, bc->port, " --- facility dump start. length:%d\n", fac_len);
|
||||
for (i = 0; i < fac_len; ++i)
|
||||
if (isprint(facility[i]))
|
||||
cb_log(0, bc->port, " --- %d: %04p (char:%c)\n", i, facility[i], facility[i]);
|
||||
else
|
||||
cb_log(0, bc->port, " --- %d: %04p\n", i, facility[i]);
|
||||
cb_log(0, bc->port, " --- facility dump end\n");
|
||||
}
|
||||
#else
|
||||
#define FAC_DUMP(fac,len,bc)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Facility Encoding
|
||||
*/
|
||||
|
||||
static int enc_fac_calldeflect (__u8 *dest, char *number, int pres)
|
||||
{
|
||||
__u8 *body_len,
|
||||
*p = dest,
|
||||
*seq1, *seq2;
|
||||
|
||||
*p++ = SUPPLEMENTARY_SERVICE;
|
||||
*p++ = INVOKE;
|
||||
|
||||
body_len = p++;
|
||||
|
||||
p += _enc_int(p, 0x1 /* some odd integer in (0..127) */, INVOKE_IDENTIFIER);
|
||||
p += _enc_int(p, CALL_DEFLECT, OPERATION_VALUE);
|
||||
p += enc_sequence_start(p, &seq1);
|
||||
p += enc_sequence_start(p, &seq2);
|
||||
p += _enc_num_string(p, number, strlen(number), ASN1_TAG_CONTEXT_SPECIFIC);
|
||||
p += enc_sequence_end(p, seq2);
|
||||
p += enc_bool(p, pres);
|
||||
p += enc_sequence_end(p, seq1);
|
||||
|
||||
*body_len = p - &body_len[1];
|
||||
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************/
|
||||
/*** FACILITY STUFF ***/
|
||||
/**********************/
|
||||
|
||||
|
||||
/* IE_FACILITY */
|
||||
void enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len, int nt, struct misdn_bchannel *bc)
|
||||
static void enc_ie_facility (__u8 **ntmode, msg_t *msg, __u8 *facility, int facility_len, struct misdn_bchannel *bc)
|
||||
{
|
||||
unsigned char *p;
|
||||
Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
|
||||
int l;
|
||||
__u8 *ie_fac;
|
||||
|
||||
Q931_info_t *qi;
|
||||
|
||||
if (!facility || facility_len<=0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
l = facility_len;
|
||||
p = msg_put(msg, l+2);
|
||||
if (nt)
|
||||
*ntmode = p+1;
|
||||
else
|
||||
qi->QI_ELEMENT(facility) = p - (unsigned char *)qi - sizeof(Q931_info_t);
|
||||
p[0] = IE_FACILITY;
|
||||
p[1] = l;
|
||||
memcpy(p+2, facility, facility_len);
|
||||
}
|
||||
|
||||
|
||||
/* facility for siemens CENTEX (known parts implemented only) */
|
||||
void enc_ie_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup, int nt, struct misdn_bchannel *bc)
|
||||
{
|
||||
unsigned char centrex[256];
|
||||
int i = 0;
|
||||
|
||||
if (!cnip)
|
||||
return;
|
||||
|
||||
/* centrex facility */
|
||||
centrex[i++] = FACILITY_CENTREX;
|
||||
centrex[i++] = CENTREX_ID;
|
||||
|
||||
/* cnip */
|
||||
if (strlen((char *)cnip) > 15)
|
||||
{
|
||||
/* if (options.deb & DEBUG_PORT) */
|
||||
cb_log(1,0,"%s: CNIP/CONP text too long (max 13 chars), cutting.\n", __FUNCTION__);
|
||||
cnip[15] = '\0';
|
||||
}
|
||||
/* dunno what the 8 bytes mean */
|
||||
if (setup)
|
||||
{
|
||||
centrex[i++] = 0x17;
|
||||
centrex[i++] = 0x02;
|
||||
centrex[i++] = 0x02;
|
||||
centrex[i++] = 0x44;
|
||||
centrex[i++] = 0x18;
|
||||
centrex[i++] = 0x02;
|
||||
centrex[i++] = 0x01;
|
||||
centrex[i++] = 0x09;
|
||||
} else
|
||||
{
|
||||
centrex[i++] = 0x18;
|
||||
centrex[i++] = 0x02;
|
||||
centrex[i++] = 0x02;
|
||||
centrex[i++] = 0x81;
|
||||
centrex[i++] = 0x09;
|
||||
centrex[i++] = 0x02;
|
||||
centrex[i++] = 0x01;
|
||||
centrex[i++] = 0x0a;
|
||||
}
|
||||
|
||||
centrex[i++] = 0x80;
|
||||
centrex[i++] = strlen((char *)cnip);
|
||||
strcpy((char *)(¢rex[i]), (char *)cnip);
|
||||
i += strlen((char *)cnip);
|
||||
cb_log(4,0," cnip='%s'\n", cnip);
|
||||
|
||||
/* encode facility */
|
||||
enc_ie_facility(ntmode, msg, centrex, i, nt , bc);
|
||||
}
|
||||
|
||||
void dec_ie_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *centrex, int facility_len, unsigned char *cnip, int cnip_len, int nt, struct misdn_bchannel *bc)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
*cnip = '\0';
|
||||
|
||||
if (facility_len >= 2)
|
||||
{
|
||||
if (centrex[i++] != FACILITY_CENTREX)
|
||||
return;
|
||||
if (centrex[i++] != CENTREX_ID)
|
||||
return;
|
||||
}
|
||||
|
||||
/* loop sub IEs of facility */
|
||||
while(facility_len > i+1)
|
||||
{
|
||||
if (centrex[i+1]+i+1 > facility_len)
|
||||
{
|
||||
printf("%s: ERROR: short read of centrex facility.\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
switch(centrex[i])
|
||||
{
|
||||
case 0x80:
|
||||
strnncpy(cnip, ¢rex[i+2], centrex[i+1], cnip_len);
|
||||
cb_log(4,0," CENTREX cnip='%s'\n", cnip);
|
||||
break;
|
||||
}
|
||||
i += 1+centrex[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* facility for CALL Deflect (known parts implemented only) */
|
||||
void enc_ie_facility_calldeflect(unsigned char **ntmode, msg_t *msg, unsigned char *nr, int nt, struct misdn_bchannel *bc)
|
||||
{
|
||||
unsigned char fac[256];
|
||||
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
int len = strlen(nr);
|
||||
/* calldeflect facility */
|
||||
|
||||
/* cnip */
|
||||
if (strlen((char *)nr) > 15)
|
||||
{
|
||||
/* if (options.deb & DEBUG_PORT) */
|
||||
cb_log(1,0,"%s: NR text too long (max 13 chars), cutting.\n", __FUNCTION__);
|
||||
nr[15] = '\0';
|
||||
}
|
||||
|
||||
fac[0]=FACILITY_CALLDEFLECT; // ..
|
||||
fac[1]=CALLDEFLECT_ID;
|
||||
fac[2]=0x0f + len; // strlen destination + 15 = 26
|
||||
fac[3]=0x02;
|
||||
fac[4]=0x01;
|
||||
//fac[5]=0x70;
|
||||
fac[5]=0x09;
|
||||
fac[6]=0x02;
|
||||
fac[7]=0x01;
|
||||
fac[8]=0x0d;
|
||||
fac[9]=0x30;
|
||||
fac[10]=0x07 + len; // strlen destination + 7 = 18
|
||||
fac[11]=0x30; // ...hm 0x30
|
||||
fac[12]=0x02+ len; // strlen destination + 2
|
||||
fac[13]=0x80; // CLIP
|
||||
fac[14]= len; // strlen destination
|
||||
|
||||
memcpy((unsigned char *)fac+15,nr,len);
|
||||
fac[15+len]=0x01; //sending complete
|
||||
fac[16+len]=0x01;
|
||||
fac[17+len]=0x80;
|
||||
|
||||
enc_ie_facility(ntmode, msg, fac, 17+len +1 , nt , bc);
|
||||
}
|
||||
|
||||
|
||||
void dec_ie_facility_calldeflect(unsigned char *p, Q931_info_t *qi, unsigned char *fac, int fac_len, unsigned char *cd_nr, int nt, struct misdn_bchannel *bc)
|
||||
{
|
||||
*cd_nr = '\0';
|
||||
|
||||
if (fac_len >= 15)
|
||||
{
|
||||
if (fac[0] != FACILITY_CALLDEFLECT)
|
||||
return;
|
||||
if (fac[1] != CALLDEFLECT_ID)
|
||||
return;
|
||||
ie_fac = msg_put(msg, facility_len + 2);
|
||||
if (bc->nt) {
|
||||
*ntmode = ie_fac + 1;
|
||||
} else {
|
||||
cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n");
|
||||
return ;
|
||||
qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
|
||||
qi->QI_ELEMENT(facility) = ie_fac - (__u8 *)qi - sizeof(Q931_info_t);
|
||||
}
|
||||
|
||||
ie_fac[0] = IE_FACILITY;
|
||||
ie_fac[1] = facility_len;
|
||||
memcpy(ie_fac + 2, facility, facility_len);
|
||||
|
||||
|
||||
{
|
||||
int dest_len=fac[2]-0x0f;
|
||||
|
||||
if (dest_len <0 || dest_len > 15) {
|
||||
cb_log(1,bc->port, "IE is garbage: FAC_CALLDEFLECT\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
if (fac_len < 15+dest_len) {
|
||||
cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
memcpy(cd_nr, &fac[15],dest_len);
|
||||
cd_nr[dest_len]=0;
|
||||
|
||||
cb_log(5,bc->port, "--> IE CALLDEFLECT NR: %s\n",cd_nr);
|
||||
}
|
||||
FAC_DUMP(ie_fac, facility_len + 2, bc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc)
|
||||
void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc)
|
||||
{
|
||||
__u8 facility[256];
|
||||
int len;
|
||||
|
||||
switch (type) {
|
||||
case FACILITY_CENTREX:
|
||||
{
|
||||
int setup=0;
|
||||
enc_ie_facility_centrex(ntmsg, msg, fac.cnip, setup, bc->nt, bc);
|
||||
}
|
||||
break;
|
||||
case FACILITY_CALLDEFLECT:
|
||||
enc_ie_facility_calldeflect(ntmsg, msg, fac.calldeflect_nr, bc->nt, bc);
|
||||
len = enc_fac_calldeflect(facility, fac.calldeflect_nr, 1);
|
||||
enc_ie_facility(ntmsg, msg, facility, len, bc);
|
||||
break;
|
||||
case FACILITY_CENTREX:
|
||||
case FACILITY_NONE:
|
||||
break;
|
||||
default:
|
||||
cb_log(1,0,"Don't know how handle this facility: %d\n", type);
|
||||
}
|
||||
}
|
||||
|
||||
void fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc)
|
||||
{
|
||||
int i, fac_len=0;
|
||||
unsigned char facility[256];
|
||||
/*
|
||||
** Facility Decoding
|
||||
*/
|
||||
|
||||
if (!bc->nt)
|
||||
{
|
||||
p = NULL;
|
||||
static int dec_fac_calldeflect (__u8 *p, int len, struct misdn_bchannel *bc)
|
||||
{
|
||||
__u8 *end = p + len;
|
||||
int offset,
|
||||
pres;
|
||||
|
||||
if ((offset = dec_sequence(p, end)) < 0)
|
||||
return -1;
|
||||
p += offset;
|
||||
|
||||
if ((offset = dec_sequence(p, end)) < 0)
|
||||
return -1;
|
||||
p += offset;
|
||||
|
||||
if ((offset = dec_num_string(p, end, bc->fac.calldeflect_nr)) < 0)
|
||||
return -1;
|
||||
p += offset;
|
||||
|
||||
if ((offset = dec_bool(p, end, &pres)) < 0)
|
||||
return -1;
|
||||
|
||||
cb_log(0, 0, "CALLDEFLECT: dest:%s pres:%s (not implemented yet)\n", bc->fac.calldeflect_nr, pres ? "yes" : "no");
|
||||
bc->fac_type = FACILITY_CALLDEFLECT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fac_dec (__u8 *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc)
|
||||
{
|
||||
int len,
|
||||
offset,
|
||||
inner_len,
|
||||
invoke_id,
|
||||
op_tag,
|
||||
op_val;
|
||||
__u8 *end,
|
||||
*begin = p;
|
||||
|
||||
if (!bc->nt) {
|
||||
if (qi->QI_ELEMENT(facility))
|
||||
p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
|
||||
p = (__u8 *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
|
||||
else
|
||||
p = NULL;
|
||||
}
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
fac_len = p[0] & 0xff;
|
||||
|
||||
memcpy(facility, p+1, fac_len);
|
||||
|
||||
switch(facility[0]) {
|
||||
case FACILITY_CENTREX:
|
||||
{
|
||||
int cnip_len=15;
|
||||
|
||||
dec_ie_facility_centrex(p, qi,facility, fac_len, fac->cnip, cnip_len, bc->nt, bc);
|
||||
|
||||
*type=FACILITY_CENTREX;
|
||||
offset = dec_len (p, &len);
|
||||
if (offset < 0) {
|
||||
cb_log(0, bc->port, "Could not decode FACILITY: dec_len failed!\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case FACILITY_CALLDEFLECT:
|
||||
dec_ie_facility_calldeflect(p, qi,facility, fac_len, fac->calldeflect_nr, bc->nt, bc);
|
||||
p += offset;
|
||||
end = p + len;
|
||||
|
||||
*type=FACILITY_CALLDEFLECT;
|
||||
FAC_DUMP(p, len, bc);
|
||||
|
||||
if (len < 3 || p[0] != SUPPLEMENTARY_SERVICE || p[1] != INVOKE) {
|
||||
cb_log(0, bc->port, "Could not decode FACILITY: invalid or not supported!\n");
|
||||
return;
|
||||
}
|
||||
p += 2;
|
||||
|
||||
offset = dec_len (p, &inner_len);
|
||||
if (offset < 0) {
|
||||
cb_log(0, bc->port, "Could not decode FACILITY: failed parsing inner length!\n");
|
||||
return;
|
||||
}
|
||||
p += offset;
|
||||
|
||||
offset = dec_int (p, end, &invoke_id);
|
||||
if (offset < 0) {
|
||||
cb_log(0, bc->port, "Could not decode FACILITY: failed parsing invoke identifier!\n");
|
||||
return;
|
||||
}
|
||||
p += offset;
|
||||
|
||||
offset = _dec_int (p, end, &op_val, &op_tag);
|
||||
if (offset < 0) {
|
||||
cb_log(0, bc->port, "Could not decode FACILITY: failed parsing operation value!\n");
|
||||
return;
|
||||
}
|
||||
p += offset;
|
||||
|
||||
if (op_tag != OPERATION_VALUE || offset != 3) {
|
||||
cb_log(0, bc->port, "Could not decode FACILITY: operation value tag 0x%x unknown!\n", op_tag);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op_val) {
|
||||
case CALL_DEFLECT:
|
||||
cb_log(0, bc->port, "FACILITY: Call Deflect\n");
|
||||
dec_fac_calldeflect(p, len - (p - begin) + 1, bc);
|
||||
break;
|
||||
case AOC:
|
||||
cb_log(0, bc->port, "FACILITY: AOC\n");
|
||||
break;
|
||||
default:
|
||||
cb_log(3, bc->port, "Unknown Facility received: ");
|
||||
i = 0;
|
||||
while(i < fac_len)
|
||||
{
|
||||
cb_log(3, bc->port, " %02x", facility[i]);
|
||||
i++;
|
||||
}
|
||||
cb_log(3, bc->port, " facility\n");
|
||||
|
||||
*type=FACILITY_NONE;
|
||||
cb_log(0, bc->port, "FACILITY unknown: operation value 0x%x, ignoring ...\n", op_val);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*** FACILITY END **/
|
||||
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#ifndef FAC_H
|
||||
#define FAC_H
|
||||
#ifndef __FAC_H__
|
||||
#define __FAC_H__
|
||||
|
||||
void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc);
|
||||
#include "isdn_lib_intern.h"
|
||||
|
||||
void fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc);
|
||||
void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc);
|
||||
void fac_dec (__u8 *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -2589,6 +2589,7 @@ int handle_frm(msg_t *msg)
|
||||
|
||||
bc=find_bc_by_l3id(stack, frm->dinfo);
|
||||
|
||||
handle_frm_bc:
|
||||
if (bc ) {
|
||||
enum event_e event = isdn_msg_get_event(msgs_g, msg, 0);
|
||||
enum event_response_e response=RESPONSE_OK;
|
||||
@@ -2644,7 +2645,13 @@ int handle_frm(msg_t *msg)
|
||||
#endif
|
||||
|
||||
} else {
|
||||
cb_log(0, stack->port, "NO BC FOR STACK\n");
|
||||
cb_log(0, stack->port, " --> Didn't find BC so temporarly creating dummy BC (l3id:%x) on this port.\n", frm->dinfo);
|
||||
struct misdn_bchannel dummybc;
|
||||
memset (&dummybc,0,sizeof(dummybc));
|
||||
dummybc.port=stack->port;
|
||||
dummybc.l3_id=frm->dinfo;
|
||||
bc=&dummybc;
|
||||
goto handle_frm_bc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4023,6 +4030,32 @@ void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2)
|
||||
mISDN_write(glob_mgr->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* allow live control of channel parameters
|
||||
*/
|
||||
void isdn_lib_update_rxgain (struct misdn_bchannel *bc)
|
||||
{
|
||||
manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain);
|
||||
}
|
||||
|
||||
void isdn_lib_update_txgain (struct misdn_bchannel *bc)
|
||||
{
|
||||
manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain);
|
||||
}
|
||||
|
||||
void isdn_lib_update_ec (struct misdn_bchannel *bc)
|
||||
{
|
||||
if (bc->ec_enable)
|
||||
manager_ec_enable(bc);
|
||||
else
|
||||
manager_ec_disable(bc);
|
||||
}
|
||||
|
||||
void isdn_lib_stop_dtmf (struct misdn_bchannel *bc)
|
||||
{
|
||||
manager_ph_control(bc, DTMF_TONE_STOP, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* send control information to the channel (dsp-module)
|
||||
*/
|
||||
|
@@ -406,6 +406,10 @@ int misdn_lib_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len);
|
||||
|
||||
void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2);
|
||||
|
||||
void isdn_lib_update_rxgain (struct misdn_bchannel *bc);
|
||||
void isdn_lib_update_txgain (struct misdn_bchannel *bc);
|
||||
void isdn_lib_update_ec (struct misdn_bchannel *bc);
|
||||
void isdn_lib_stop_dtmf (struct misdn_bchannel *bc);
|
||||
|
||||
int misdn_lib_port_restart(int port);
|
||||
int misdn_lib_get_port_info(int port);
|
||||
|
@@ -879,8 +879,7 @@ msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc
|
||||
|
||||
void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
|
||||
{
|
||||
//#define FACILITY_DECODE
|
||||
#ifdef FACILITY_DECODE
|
||||
#ifdef FACILITY_DEBUG
|
||||
int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
|
||||
FACILITY_t *facility=(FACILITY_t*)((unsigned long)(msg->data+HEADER_LEN));
|
||||
Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
|
||||
@@ -889,9 +888,7 @@ void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *
|
||||
printf("Parsing FACILITY Msg\n");
|
||||
#endif
|
||||
|
||||
{
|
||||
fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc);
|
||||
}
|
||||
fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ static const struct misdn_cfg_spec port_spec[] = {
|
||||
"\tas well, since chan_misdn has no chance to distinguish if the L1 is down\n"
|
||||
"\tbecause of a lost Link or because the Provider shut it down..." },
|
||||
{ "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "yes", NONE ,
|
||||
"Block this port if we have an alarm on it.\n"
|
||||
"Block this port if we have an alarm on it."
|
||||
"default: yes\n" },
|
||||
{ "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE,
|
||||
"Set this to yes, if you want to bridge a mISDN data channel to\n"
|
||||
@@ -212,7 +212,7 @@ static const struct misdn_cfg_spec port_spec[] = {
|
||||
{ "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE,
|
||||
"Enable this to prevent chan_misdn to generate the dialtone\n"
|
||||
"\tThis makes only sense together with the always_immediate=yes option\n"
|
||||
"\tto generate your own dialtone with Playtones or so.\n"},
|
||||
"\tto generate your own dialtone with Playtones or so."},
|
||||
{ "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
|
||||
"Enable this if you want callers which called exactly the base\n"
|
||||
"\tnumber (so no extension is set) to jump into the s extension.\n"
|
||||
@@ -221,7 +221,7 @@ static const struct misdn_cfg_spec port_spec[] = {
|
||||
{ "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE,
|
||||
"Enable this if we should produce DTMF Tones ourselves." },
|
||||
{ "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE,
|
||||
"Enable this to have support for hold and retrieve.\n" },
|
||||
"Enable this to have support for hold and retrieve." },
|
||||
{ "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE,
|
||||
"Disable this if you don't mind correct handling of Progress Indicators." },
|
||||
{ "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE,
|
||||
@@ -272,7 +272,19 @@ static const struct misdn_cfg_spec port_spec[] = {
|
||||
"Defines the maximum amount of outgoing calls per port for this group\n"
|
||||
"\texceeding calls will be rejected" },
|
||||
{ "faxdetect", MISDN_CFG_FAXDETECT, MISDN_CTYPE_STR, "no", NONE,
|
||||
"Context to jump into if we detect an incoming fax." },
|
||||
"Setup fax detection:\n"
|
||||
"\t no - no fax detection\n"
|
||||
"\t incoming - fax detection for incoming calls\n"
|
||||
"\t outgoing - fax detection for outgoing calls\n"
|
||||
"\t both - fax detection for incoming and outgoing calls\n"
|
||||
"\tAdd +nojump to your value (i.e. faxdetect=both+nojump) if you don't want to jump into the\n"
|
||||
"\tfax-extension but still want to detect the fax and prepare the channel for fax transfer." },
|
||||
{ "faxdetect_timeout", MISDN_CFG_FAXDETECT_TIMEOUT, MISDN_CTYPE_INT, "5", NONE,
|
||||
"Number of seconds the fax detection should do its job. After the given period of time,\n"
|
||||
"\twe assume that it's not a fax call and save some CPU time by turning off fax detection.\n"
|
||||
"\tSet this to 0 if you don't want a timeout (never stop detecting)." },
|
||||
{ "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
|
||||
"Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." },
|
||||
{ "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4,
|
||||
"Watches the layer 1. If the layer 1 is down, it tries to\n"
|
||||
"\tget it up. The timeout is given in seconds. with 0 as value it\n"
|
||||
@@ -342,28 +354,41 @@ static ast_mutex_t config_mutex;
|
||||
"Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \
|
||||
})
|
||||
|
||||
static void _enum_array_map (void)
|
||||
static int _enum_array_map (void)
|
||||
{
|
||||
int i, j;
|
||||
int i, j, ok;
|
||||
|
||||
for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
|
||||
if (i == MISDN_CFG_PTP)
|
||||
continue;
|
||||
ok = 0;
|
||||
for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
|
||||
if (port_spec[j].elem == i) {
|
||||
map[i] = j;
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (port section) has no corresponding element in the config struct!\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
|
||||
ok = 0;
|
||||
for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
|
||||
if (gen_spec[j].elem == i) {
|
||||
map[i] = j;
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (general section) has no corresponding element in the config struct!\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_cfg_position (char *name, int type)
|
||||
@@ -998,7 +1023,7 @@ void misdn_cfg_destroy (void)
|
||||
ast_mutex_destroy(&config_mutex);
|
||||
}
|
||||
|
||||
void misdn_cfg_init (int this_max_ports)
|
||||
int misdn_cfg_init (int this_max_ports)
|
||||
{
|
||||
char config[] = "misdn.conf";
|
||||
char *cat, *p;
|
||||
@@ -1007,8 +1032,8 @@ void misdn_cfg_init (int this_max_ports)
|
||||
struct ast_variable *v;
|
||||
|
||||
if (!(cfg = AST_LOAD_CFG(config))) {
|
||||
ast_log(LOG_WARNING,"no misdn.conf ?\n");
|
||||
return;
|
||||
ast_log(LOG_WARNING, "missing file: misdn.conf\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_mutex_init(&config_mutex);
|
||||
@@ -1018,6 +1043,9 @@ void misdn_cfg_init (int this_max_ports)
|
||||
if (this_max_ports) {
|
||||
/* this is the first run */
|
||||
max_ports = this_max_ports;
|
||||
map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int));
|
||||
if (_enum_array_map())
|
||||
return -1;
|
||||
p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
|
||||
+ (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
|
||||
port_cfg = (union misdn_cfg_pt **)p;
|
||||
@@ -1028,8 +1056,6 @@ void misdn_cfg_init (int this_max_ports)
|
||||
}
|
||||
general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
|
||||
ptp = (int *)calloc(max_ports + 1, sizeof(int));
|
||||
map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int));
|
||||
_enum_array_map();
|
||||
}
|
||||
else {
|
||||
/* misdn reload */
|
||||
@@ -1044,18 +1070,20 @@ void misdn_cfg_init (int this_max_ports)
|
||||
|
||||
while(cat) {
|
||||
v = ast_variable_browse(cfg, cat);
|
||||
if (!strcasecmp(cat,"general")) {
|
||||
if (!strcasecmp(cat, "general")) {
|
||||
_build_general_config(v);
|
||||
} else {
|
||||
_build_port_config(v, cat);
|
||||
}
|
||||
cat = ast_category_browse(cfg,cat);
|
||||
cat = ast_category_browse(cfg, cat);
|
||||
}
|
||||
|
||||
_fill_defaults();
|
||||
|
||||
misdn_cfg_unlock();
|
||||
AST_DESTROY_CFG(cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user