* first bits of decoding facility information elements
authorNadi Sarrar <ns@beronet.com>
Tue, 8 Aug 2006 18:13:40 +0000 (18:13 +0000)
committerNadi Sarrar <ns@beronet.com>
Tue, 8 Aug 2006 18:13:40 +0000 (18:13 +0000)
* 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

channels/chan_misdn.c
channels/misdn/Makefile
channels/misdn/asn1.c [new file with mode: 0644]
channels/misdn/asn1.h [new file with mode: 0644]
channels/misdn/chan_misdn_config.h
channels/misdn/fac.c
channels/misdn/fac.h
channels/misdn/isdn_lib.c
channels/misdn/isdn_lib.h
channels/misdn/isdn_msg_parser.c
channels/misdn_config.c

index 72a26c8..213b648 100644 (file)
@@ -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
-       };
-       
-       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);
-       }
+       sem_t blocker;
+       int i = 5;
 
-       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);
        }
 
+       chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
+       
        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);
-       semctl(misdn_tasks_semid, 0, IPC_RMID, semu);
+       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;
-               }
-       }
 
-       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;
 }
 
@@ -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 ;
-       
-       if (tmp->faxdetect || tmp->ast_dsp ) {
-               return process_ast_dsp(tmp, &tmp->frame);
+       tmp->frame.data = tmp->ast_rd_buf;
+
+       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);
index ba4a129..febca51 100644 (file)
@@ -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 
 
diff --git a/channels/misdn/asn1.c b/channels/misdn/asn1.c
new file mode 100644 (file)
index 0000000..80dcacd
--- /dev/null
@@ -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;
+}
diff --git a/channels/misdn/asn1.h b/channels/misdn/asn1.h
new file mode 100644 (file)
index 0000000..d3bdae3
--- /dev/null
@@ -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
+
index 4828261..04376c3 100644 (file)
@@ -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);
 
index 383a60f..19bfbf7 100644 (file)
 
-#include "isdn_lib_intern.h"
-#include "isdn_lib.h"
-
-#include "string.h"
-
-
-
-
-#define CENTREX_ID      0xa1
-#define CALLDEFLECT_ID      0xa1
-
-/**
-   This file covers the encoding and decoding of facility messages and
-   facility information elements.
-
-   There will be 2 Functions as Interface:
-   
-   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);
-
-   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)
+#include "fac.h"
+#include "asn1.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;
+
+enum {
+       OPERATION_VALUE                 = 0x02,
+} OPERATION_VALUE_TAG;
+
+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,
+
+       /* not from document */
+       CALL_DEFLECT                    = 0x0d,
+       AOC                                     = 0x22,
+} OPERATION_CODE;
+
+enum {
+       Q931_IE_TAG                     = 0x40,
+} ARGUMENT_TAG;
+
+#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
+*/
 
-
-
-/**********************/
-/*** 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 int enc_fac_calldeflect (__u8 *dest, char *number, int pres)
 {
-       unsigned char *p;
-       Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
-       int l;
-
-
-       if (!facility || facility_len<=0)
-       {
-               return;
-       }
-
+       __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);
        
-       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);
+       *body_len = p - &body_len[1];
+       
+       return p - dest;
 }
 
-
-/* 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)
+static void enc_ie_facility (__u8 **ntmode, msg_t *msg, __u8 *facility, int facility_len, struct misdn_bchannel *bc)
 {
-       unsigned char centrex[256];
-       int i = 0;
-
-       if (!cnip)
-               return;
-
-       /* centrex facility */
-       centrex[i++] = FACILITY_CENTREX;
-       centrex[i++] = CENTREX_ID;
+       __u8 *ie_fac;
+       
+       Q931_info_t *qi;
 
