* 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:
Nadi Sarrar
2006-08-08 18:13:40 +00:00
parent bec806f25f
commit 958f3726f1
11 changed files with 715 additions and 395 deletions

View File

@@ -43,8 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <signal.h> #include <signal.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/ipc.h> #include <semaphore.h>
#include <sys/sem.h>
#include "asterisk/channel.h" #include "asterisk/channel.h"
#include "asterisk/config.h" #include "asterisk/config.h"
@@ -157,7 +156,9 @@ struct chan_list {
char ast_rd_buf[4096]; char ast_rd_buf[4096];
struct ast_frame frame; 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 faxhandled;
int ast_dsp; 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, ... */ /* the main schedule context for stuff like l1 watcher, overlap dial, ... */
static struct sched_context *misdn_tasks = NULL; static struct sched_context *misdn_tasks = NULL;
static pthread_t misdn_tasks_thread; static pthread_t misdn_tasks_thread;
static int misdn_tasks_semid;
static void chan_misdn_log(int level, int port, char *tmpl, ...); 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) { switch (bc->fac_type) {
case FACILITY_CALLDEFLECT: 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); bc->fac.calldeflect_nr);
break; break;
case FACILITY_CENTREX: case FACILITY_CENTREX:
chan_misdn_log(2,bc->port," --> centrex: %s\n", chan_misdn_log(0,bc->port," --> centrex: %s\n",
bc->fac.cnip); bc->fac.cnip);
break; break;
default: 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; int wait;
struct sigaction sa; struct sigaction sa;
struct sembuf semb = {
.sem_num = 0,
.sem_op = 1,
.sem_flg = 0
};
sa.sa_handler = sighandler; sa.sa_handler = sighandler;
sa.sa_flags = SA_NODEFER; sa.sa_flags = SA_NODEFER;
@@ -465,7 +460,7 @@ static void* misdn_tasks_thread_func (void *data)
sigaddset(&sa.sa_mask, SIGUSR1); sigaddset(&sa.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR1, &sa, NULL);
semop(misdn_tasks_semid, &semb, 1); sem_post((sem_t *)data);
while (1) { while (1) {
wait = ast_sched_wait(misdn_tasks); wait = ast_sched_wait(misdn_tasks);
@@ -480,44 +475,21 @@ static void* misdn_tasks_thread_func (void *data)
static void misdn_tasks_init (void) static void misdn_tasks_init (void)
{ {
key_t key; sem_t blocker;
union { int i = 5;
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
};
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 (sem_init(&blocker, 0, 0)) {
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) {
perror("chan_misdn: Failed to initialize semaphore!"); perror("chan_misdn: Failed to initialize semaphore!");
exit(1); exit(1);
} }
chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
misdn_tasks = sched_context_create(); misdn_tasks = sched_context_create();
pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, NULL); pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
semop(misdn_tasks_semid, &semb, 1); while (sem_wait(&blocker) && --i);
semctl(misdn_tasks_semid, 0, IPC_RMID, semu); sem_destroy(&blocker);
} }
static void misdn_tasks_destroy (void) 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); 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; int hdlc=0;
misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); 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) { if ( orig == ORG_AST) {
misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(int)); 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]; char callerid[BUFFERSIZE+1];
misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE); 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; ch->overlap_dial = 0;
} else { /** ORIGINATOR MISDN **/ } 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)); misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int));
debug_numplan(port, bc->cpnnumplan,"CTON"); 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); ast_mutex_init(&ch->overlap_tv_lock);
} /* ORIG MISDN END */ } /* 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; 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 *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
{ {
struct ast_frame *f,*f2; struct ast_frame *f,*f2;
if (tmp->trans)
f2=ast_translate(tmp->trans, frame,0); if (tmp->trans) {
else { 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"); chan_misdn_log(0, tmp->bc->port, "No T-Path found\n");
return NULL; 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;
}
}
frame->frametype = AST_FRAME_NULL;
frame->subclass = 0; 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);
}
return frame; 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"); chan_misdn_log(1,0,"misdn_read called without ast\n");
return NULL; 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"); chan_misdn_log(1,0,"misdn_read called without ast->pvt\n");
return NULL; return NULL;
} }
@@ -2539,17 +2559,40 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
tmp->frame.frametype = AST_FRAME_VOICE; tmp->frame.frametype = AST_FRAME_VOICE;
tmp->frame.subclass = AST_FORMAT_ALAW; tmp->frame.subclass = AST_FORMAT_ALAW;
tmp->frame.datalen = len; tmp->frame.datalen = len;
tmp->frame.samples = len ; tmp->frame.samples = len;
tmp->frame.mallocd =0 ; tmp->frame.mallocd = 0;
tmp->frame.offset= 0 ; tmp->frame.offset = 0;
tmp->frame.src = NULL; tmp->frame.src = NULL;
tmp->frame.data = tmp->ast_rd_buf ; tmp->frame.data = tmp->ast_rd_buf;
if (tmp->faxdetect || tmp->ast_dsp ) { if (tmp->faxdetect && !tmp->faxhandled) {
return process_ast_dsp(tmp, &tmp->frame); 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); 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) ) { if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) {
/* Buffered Transmit (triggert by read from isdn side)*/ /* Buffered Transmit (triggert by read from isdn side)*/
if (misdn_jb_fill(ch->jb,frame->data,frame->samples) < 0) { 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_PORT_ALARM:
case EVENT_RETRIEVE: case EVENT_RETRIEVE:
case EVENT_NEW_BC: case EVENT_NEW_BC:
case EVENT_FACILITY:
break; break;
case EVENT_RELEASE_COMPLETE: case EVENT_RELEASE_COMPLETE:
chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n"); 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 ast_channel *bridged=AST_BRIDGED_P(ch->ast);
struct chan_list *ch; struct chan_list *ch;
misdn_lib_send_event(bc, EVENT_DISCONNECT);
if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) { if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
ch=MISDN_ASTERISK_TECH_PVT(bridged); ch=MISDN_ASTERISK_TECH_PVT(bridged);
/*ch->state=MISDN_FACILITY_DEFLECTED;*/ /*ch->state=MISDN_FACILITY_DEFLECTED;*/
@@ -4455,7 +4500,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
break; break;
default: 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; break;
@@ -4550,8 +4595,10 @@ static int load_module(void *mod)
return -1; return -1;
} }
if (misdn_cfg_init(max_ports)) {
misdn_cfg_init(max_ports); ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
return -1;
}
g_config_initialized=1; g_config_initialized=1;
misdn_debug = (int *)malloc(sizeof(int) * (max_ports+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': case 'f':
chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n"); chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
ch->faxdetect=1; ch->faxdetect=1;
misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
break; break;
case 'a': 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->faxdetect || ch->ast_dsp) {
if (!ch->dsp) ch->dsp = ast_dsp_new(); 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->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); if (!ch->trans) ch->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW);

View File

@@ -11,14 +11,14 @@ CFLAGS += -fPIC
endif endif
SOURCES = isdn_lib.c isdn_msg_parser.c SOURCES = isdn_lib.c isdn_msg_parser.c
OBJDIR = . 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),) ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libbnec.so),)
CFLAGS+=-DBEROEC_VERSION=1 CFLAGS+=-DBEROEC_VERSION=1
CFLAGS+=-DWITH_BEROEC CFLAGS+=-DWITH_BEROEC
endif endif
CFLAGS+=-DFACILITY_DEBUG
all: chan_misdn_lib.a all: chan_misdn_lib.a

181
channels/misdn/asn1.c Normal file
View 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
View 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

View File

@@ -75,6 +75,8 @@ enum misdn_cfg_elements {
MISDN_CFG_OVERLAP_DIAL, /* int (bool)*/ MISDN_CFG_OVERLAP_DIAL, /* int (bool)*/
MISDN_CFG_MSNS, /* char[] */ MISDN_CFG_MSNS, /* char[] */
MISDN_CFG_FAXDETECT, /* char[] */ MISDN_CFG_FAXDETECT, /* char[] */
MISDN_CFG_FAXDETECT_CONTEXT, /* char[] */
MISDN_CFG_FAXDETECT_TIMEOUT, /* int */
MISDN_CFG_PTP, /* int (bool) */ MISDN_CFG_PTP, /* int (bool) */
MISDN_CFG_LAST, 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 */ /* 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_reload(void);
void misdn_cfg_destroy(void); void misdn_cfg_destroy(void);

View File

@@ -1,313 +1,267 @@
#include "isdn_lib_intern.h" #include "fac.h"
#include "isdn_lib.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 enum {
#define CALLDEFLECT_ID 0xa1 OPERATION_VALUE = 0x02,
} OPERATION_VALUE_TAG;
/** enum {
This file covers the encoding and decoding of facility messages and VALUE_QUERY = 0x8c,
facility information elements. 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,
fac_enc( char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc) AOC = 0x22,
fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc); } OPERATION_CODE;
Those will either read the union facility or fill it. enum {
Q931_IE_TAG = 0x40,
} ARGUMENT_TAG;
internally, we will have deconding and encoding functions for each facility #ifdef FACILITY_DEBUG
IE. #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)
/* support stuff */
static void strnncpy(unsigned char *dest, unsigned char *src, int len, int dst_len)
{ {
if (len > dst_len-1) int i;
len = dst_len-1; cb_log(0, bc->port, " --- facility dump start. length:%d\n", fac_len);
strncpy((char *)dest, (char *)src, len); for (i = 0; i < fac_len; ++i)
dest[len] = '\0'; 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;
} }
static void enc_ie_facility (__u8 **ntmode, msg_t *msg, __u8 *facility, int facility_len, struct misdn_bchannel *bc)
/**********************/
/*** 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)
{ {
unsigned char *p; __u8 *ie_fac;
Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
int l;
if (!facility || facility_len<=0)
{
return;
}
l = facility_len; Q931_info_t *qi;
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);
}
ie_fac = msg_put(msg, facility_len + 2);
/* facility for siemens CENTEX (known parts implemented only) */ if (bc->nt) {
void enc_ie_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup, int nt, struct misdn_bchannel *bc) *ntmode = ie_fac + 1;
{
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 *)(&centrex[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, &centrex[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;
} else { } else {
cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n"); qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
return ; qi->QI_ELEMENT(facility) = ie_fac - (__u8 *)qi - sizeof(Q931_info_t);
}
{
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);
} }
ie_fac[0] = IE_FACILITY;
ie_fac[1] = facility_len;
memcpy(ie_fac + 2, facility, facility_len);
FAC_DUMP(ie_fac, facility_len + 2, bc);
} }
void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc)
void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc)
{ {
__u8 facility[256];
int len;
switch (type) { switch (type) {
case FACILITY_CENTREX:
{
int setup=0;
enc_ie_facility_centrex(ntmsg, msg, fac.cnip, setup, bc->nt, bc);
}
break;
case FACILITY_CALLDEFLECT: 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; 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) /*
{ ** Facility Decoding
int i, fac_len=0; */
unsigned char facility[256];
if (!bc->nt) static int dec_fac_calldeflect (__u8 *p, int len, struct misdn_bchannel *bc)
{ {
p = NULL; __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)) 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) if (!p)
return; return;
fac_len = p[0] & 0xff;
memcpy(facility, p+1, fac_len); offset = dec_len (p, &len);
if (offset < 0) {
switch(facility[0]) { cb_log(0, bc->port, "Could not decode FACILITY: dec_len failed!\n");
case FACILITY_CENTREX: return;
{
int cnip_len=15;
dec_ie_facility_centrex(p, qi,facility, fac_len, fac->cnip, cnip_len, bc->nt, bc);
*type=FACILITY_CENTREX;
} }
break; p += offset;
case FACILITY_CALLDEFLECT: end = p + len;
dec_ie_facility_calldeflect(p, qi,facility, fac_len, fac->calldeflect_nr, bc->nt, bc);
FAC_DUMP(p, len, bc);
*type=FACILITY_CALLDEFLECT;
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; break;
default: default:
cb_log(3, bc->port, "Unknown Facility received: "); cb_log(0, bc->port, "FACILITY unknown: operation value 0x%x, ignoring ...\n", op_val);
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;
} }
} }
/*** FACILITY END **/