-       /* 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;
+       ie_fac = msg_put(msg, facility_len + 2);
+       if (bc->nt) {
+               *ntmode = ie_fac + 1;
+       } else {
+               qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
+               qi->QI_ELEMENT(facility) = ie_fac - (__u8 *)qi - sizeof(Q931_info_t);
        }
 
-       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);
+       ie_fac[0] = IE_FACILITY;
+       ie_fac[1] = facility_len;
+       memcpy(ie_fac + 2, facility, facility_len);
 
-       /* encode facility */
-       enc_ie_facility(ntmode, msg, centrex, i, nt , bc);
+       FAC_DUMP(ie_fac, facility_len + 2, 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)
+void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type,  union facility fac, struct misdn_bchannel *bc)
 {
+       __u8 facility[256];
+       int len;
 
-       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];
+       switch (type) {
+       case FACILITY_CALLDEFLECT:
+               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;
        }
 }
 
+/*
+** Facility Decoding
+*/
 
+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;
 
-/* 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 ((offset = dec_sequence(p, end)) < 0)
+               return -1;
+       p += offset;
        
-       if (!nr)
-               return;
+       if ((offset = dec_num_string(p, end, bc->fac.calldeflect_nr)) < 0)
+               return -1;
+       p += offset;
 
-       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);
-}
+       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 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)
+void fac_dec (__u8 *p, Q931_info_t *qi, enum facility_type *type,  union facility *fac, struct misdn_bchannel *bc)
 {
-       *cd_nr = '\0';
-       
-       if (fac_len >= 15)
-       {
-               if (fac[0] != FACILITY_CALLDEFLECT)
-                       return;
-               if (fac[1] != CALLDEFLECT_ID)
-                       return;
-       } else {
-               cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n");
-               return ;
-       }
-       
-       
-       
-       {
-               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);
+       int len,
+               offset,
+               inner_len,
+               invoke_id,
+               op_tag,
+               op_val;
+       __u8 *end,
+                                 *begin = p;
+
+       if (!bc->nt) {
+               if (qi->QI_ELEMENT(facility))
+                       p = (__u8 *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
+               else
+                       p = NULL;
        }
-}
+       if (!p)
+               return;
 
+       offset = dec_len (p, &len);
+       if (offset < 0) {
+               cb_log(0, bc->port, "Could not decode FACILITY: dec_len failed!\n");
+               return;
+       }
+       p += offset;
+       end = p + len;
 
+       FAC_DUMP(p, len, bc);
 
-void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type,  union facility fac, struct misdn_bchannel *bc)
-{
-       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);
-               break;
-       default:
-               cb_log(1,0,"Don't know how handle this facility: %d\n", type);
+       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;
 
-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];
+       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;
 
-       if (!bc->nt)
-       {
-               p = NULL;
-               if (qi->QI_ELEMENT(facility))
-                       p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
+       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;
        }
-       if (!p)
+       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;
-       
-       fac_len = p[0] & 0xff;
+       }
+       p += offset;
 
-       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;
+       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;
        }
-       break;
-       case FACILITY_CALLDEFLECT:
-               dec_ie_facility_calldeflect(p, qi,facility, fac_len, fac->calldeflect_nr,  bc->nt, bc);
-               
-               *type=FACILITY_CALLDEFLECT;
+
+       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 **/
-
index acc41f1..da63299 100644 (file)
@@ -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
+
index 8209df9..8b6e08f 100644 (file)
@@ -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;
@@ -2602,7 +2603,7 @@ int handle_frm(msg_t *msg)
       
                        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);
-                       else 
+                       else
                                response=cb_event(event, bc, glob_mgr->user_data);
 #if 1
                        if (event == EVENT_SETUP) {
@@ -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;
                }
        }
 
@@ -4024,6 +4031,32 @@ void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2)
 }
 
 /*
+ * 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)
  */
 void manager_ph_control_block(struct misdn_bchannel *bc, int c1, void *c2, int c2_len)
index 3673baf..5bb82d4 100644 (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 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);
index ae8aa76..5ee7f6f 100644 (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) 
 {
-//#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 
 
 }
index 48be306..5bca76e 100644 (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"
                "\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;
 }