View File

@@ -1,8 +1,10 @@
#ifndef FAC_H #ifndef __FAC_H__
#define 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 #endif

View File

@@ -2589,6 +2589,7 @@ int handle_frm(msg_t *msg)
bc=find_bc_by_l3id(stack, frm->dinfo); bc=find_bc_by_l3id(stack, frm->dinfo);
handle_frm_bc:
if (bc ) { if (bc ) {
enum event_e event = isdn_msg_get_event(msgs_g, msg, 0); enum event_e event = isdn_msg_get_event(msgs_g, msg, 0);
enum event_response_e response=RESPONSE_OK; enum event_response_e response=RESPONSE_OK;
@@ -2602,7 +2603,7 @@ int handle_frm(msg_t *msg)
if(!isdn_get_info(msgs_g,event,0)) if(!isdn_get_info(msgs_g,event,0))
cb_log(0, stack->port, "Unknown Event Ind: Addr:%x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo); cb_log(0, stack->port, "Unknown Event Ind: Addr:%x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo);
else else
response=cb_event(event, bc, glob_mgr->user_data); response=cb_event(event, bc, glob_mgr->user_data);
#if 1 #if 1
if (event == EVENT_SETUP) { if (event == EVENT_SETUP) {
@@ -2644,7 +2645,13 @@ int handle_frm(msg_t *msg)
#endif #endif
} else { } 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); 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) * send control information to the channel (dsp-module)
*/ */

View File

@@ -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 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_port_restart(int port);
int misdn_lib_get_port_info(int port); int misdn_lib_get_port_info(int port);

View File

@@ -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) void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
{ {
//#define FACILITY_DECODE #ifdef FACILITY_DEBUG
#ifdef FACILITY_DECODE
int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
FACILITY_t *facility=(FACILITY_t*)((unsigned long)(msg->data+HEADER_LEN)); FACILITY_t *facility=(FACILITY_t*)((unsigned long)(msg->data+HEADER_LEN));
Q931_info_t *qi=(Q931_info_t*)(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"); printf("Parsing FACILITY Msg\n");
#endif #endif
{ fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc);
fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc);
}
#endif #endif
} }

View File

@@ -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" "\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..." }, "\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_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" }, "default: yes\n" },
{ "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE, { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE,
"Set this to yes, if you want to bridge a mISDN data channel to\n" "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, { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE,
"Enable this to prevent chan_misdn to generate the dialtone\n" "Enable this to prevent chan_misdn to generate the dialtone\n"
"\tThis makes only sense together with the always_immediate=yes option\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, { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
"Enable this if you want callers which called exactly the base\n" "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" "\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, { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE,
"Enable this if we should produce DTMF Tones ourselves." }, "Enable this if we should produce DTMF Tones ourselves." },
{ "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE, { "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, { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE,
"Disable this if you don't mind correct handling of Progress Indicators." }, "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, { "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" "Defines the maximum amount of outgoing calls per port for this group\n"
"\texceeding calls will be rejected" }, "\texceeding calls will be rejected" },
{ "faxdetect", MISDN_CFG_FAXDETECT, MISDN_CTYPE_STR, "no", NONE, { "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, { "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" "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" "\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); \ "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) { for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
if (i == MISDN_CFG_PTP) if (i == MISDN_CFG_PTP)
continue; continue;
ok = 0;
for (j = 0; j < NUM_PORT_ELEMENTS; ++j) { for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
if (port_spec[j].elem == i) { if (port_spec[j].elem == i) {
map[i] = j; map[i] = j;
ok = 1;
break; 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) { for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
ok = 0;
for (j = 0; j < NUM_GEN_ELEMENTS; ++j) { for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
if (gen_spec[j].elem == i) { if (gen_spec[j].elem == i) {
map[i] = j; map[i] = j;
ok = 1;
break; 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) static int get_cfg_position (char *name, int type)
@@ -998,7 +1023,7 @@ void misdn_cfg_destroy (void)
ast_mutex_destroy(&config_mutex); 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 config[] = "misdn.conf";
char *cat, *p; char *cat, *p;
@@ -1007,8 +1032,8 @@ void misdn_cfg_init (int this_max_ports)
struct ast_variable *v; struct ast_variable *v;
if (!(cfg = AST_LOAD_CFG(config))) { if (!(cfg = AST_LOAD_CFG(config))) {
ast_log(LOG_WARNING,"no misdn.conf ?\n"); ast_log(LOG_WARNING, "missing file: misdn.conf\n");
return; return -1;
} }
ast_mutex_init(&config_mutex); ast_mutex_init(&config_mutex);
@@ -1018,6 +1043,9 @@ void misdn_cfg_init (int this_max_ports)
if (this_max_ports) { if (this_max_ports) {
/* this is the first run */ /* this is the first run */
max_ports = this_max_ports; 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 *) p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
+ (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt)); + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
port_cfg = (union misdn_cfg_pt **)p; 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); general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
ptp = (int *)calloc(max_ports + 1, sizeof(int)); ptp = (int *)calloc(max_ports + 1, sizeof(int));
map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int));
_enum_array_map();
} }
else { else {
/* misdn reload */ /* misdn reload */
@@ -1044,18 +1070,20 @@ void misdn_cfg_init (int this_max_ports)
while(cat) { while(cat) {
v = ast_variable_browse(cfg, cat); v = ast_variable_browse(cfg, cat);
if (!strcasecmp(cat,"general")) { if (!strcasecmp(cat, "general")) {
_build_general_config(v); _build_general_config(v);
} else { } else {
_build_port_config(v, cat); _build_port_config(v, cat);
} }
cat = ast_category_browse(cfg,cat); cat = ast_category_browse(cfg, cat);
} }
_fill_defaults(); _fill_defaults();
misdn_cfg_unlock(); misdn_cfg_unlock();
AST_DESTROY_CFG(cfg); AST_DESTROY_CFG(cfg);
return 0;
} }