diff options
author | root <root@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-17 22:04:22 +0000 |
---|---|---|
committer | root <root@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-17 22:04:22 +0000 |
commit | b1742b89db7d0f0335f59a3b701895683e0f3d2f (patch) | |
tree | 4a433ea2f38280b587e2d14eb297ea95d2d710dd /channels | |
parent | 62245abb42c1e23df30e8bb1b80920750fcfc7b6 (diff) |
automerge commit
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.2-netsec@40332 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/Makefile | 18 | ||||
-rw-r--r-- | channels/chan_misdn.c | 3227 | ||||
-rw-r--r-- | channels/chan_misdn_config.c | 1083 | ||||
-rw-r--r-- | channels/misdn/Makefile | 58 | ||||
-rw-r--r-- | channels/misdn/chan_misdn_config.h | 29 | ||||
-rw-r--r-- | channels/misdn/fac.c | 313 | ||||
-rw-r--r-- | channels/misdn/fac.h | 8 | ||||
-rw-r--r-- | channels/misdn/ie.c | 353 | ||||
-rw-r--r-- | channels/misdn/isdn_lib.c | 2791 | ||||
-rw-r--r-- | channels/misdn/isdn_lib.h | 175 | ||||
-rw-r--r-- | channels/misdn/isdn_lib_intern.h | 24 | ||||
-rw-r--r-- | channels/misdn/isdn_msg_parser.c | 384 | ||||
-rw-r--r-- | channels/misdn/mISDN.patch | 2500 | ||||
-rw-r--r-- | channels/misdn/portinfo.c | 197 | ||||
-rw-r--r-- | channels/misdn_config.c | 784 |
15 files changed, 5455 insertions, 6489 deletions
diff --git a/channels/Makefile b/channels/Makefile index 10ff8c128..3a02cf3bd 100644 --- a/channels/Makefile +++ b/channels/Makefile @@ -81,9 +81,9 @@ ifneq ($(wildcard h323/libchanh323.a),) CHANNEL_LIBS+=chan_h323.so endif -ifneq ($(wildcard misdn/chan_misdn_lib.a),) +ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/mISDNuser/mISDNlib.h),) CHANNEL_LIBS+=chan_misdn.so - CFLAGS+=-Imisdn + CFLAGS+=-Imisdn endif CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations @@ -239,11 +239,17 @@ chan_h323.so: chan_h323.o h323/libchanh323.a $(CC) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat endif -chan_misdn.so: chan_misdn.o chan_misdn_config.o misdn/chan_misdn_lib.a - $(CC) -shared -Xlinker -x -L/usr/lib -o $@ $^ -lmISDN -lisdnnet +misdn/chan_misdn_lib.a: + make -C misdn -chan_misdn.o: chan_misdn.c - $(CC) $(CFLAGS) -DCHAN_MISDN_VERSION=\"0.2.1\" -c $< -o $@ +chan_misdn.so: chan_misdn.o misdn_config.o misdn/chan_misdn_lib.a + $(CC) -shared -Xlinker -x -L/usr/lib -o $@ $^ -lisdnnet -lmISDN + +chan_misdn.o: chan_misdn.c + $(CC) $(CFLAGS) -DCHAN_MISDN_VERSION=\"0.3.0\" -c $< -o $@ + +misdn_config.o: misdn_config.c misdn/chan_misdn_config.h + $(CC) $(CFLAGS) -DCHAN_MISDN_VERSION=\"0.3.0\" -c $< -o $@ #chan_modem.so : chan_modem.o # $(CC) -rdynamic -shared -Xlinker -x -o $@ $< diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index a170105ff..5b322f6bf 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -59,28 +59,63 @@ #include <asterisk/app.h> #include <asterisk/features.h> -#include "chan_misdn_config.h" -#include "isdn_lib.h" +#include <chan_misdn_config.h> +#include <isdn_lib.h> + +char global_tracefile[BUFFERSIZE+1]; + + +struct misdn_jb{ + int size; + int upper_threshold; + char *samples, *ok; + int wp,rp; + int state_empty; + int state_full; + int state_buffer; + int bytes_wrote; + ast_mutex_t mutexjb; +}; + + + +/* allocates the jb-structure and initialise the elements*/ +struct misdn_jb *misdn_jb_init(int size, int upper_threshold); + +/* frees the data and destroys the given jitterbuffer struct */ +void misdn_jb_destroy(struct misdn_jb *jb); + +/* fills the jitterbuffer with len data returns < 0 if there was an +error (bufferoverun). */ +int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len); + +/* gets len bytes out of the jitterbuffer if available, else only the +available data is returned and the return value indicates the number +of data. */ +int misdn_jb_empty(struct misdn_jb *jb, char *data, int len); -ast_mutex_t release_lock_mutex; -#define release_lock ast_mutex_lock(&release_lock_mutex) -#define release_unlock ast_mutex_unlock(&release_lock_mutex) /* BEGIN: chan_misdn.h */ + + enum misdn_chan_state { MISDN_NOTHING, /*!< at beginning */ MISDN_WAITING4DIGS, /*!< when waiting for infos */ MISDN_EXTCANTMATCH, /*!< when asterisk couldnt match our ext */ MISDN_DIALING, /*!< when pbx_start */ MISDN_PROGRESS, /*!< we got a progress */ + MISDN_PROCEEDING, /*!< we got a progress */ MISDN_CALLING, /*!< when misdn_call is called */ MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */ MISDN_ALERTING, /*!< when Alerting */ MISDN_BUSY, /*!< when BUSY */ MISDN_CONNECTED, /*!< when connected */ + MISDN_PRECONNECTED, /*!< when connected */ + MISDN_DISCONNECTED, /*!< when connected */ + MISDN_RELEASED, /*!< when connected */ MISDN_BRIDGED, /*!< when bridged */ MISDN_CLEANING, /*!< when hangup from * but we were connected before */ MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP cam from misdn */ @@ -98,13 +133,24 @@ struct chan_list { ast_mutex_t lock; + char allowed_bearers[BUFFERSIZE+1]; + enum misdn_chan_state state; - int holded; + int need_queue_hangup; + int need_hangup; + int need_busy; + int orginator; int norxtone; int notxtone; + int toggle_ec; + + int incoming_early_audio; + + int ignore_dtmf; + int pipe[2]; char ast_rd_buf[4096]; struct ast_frame frame; @@ -113,17 +159,34 @@ struct chan_list { int faxhandled; int ast_dsp; + + int jb_len; + int jb_upper_threshold; + struct misdn_jb *jb; struct ast_dsp *dsp; struct ast_trans_pvt *trans; struct ast_channel * ast; + + int dummy; struct misdn_bchannel *bc; struct misdn_bchannel *holded_bc; unsigned int l3id; int addr; + + char context[BUFFERSIZE]; + + int zero_read_cnt; + int dropped_frame_cnt; + + int far_alerting; + int other_pid; + struct chan_list *other_ch; + + const struct tone_zone_sound *ts; struct chan_list *peer; struct chan_list *next; @@ -131,6 +194,11 @@ struct chan_list { struct chan_list *first; }; + + +void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch); +void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch); + struct robin_list { char *group; int port; @@ -140,13 +208,19 @@ struct robin_list { }; static struct robin_list *robin = NULL; + + +struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame); + + + static inline void free_robin_list_r (struct robin_list *r) { - if (r) { - if (r->next) free_robin_list_r(r->next); - if (r->group) free(r->group); - free(r); - } + if (r) { + if (r->next) free_robin_list_r(r->next); + if (r->group) free(r->group); + free(r); + } } static void free_robin_list ( void ) @@ -155,7 +229,7 @@ static void free_robin_list ( void ) robin = NULL; } -struct robin_list* get_robin_position (char *group) +static struct robin_list* get_robin_position (char *group) { struct robin_list *iter = robin; for (; iter; iter = iter->next) { @@ -173,8 +247,11 @@ struct robin_list* get_robin_position (char *group) return robin; } -struct ast_channel *misdn_new(struct chan_list *cl, int state, char * name, char * context, char *exten, char *callerid, int format, int port, int c); -void send_digit_to_chan(struct chan_list *cl, char digit ); + +static void chan_misdn_log(int level, int port, char *tmpl, ...); + +static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c); +static void send_digit_to_chan(struct chan_list *cl, char digit ); #define AST_CID_P(ast) ast->cid.cid_num @@ -184,48 +261,50 @@ void send_digit_to_chan(struct chan_list *cl, char digit ); #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt #define MISDN_ASTERISK_PVT(ast) 1 -#define MISDN_ASTERISK_TYPE(ast) ast->tech->type - -/* END: chan_misdn.h */ #include <asterisk/strings.h> /* #define MISDN_DEBUG 1 */ -static char *desc = "Channel driver for mISDN Support (Bri/Pri)"; -static char *type = "mISDN"; +static char *desc = "Channel driver for mISDN Support (Bri/Pri)"; +static const char misdn_type[] = "mISDN"; -int tracing = 0 ; +static int tracing = 0 ; static int usecnt=0; -char **misdn_key_vector=NULL; -int misdn_key_vector_size=0; +static char **misdn_key_vector=NULL; +static int misdn_key_vector_size=0; /* Only alaw and mulaw is allowed for now */ static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */ static ast_mutex_t usecnt_lock; -int *misdn_debug; -int *misdn_debug_only; -int max_ports; +static int *misdn_debug; +static int *misdn_debug_only; +static int max_ports; struct chan_list dummy_cl; struct chan_list *cl_te=NULL; ast_mutex_t cl_te_lock; -enum event_response_e +static enum event_response_e cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data); -void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc); +static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch); + +static void cl_queue_chan(struct chan_list **list, struct chan_list *chan); +static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan); +static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc); +static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid); -void cl_queue_chan(struct chan_list **list, struct chan_list *chan); -void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan); -struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc); -void chan_misdn_log(int level, int port, char *tmpl, ...); -void chan_misdn_trace_call(struct ast_channel *chan, int debug, char *tmpl, ...); + + +static int dialtone_indicate(struct chan_list *cl); +static int hanguptone_indicate(struct chan_list *cl); +static int stop_indicate(struct chan_list *cl); static int start_bc_tones(struct chan_list *cl); static int stop_bc_tones(struct chan_list *cl); @@ -234,6 +313,10 @@ static void release_chan(struct misdn_bchannel *bc); static int misdn_set_opt_exec(struct ast_channel *chan, void *data); static int misdn_facility_exec(struct ast_channel *chan, void *data); +int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len); + +static int update_ec_config(struct misdn_bchannel *bc); + /*************** Helpers *****************/ static struct chan_list * get_chan_by_ast(struct ast_channel *ast) @@ -258,25 +341,21 @@ static struct chan_list * get_chan_by_ast_name(char *name) return NULL; } -static char* tone2str(struct misdn_bchannel *bc) -{ - static struct { - char name[16]; - enum tone_e tone; - } *tone, tone_buf[] = { - {"NOTONE",TONE_NONE}, - {"DIAL",TONE_DIAL}, - {"BUSY",TONE_BUSY}, - {"ALERT",TONE_ALERTING}, - {"",TONE_NONE} - }; - - - for (tone=&tone_buf[0]; tone->name[0]; tone++) { - if (tone->tone == bc->tone) return tone->name; - } - return NULL; -} + + +struct allowed_bearers { + int cap; + int val; + char *name; +}; + +struct allowed_bearers allowed_bearers_array[]={ + {INFO_CAPABILITY_SPEECH,1,"speech"}, + {INFO_CAPABILITY_AUDIO_3_1K,2,"3_1khz"}, + {INFO_CAPABILITY_DIGITAL_UNRESTRICTED,4,"digital_unrestricted"}, + {INFO_CAPABILITY_DIGITAL_RESTRICTED,8,"digital_restriced"}, + {INFO_CAPABILITY_VIDEO,16,"video"} +}; static char *bearer2str(int cap) { static char *bearers[]={ @@ -284,6 +363,7 @@ static char *bearer2str(int cap) { "Audio 3.1k", "Unres Digital", "Res Digital", + "Video", "Unknown Bearer" }; @@ -300,9 +380,30 @@ static char *bearer2str(int cap) { case INFO_CAPABILITY_DIGITAL_RESTRICTED: return bearers[3]; break; - default: + case INFO_CAPABILITY_VIDEO: return bearers[4]; break; + default: + return bearers[5]; + break; + } +} + + +static void print_facility( struct misdn_bchannel *bc) +{ + switch (bc->fac_type) { + case FACILITY_CALLDEFLECT: + chan_misdn_log(2,bc->port," --> calldeflect: %s\n", + bc->fac.calldeflect_nr); + break; + case FACILITY_CENTREX: + chan_misdn_log(2,bc->port," --> centrex: %s\n", + bc->fac.cnip); + break; + default: + chan_misdn_log(2,bc->port," --> unknown\n"); + } } @@ -322,7 +423,7 @@ static void print_bearer(struct misdn_bchannel *bc) } /*************** Helpers END *************/ -void send_digit_to_chan(struct chan_list *cl, char digit ) +static void send_digit_to_chan(struct chan_list *cl, char digit ) { static const char* dtmf_tones[] = { "!941+1336/100,!0/100", /* 0 */ @@ -416,10 +517,38 @@ static int misdn_set_debug(int fd, int argc, char *argv[]) return 0; } - static int misdn_set_crypt_debug(int fd, int argc, char *argv[]) { - if (argc != 5 )return RESULT_SHOWUSAGE; + if (argc != 5) return RESULT_SHOWUSAGE; + + return 0; +} + + +static int misdn_port_block(int fd, int argc, char *argv[]) +{ + int port; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + port = atoi(argv[3]); + + misdn_lib_port_block(port); + + return 0; +} + +static int misdn_port_unblock(int fd, int argc, char *argv[]) +{ + int port; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + port = atoi(argv[3]); + + misdn_lib_port_unblock(port); return 0; } @@ -453,6 +582,20 @@ static int misdn_port_up (int fd, int argc, char *argv[]) return 0; } +static int misdn_port_down (int fd, int argc, char *argv[]) +{ + int port; + + if (argc != 4) + return RESULT_SHOWUSAGE; + + port = atoi(argv[3]); + + misdn_lib_get_port_down(port); + + return 0; +} + static int misdn_show_config (int fd, int argc, char *argv[]) { @@ -470,12 +613,12 @@ static int misdn_show_config (int fd, int argc, char *argv[]) if (argc == 3 || onlyport == 0) { ast_cli(fd,"Misdn General-Config: \n"); - ast_cli(fd," -> VERSION: " CHAN_MISDN_VERSION "\n"); - + ast_cli(fd," -> Version: chan_misdn-" CHAN_MISDN_VERSION "\n"); for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) { misdn_cfg_get_config_string( 0, elem, buffer, BUFFERSIZE); ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : ""); } + ast_cli(fd, "\n"); } if (onlyport < 0) { @@ -505,23 +648,26 @@ static int misdn_show_config (int fd, int argc, char *argv[]) return 0; } - - struct state_struct { enum misdn_chan_state state; char txt[255] ; } ; -struct state_struct state_array[] = { +static struct state_struct state_array[] = { {MISDN_NOTHING,"NOTHING"}, /* at beginning */ {MISDN_WAITING4DIGS,"WAITING4DIGS"}, /* when waiting for infos */ {MISDN_EXTCANTMATCH,"EXTCANTMATCH"}, /* when asterisk couldnt match our ext */ {MISDN_DIALING,"DIALING"}, /* when pbx_start */ {MISDN_PROGRESS,"PROGRESS"}, /* when pbx_start */ + {MISDN_PROCEEDING,"PROCEEDING"}, /* when pbx_start */ {MISDN_CALLING,"CALLING"}, /* when misdn_call is called */ + {MISDN_CALLING_ACKNOWLEDGE,"CALLING_ACKNOWLEDGE"}, /* when misdn_call is called */ {MISDN_ALERTING,"ALERTING"}, /* when Alerting */ {MISDN_BUSY,"BUSY"}, /* when BUSY */ {MISDN_CONNECTED,"CONNECTED"}, /* when connected */ + {MISDN_PRECONNECTED,"PRECONNECTED"}, /* when connected */ + {MISDN_DISCONNECTED,"DISCONNECTED"}, /* when connected */ + {MISDN_RELEASED,"RELEASED"}, /* when connected */ {MISDN_BRIDGED,"BRIDGED"}, /* when bridged */ {MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */ {MISDN_HUNGUP_FROM_MISDN,"HUNGUP_FROM_MISDN"}, /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */ @@ -531,45 +677,44 @@ struct state_struct state_array[] = { /* misdn_hangup */ }; - - - -char *misdn_get_ch_state(struct chan_list *p) +static char *misdn_get_ch_state(struct chan_list *p) { int i; + static char state[8]; + if( !p) return NULL; for (i=0; i< sizeof(state_array)/sizeof(struct state_struct); i++) { if ( state_array[i].state == p->state) return state_array[i].txt; } - - return NULL; + + sprintf(state,"%d",p->state) ; + + return state; } -static int misdn_reload (int fd, int argc, char *argv[]) + + +void reload_config(void) { int i, cfg_debug; - ast_cli(fd, "Reloading mISDN Config\n"); - chan_misdn_log(0, 0, "Dynamic Crypting Activation is not support during reload at the moment\n"); - free_robin_list(); - misdn_cfg_reload(); - - { - char tempbuf[BUFFERSIZE]; - misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, tempbuf, BUFFERSIZE); - if (strlen(tempbuf)) - tracing = 1; - } - + misdn_cfg_update_ptp(); + misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE); misdn_cfg_get( 0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(int)); + for (i = 0; i <= max_ports; i++) { misdn_debug[i] = cfg_debug; misdn_debug_only[i] = 0; } - +} + +static int misdn_reload (int fd, int argc, char *argv[]) +{ + ast_cli(fd, "Reloading mISDN Config\n"); + reload_config(); return 0; } @@ -577,12 +722,14 @@ static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel { struct ast_channel *ast=help->ast; ast_cli(fd, - "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s ctx:%s state:%s\n", + "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n", + bc->pid, bc->port, bc->channel, bc->nt?"NT":"TE", help->orginator == ORG_AST?"*":"I", ast?ast->exten:NULL, ast?AST_CID_P(ast):NULL, + bc->rad, ast?ast->context:NULL, misdn_get_ch_state(help) ); @@ -593,9 +740,9 @@ static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel " --> ch_addr: %x\n" " --> bc_addr: %x\n" " --> bc_l3id: %x\n" - " --> tone: %s\n" " --> display: %s\n" " --> activated: %d\n" + " --> state: %s\n" " --> capability: %s\n" " --> echo_cancel: %d\n" " --> notone : rx %d tx:%d\n" @@ -605,19 +752,19 @@ static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel help->addr, bc->addr, bc?bc->l3_id:-1, - tone2str(bc), bc->display, bc->active, + bc_state2str(bc->bc_state), bearer2str(bc->capability), bc->ec_enable, + help->norxtone,help->notxtone, bc->holded, help->holded_bc?1:0 ); } - static int misdn_show_cls (int fd, int argc, char *argv[]) { struct chan_list *help=cl_te; @@ -642,8 +789,6 @@ static int misdn_show_cls (int fd, int argc, char *argv[]) return 0; } - - static int misdn_show_cl (int fd, int argc, char *argv[]) { struct chan_list *help=cl_te; @@ -680,13 +825,12 @@ static int misdn_set_tics (int fd, int argc, char *argv[]) return 0; } - - static int misdn_show_stacks (int fd, int argc, char *argv[]) { int port; - + ast_cli(fd, "BEGIN STACK_LIST:\n"); + for (port=misdn_cfg_get_next_port(0); port > 0; port=misdn_cfg_get_next_port(port)) { char buf[128]; @@ -746,8 +890,6 @@ static int misdn_send_cd (int fd, int argc, char *argv[]) return 0; } - - static int misdn_send_digit (int fd, int argc, char *argv[]) { char *channame; @@ -806,9 +948,11 @@ static int misdn_toggle_echocancel (int fd, int argc, char *argv[]) ast_cli(fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame); return 0; } else { - tmp->bc->ec_enable=tmp->bc->ec_enable?0:1; + + tmp->toggle_ec=tmp->toggle_ec?0:1; - if (tmp->bc->ec_enable) { + if (tmp->toggle_ec) { + update_ec_config(tmp->bc); manager_ec_enable(tmp->bc); } else { manager_ec_disable(tmp->bc); @@ -819,8 +963,6 @@ static int misdn_toggle_echocancel (int fd, int argc, char *argv[]) return 0; } - - static int misdn_send_display (int fd, int argc, char *argv[]) { char *channame; @@ -838,9 +980,7 @@ static int misdn_send_display (int fd, int argc, char *argv[]) tmp=get_chan_by_ast_name(channame); if (tmp && tmp->bc) { - int l = sizeof(tmp->bc->display); - strncpy(tmp->bc->display, msg, l); - tmp->bc->display[l-1] = 0; + ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display)); misdn_lib_send_event(tmp->bc, EVENT_INFORMATION); } else { ast_cli(fd,"No such channel %s\n",channame); @@ -851,9 +991,6 @@ static int misdn_send_display (int fd, int argc, char *argv[]) return RESULT_SUCCESS ; } - - - static char *complete_ch_helper(char *line, char *word, int pos, int state, int rpos) { struct ast_channel *c; @@ -909,7 +1046,6 @@ static struct ast_cli_entry cli_send_cd = complete_ch }; - static struct ast_cli_entry cli_send_digit = { {"misdn","send","digit", NULL}, misdn_send_digit, @@ -920,7 +1056,6 @@ static struct ast_cli_entry cli_send_digit = complete_ch }; - static struct ast_cli_entry cli_toggle_echocancel = { {"misdn","toggle","echocancel", NULL}, misdn_toggle_echocancel, @@ -929,8 +1064,6 @@ static struct ast_cli_entry cli_toggle_echocancel = complete_ch }; - - static struct ast_cli_entry cli_send_display = { {"misdn","send","display", NULL}, misdn_send_display, @@ -941,7 +1074,6 @@ static struct ast_cli_entry cli_send_display = complete_ch }; - static struct ast_cli_entry cli_show_config = { {"misdn","show","config", NULL}, misdn_show_config, @@ -949,7 +1081,6 @@ static struct ast_cli_entry cli_show_config = "Usage: misdn show config [port | 0]\n use 0 to only print the general config.\n" }; - static struct ast_cli_entry cli_reload = { {"misdn","reload", NULL}, misdn_reload, @@ -964,7 +1095,6 @@ static struct ast_cli_entry cli_set_tics = "\n" }; - static struct ast_cli_entry cli_show_cls = { {"misdn","show","channels", NULL}, misdn_show_cls, @@ -980,6 +1110,19 @@ static struct ast_cli_entry cli_show_cl = complete_ch }; +static struct ast_cli_entry cli_port_block= +{ {"misdn","port","block", NULL}, + misdn_port_block, + "Blocks the given port", + "Usage: misdn port block\n" +}; + +static struct ast_cli_entry cli_port_unblock= +{ {"misdn","port","unblock", NULL}, + misdn_port_unblock, + "Unblocks the given port", + "Usage: misdn port unblock\n" +}; static struct ast_cli_entry cli_restart_port = @@ -989,7 +1132,6 @@ static struct ast_cli_entry cli_restart_port = "Usage: misdn restart port\n" }; - static struct ast_cli_entry cli_port_up = { {"misdn","port","up", NULL}, misdn_port_up, @@ -997,6 +1139,14 @@ static struct ast_cli_entry cli_port_up = "Usage: misdn port up <port>\n" }; +static struct ast_cli_entry cli_port_down = +{ {"misdn","port","down", NULL}, + misdn_port_down, + "Tries to deacivate the L1 on the given port", + "Usage: misdn port down <port>\n" +}; + + static struct ast_cli_entry cli_show_stacks = { {"misdn","show","stacks", NULL}, @@ -1012,8 +1162,6 @@ static struct ast_cli_entry cli_show_port = "Usage: misdn show port <port>\n" }; - - static struct ast_cli_entry cli_set_debug = { {"misdn","set","debug", NULL}, misdn_set_debug, @@ -1031,6 +1179,372 @@ static struct ast_cli_entry cli_set_crypt_debug = /*** CLI END ***/ +static int update_config (struct chan_list *ch, int orig) +{ + if (!ch) { + ast_log(LOG_WARNING, "Cannot configure without chanlist\n"); + return -1; + } + + struct ast_channel *ast=ch->ast; + struct misdn_bchannel *bc=ch->bc; + if (! ast || ! bc ) { + ast_log(LOG_WARNING, "Cannot configure without ast || bc\n"); + return -1; + } + + int port=bc->port; + + chan_misdn_log(1,port,"update_config: Getting Config\n"); + + + int hdlc=0; + misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); + + if (hdlc) { + switch (bc->capability) { + case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: + case INFO_CAPABILITY_DIGITAL_RESTRICTED: + chan_misdn_log(1,bc->port," --> CONF HDLC\n"); + bc->hdlc=1; + break; + } + + } + + + int pres, screen; + + misdn_cfg_get( port, MISDN_CFG_PRES, &pres, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_SCREEN, &screen, sizeof(int)); + chan_misdn_log(2,port," --> pres: %d screen: %d\n",pres, screen); + + if ( (pres + screen) < 0 ) { + + chan_misdn_log(2,port," --> pres: %x\n", ast->cid.cid_pres); + + switch (ast->cid.cid_pres & 0x60){ + + case AST_PRES_RESTRICTED: + bc->pres=1; + chan_misdn_log(2, port, " --> PRES: Restricted (0x1)\n"); + break; + + + case AST_PRES_UNAVAILABLE: + bc->pres=2; + chan_misdn_log(2, port, " --> PRES: Unavailable (0x2)\n"); + break; + + default: + bc->pres=0; + chan_misdn_log(2, port, " --> PRES: Allowed (0x0)\n"); + } + + switch (ast->cid.cid_pres & 0x3){ + + case AST_PRES_USER_NUMBER_UNSCREENED: + bc->screen=0; + chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); + break; + + case AST_PRES_USER_NUMBER_PASSED_SCREEN: + bc->screen=1; + chan_misdn_log(2, port, " --> SCREEN: Passed Screen (0x1)\n"); + break; + case AST_PRES_USER_NUMBER_FAILED_SCREEN: + bc->screen=2; + chan_misdn_log(2, port, " --> SCREEN: Failed Screen (0x2)\n"); + break; + + case AST_PRES_NETWORK_NUMBER: + bc->screen=3; + chan_misdn_log(2, port, " --> SCREEN: Network Nr. (0x3)\n"); + break; + + default: + bc->screen=0; + chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); + } + + + } else { + bc->screen=screen; + bc->pres=pres; + } + + return 0; + +} + + + + +void config_jitterbuffer(struct chan_list *ch) +{ + struct misdn_bchannel *bc=ch->bc; + int len=ch->jb_len, threshold=ch->jb_upper_threshold; + + chan_misdn_log(5,bc->port, "config_jb: Called\n"); + + if ( ! len ) { + chan_misdn_log(1,bc->port, "config_jb: Deactivating Jitterbuffer\n"); + bc->nojitter=1; + } else { + + if (len <=100 || len > 8000) { + chan_misdn_log(0,bc->port,"config_jb: Jitterbuffer out of Bounds, setting to 1000\n"); + len=1000; + } + + if ( threshold > len ) { + chan_misdn_log(0,bc->port,"config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n"); + } + + if ( ch->jb) { + cb_log(0,bc->port,"config_jb: We've got a Jitterbuffer Already on this port.\n"); + misdn_jb_destroy(ch->jb); + ch->jb=NULL; + } + + ch->jb=misdn_jb_init(len, threshold); + + if (!ch->jb ) + bc->nojitter=1; + } +} + + +void debug_numplan(int port, int numplan, char *type) +{ + switch (numplan) { + case NUMPLAN_INTERNATIONAL: + chan_misdn_log(2, port, " --> %s: International\n",type); + break; + case NUMPLAN_NATIONAL: + chan_misdn_log(2, port, " --> %s: National\n",type); + break; + case NUMPLAN_SUBSCRIBER: + chan_misdn_log(2, port, " --> %s: Subscriber\n",type); + break; + case NUMPLAN_UNKNOWN: + chan_misdn_log(2, port, " --> %s: Unknown\n",type); + break; + /* Maybe we should cut off the prefix if present ? */ + default: + chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n "); + break; + } +} + + + + +static int update_ec_config(struct misdn_bchannel *bc) +{ + int ec; + int port=bc->port; + + misdn_cfg_get( port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); + + if (ec == 1 ) { + bc->ec_enable=1; + } else if ( ec > 1 ) { + bc->ec_enable=1; + bc->ec_deftaps=ec; + } + + return 0; +} + + +static int read_config(struct chan_list *ch, int orig) { + + if (!ch) { + ast_log(LOG_WARNING, "Cannot configure without chanlist\n"); + return -1; + } + + struct ast_channel *ast=ch->ast; + struct misdn_bchannel *bc=ch->bc; + if (! ast || ! bc ) { + ast_log(LOG_WARNING, "Cannot configure without ast || bc\n"); + return -1; + } + + int port=bc->port; + + chan_misdn_log(5,port,"read_config: Getting Config\n"); + + char lang[BUFFERSIZE+1]; + + misdn_cfg_get( port, MISDN_CFG_LANGUAGE, lang, BUFFERSIZE); + ast_copy_string(ast->language, lang, sizeof(ast->language)); + + char musicclass[BUFFERSIZE+1]; + + misdn_cfg_get( port, MISDN_CFG_MUSICCLASS, musicclass, BUFFERSIZE); + ast_copy_string(ast->musicclass, musicclass, sizeof(ast->musicclass)); + + misdn_cfg_get( port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(int)); + + misdn_cfg_get( port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, BUFFERSIZE); + + + int hdlc=0; + misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); + + if (hdlc) { + switch (bc->capability) { + case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: + case INFO_CAPABILITY_DIGITAL_RESTRICTED: + chan_misdn_log(1,bc->port," --> CONF HDLC\n"); + bc->hdlc=1; + break; + } + + } + /*Initialize new Jitterbuffer*/ + { + misdn_cfg_get( port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(int)); + + config_jitterbuffer(ch); + } + + misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context)); + + ast_copy_string (ast->context,ch->context,sizeof(ast->context)); + + update_ec_config(bc); + + { + int eb3; + + misdn_cfg_get( bc->port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int)); + bc->early_bconnect=eb3; + } + + port=bc->port; + + { + char buf[256]; + ast_group_t pg,cg; + + misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); + misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); + + chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n",ast_print_group(buf,sizeof(buf),cg),ast_print_group(buf,sizeof(buf),pg)); + ast->pickupgroup=pg; + ast->callgroup=cg; + } + + if ( orig == ORG_AST) { + misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(int)); + + { + char callerid[BUFFERSIZE+1]; + misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE); + if ( ! ast_strlen_zero(callerid) ) { + chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid); + { + int l = sizeof(bc->oad); + strncpy(bc->oad,callerid, l); + bc->oad[l-1] = 0; + } + + } + + + misdn_cfg_get( port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(int)); + misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int)); + debug_numplan(port, bc->dnumplan,"TON"); + debug_numplan(port, bc->onumplan,"LTON"); + debug_numplan(port, bc->cpnnumplan,"CTON"); + } + + + + } else { /** ORIGINATOR MISDN **/ + + misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int)); + debug_numplan(port, bc->cpnnumplan,"CTON"); + + char prefix[BUFFERSIZE+1]=""; + switch( bc->onumplan ) { + case NUMPLAN_INTERNATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); + break; + + case NUMPLAN_NATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); + break; + default: + break; + } + + { + int l = strlen(prefix) + strlen(bc->oad); + char tmp[l+1]; + strcpy(tmp,prefix); + strcat(tmp,bc->oad); + strcpy(bc->oad,tmp); + } + + if (!ast_strlen_zero(bc->dad)) { + ast_copy_string(bc->orig_dad,bc->dad, sizeof(bc->orig_dad)); + } + + if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) { + ast_copy_string(bc->dad,bc->keypad, sizeof(bc->dad)); + } + + prefix[0] = 0; + + switch( bc->dnumplan ) { + case NUMPLAN_INTERNATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); + break; + case NUMPLAN_NATIONAL: + misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); + break; + default: + break; + } + + { + int l = strlen(prefix) + strlen(bc->dad); + char tmp[l+1]; + strcpy(tmp,prefix); + strcat(tmp,bc->dad); + strcpy(bc->dad,tmp); + } + + if ( strcmp(bc->dad,ast->exten)) { + ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten)); + } + + ast_set_callerid(ast, bc->oad, NULL, bc->oad); + + if ( !ast_strlen_zero(bc->rad) ) + ast->cid.cid_rdnis=strdup(bc->rad); + + } /* ORIG MISDN END */ + + return 0; +} + + /*****************************/ /*** AST Indications Start ***/ /*****************************/ @@ -1041,9 +1555,8 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) int r; struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast); struct misdn_bchannel *newbc; - char *opts=NULL, *ext=NULL; + char *opts=NULL, *ext,*tokb; char dest_cp[256]; - char *tokb; { strncpy(dest_cp,dest,sizeof(dest_cp)-1); @@ -1056,12 +1569,10 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) if (ext) { opts=strtok_r(NULL,"/",&tokb); } else { - chan_misdn_log(-1,0,"misdn_call: No Extension given!\n"); + chan_misdn_log(0,0,"misdn_call: No Extension given!\n"); return -1; } } - - } if (!ast) { @@ -1076,7 +1587,6 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) return -1; } - if (!ch) { ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); ast->hangupcause=41; @@ -1092,183 +1602,15 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) ast_setstate(ast, AST_STATE_DOWN); return -1; } - + port=newbc->port; - - ast_copy_string(newbc->dad, ext, sizeof(newbc->dad)); - ast_copy_string(ast->exten, ext, sizeof(ast->exten)); + strncpy(newbc->dad,ext,sizeof( newbc->dad)); + strncpy(ast->exten,ext,sizeof(ast->exten)); - chan_misdn_log(1, 0, "* CALL: %s\n",dest); + chan_misdn_log(1, port, "* CALL: %s\n",dest); chan_misdn_log(1, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context); - { - char context[BUFFERSIZE]; - - misdn_cfg_get( port, MISDN_CFG_CONTEXT, context, sizeof(ast->context)); - { - int l = sizeof(ast->context); - strncpy(ast->context,context, l); - ast->context[l-1] = 0; - } - chan_misdn_log(2, port, " --> * Setting Context to %s\n",context); - misdn_cfg_get( port, MISDN_CFG_LANGUAGE, ast->language, BUFFERSIZE); - - misdn_cfg_get( port, MISDN_CFG_TXGAIN, &newbc->txgain, sizeof(int)); - misdn_cfg_get( port, MISDN_CFG_RXGAIN, &newbc->rxgain, sizeof(int)); - - misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(newbc->te_choose_channel), sizeof(int)); - - - { - char callerid[BUFFERSIZE]; - misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE); - if ( ! ast_strlen_zero(callerid) ) { - chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid); - { - int l = sizeof(newbc->oad); - strncpy(newbc->oad,callerid, l); - newbc->oad[l-1] = 0; - } - } - - - misdn_cfg_get( port, MISDN_CFG_DIALPLAN, &newbc->dnumplan, sizeof(int)); - switch (newbc->dnumplan) { - case NUMPLAN_INTERNATIONAL: - chan_misdn_log(2, port, " --> TON: International\n"); - break; - case NUMPLAN_NATIONAL: - chan_misdn_log(2, port, " --> TON: National\n"); - break; - case NUMPLAN_SUBSCRIBER: - chan_misdn_log(2, port, " --> TON: Subscriber\n"); - break; - case NUMPLAN_UNKNOWN: - chan_misdn_log(2, port, " --> TON: Unknown\n"); - break; - /* Maybe we should cut off the prefix if present ? */ - default: - chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n "); - break; - } - - - misdn_cfg_get( port, MISDN_CFG_LOCALDIALPLAN, &newbc->onumplan, sizeof(int)); - switch (newbc->onumplan) { - case NUMPLAN_INTERNATIONAL: - chan_misdn_log(2, port, " --> TON: International\n"); - break; - case NUMPLAN_NATIONAL: - chan_misdn_log(2, port, " --> TON: National\n"); - break; - case NUMPLAN_SUBSCRIBER: - chan_misdn_log(2, port, " --> TON: Subscriber\n"); - break; - case NUMPLAN_UNKNOWN: - chan_misdn_log(2, port, " --> TON: Unknown\n"); - break; - /* Maybe we should cut off the prefix if present ? */ - default: - chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n "); - break; - } - } - - - - - { - int eb3; - - misdn_cfg_get( port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int)); - newbc->early_bconnect=eb3; - - } - - - - /* Will be overridden by asterisk in head! */ - { - int pres; - - misdn_cfg_get( port, MISDN_CFG_PRES, &pres, sizeof(int)); - newbc->pres=pres?0:1; - - } - - int def_callingpres; - misdn_cfg_get( port, MISDN_CFG_USE_CALLINGPRES, &def_callingpres, sizeof(int)); - if ( def_callingpres) { - - switch (ast->cid.cid_pres & 0x60){ - - case AST_PRES_RESTRICTED: - chan_misdn_log(2, port, " --> PRES: Restricted (0x1)\n"); - newbc->pres=1; - break; - - - case AST_PRES_UNAVAILABLE: - chan_misdn_log(2, port, " --> PRES: Unavailable (0x2)\n"); - newbc->pres=2; - break; - - default: - chan_misdn_log(2, port, " --> PRES: Allowed (0x0)\n"); - newbc->pres=0; - } - - switch (ast->cid.cid_pres & 0x3){ - - case AST_PRES_USER_NUMBER_UNSCREENED: - chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); - newbc->screen=0; - break; - - case AST_PRES_USER_NUMBER_PASSED_SCREEN: - chan_misdn_log(2, port, " --> SCREEN: Passed Screen (0x1)\n"); - newbc->screen=1; - break; - case AST_PRES_USER_NUMBER_FAILED_SCREEN: - chan_misdn_log(2, port, " --> SCREEN: Failed Screen (0x2)\n"); - newbc->screen=2; - break; - - case AST_PRES_NETWORK_NUMBER: - chan_misdn_log(2, port, " --> SCREEN: Network Nr. (0x3)\n"); - newbc->screen=3; - break; - - default: - chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); - newbc->screen=0; - } - } - - - { - int ec, ectr; - - misdn_cfg_get( port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); - - misdn_cfg_get( port, MISDN_CFG_ECHOTRAINING, &ectr, sizeof(int)); - if (ec == 1 ) { - newbc->ec_enable=1; - } else if ( ec > 1 ) { - newbc->ec_enable=1; - newbc->ec_deftaps=ec; - } - - - if (ectr>=0) { - newbc->ec_training=ectr; - } - - } - - } - chan_misdn_log(3, port, " --> * adding2newbc ext %s\n",ast->exten); if (ast->exten) { int l = sizeof(newbc->dad); @@ -1278,6 +1620,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) newbc->rad[0]=0; chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n",AST_CID_P(ast)); if (ast_strlen_zero(newbc->oad) && AST_CID_P(ast) ) { + if (AST_CID_P(ast)) { int l = sizeof(newbc->oad); strncpy(newbc->oad,AST_CID_P(ast), l); @@ -1288,14 +1631,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) { struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast); if (!ch) { ast_verbose("No chan_list in misdn_call"); return -1;} - ch->bc = newbc; - ch->orginator=ORG_AST; - ch->ast = ast; - MISDN_ASTERISK_TECH_PVT(ast) = ch ; - - - newbc->capability=ast->transfercapability; pbx_builtin_setvar_helper(ast,"TRANSFERCAPABILITY",ast_transfercapability2str(newbc->capability)); if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) { @@ -1303,17 +1639,19 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) } + /* update screening and presentation */ + update_config(ch,ORG_AST); + + /* fill in some ies from channel vary*/ + import_ch(ast, newbc, ch); + /* Finally The Options Override Everything */ if (opts) misdn_set_opt_exec(ast,opts); else - chan_misdn_log(1,0,"NO OPTS GIVEN\n"); - + chan_misdn_log(2,port,"NO OPTS GIVEN\n"); - cl_queue_chan(&cl_te, ch) ; ch->state=MISDN_CALLING; - - chan_misdn_trace_call(ast,1,"*->I: EVENT_CALL\n" ); r=misdn_lib_send_event( newbc, EVENT_SETUP ); @@ -1332,21 +1670,20 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout) chan_misdn_log(1, port, " --> * SEND: State Dialing pid:%d\n",newbc?newbc->pid:1); ast_setstate(ast, AST_STATE_DIALING); - ast->hangupcause=16; + + if (newbc->nt) stop_bc_tones(ch); + return 0; } -int misdn_answer(struct ast_channel *ast) +static int misdn_answer(struct ast_channel *ast) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; - - chan_misdn_trace_call(ast,1,"*->I: EVENT_ANSWER\n"); + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; chan_misdn_log(1, p? (p->bc? p->bc->port : 0) : 0, "* ANSWER:\n"); @@ -1362,7 +1699,7 @@ int misdn_answer(struct ast_channel *ast) } { - char *tmp_key = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY"); + const char *tmp_key = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY"); if (tmp_key ) { chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n"); @@ -1378,27 +1715,35 @@ int misdn_answer(struct ast_channel *ast) } { - char *async=pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS"); - if (async) { + const char *nodsp=pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS"); + if (nodsp) { chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n"); - p->bc->async=1; + p->bc->nodsp=1; + p->bc->hdlc=0; + p->bc->nojitter=1; } } p->state = MISDN_CONNECTED; + misdn_lib_echo(p->bc,0); + stop_indicate(p); + + if ( ast_strlen_zero(p->bc->cad) ) { + chan_misdn_log(2,p->bc->port," --> empty cad using dad\n"); + ast_copy_string(p->bc->cad,p->bc->dad,sizeof(p->bc->cad)); + } + misdn_lib_send_event( p->bc, EVENT_CONNECT); start_bc_tones(p); return 0; } -int misdn_digit(struct ast_channel *ast, char digit ) +static int misdn_digit(struct ast_channel *ast, char digit ) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; - + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) return -1; struct misdn_bchannel *bc=p->bc; chan_misdn_log(1, bc?bc->port:0, "* IND : Digit %c\n",digit); @@ -1452,14 +1797,13 @@ int misdn_digit(struct ast_channel *ast, char digit ) } -int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast) +static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) )) return -1; - chan_misdn_log(1, p->bc?p->bc->port:0, "* IND: Got Fixup State:%s Holded:%d L3id:%x\n", misdn_get_ch_state(p), p->holded, p->l3id); + chan_misdn_log(1, p->bc?p->bc->port:0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id); p->ast = ast ; p->state=MISDN_CONNECTED; @@ -1468,29 +1812,16 @@ int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast) } -int misdn_transfer (struct ast_channel *ast, char *dest) -{ - struct chan_list *p; - - if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1; - p = MISDN_ASTERISK_TECH_PVT(ast) ; - - chan_misdn_log(1, p->bc?p->bc->port:0, "* IND : Got Transfer %s\n",dest); - return 0; -} - - -int misdn_indication(struct ast_channel *ast, int cond) +static int misdn_indication(struct ast_channel *ast, int cond) { struct chan_list *p; - if (!ast || ! MISDN_ASTERISK_PVT(ast)) { + if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) { ast_log(LOG_WARNING, "Returnded -1 in misdn_indication\n"); return -1; } - p = MISDN_ASTERISK_TECH_PVT(ast) ; if (!p->bc ) { chan_misdn_log(1, 0, "* IND : Indication from %s\n",ast->exten); @@ -1498,56 +1829,85 @@ int misdn_indication(struct ast_channel *ast, int cond) return -1; } - chan_misdn_log(1, p->bc->port, "* IND : Indication from %s\n",ast->exten); + chan_misdn_log(1, p->bc->port, "* IND : Indication [%d] from %s\n",cond, ast->exten); switch (cond) { case AST_CONTROL_BUSY: chan_misdn_log(1, p->bc->port, "* IND :\tbusy\n"); chan_misdn_log(1, p->bc->port, " --> * SEND: State Busy pid:%d\n",p->bc?p->bc->pid:-1); ast_setstate(ast,AST_STATE_BUSY); - + p->bc->out_cause=17; if (p->state != MISDN_CONNECTED) { + start_bc_tones(p); misdn_lib_send_event( p->bc, EVENT_DISCONNECT); - manager_send_tone(p->bc, TONE_BUSY); } else { - chan_misdn_log(0, p->bc->port, " --> !! Got Busy in Connected State !?! port:%d ast:%s\n", - p->bc->port, ast->name); + chan_misdn_log(-1, p->bc->port, " --> !! Got Busy in Connected State !?! ast:%s\n", ast->name); } + return -1; break; case AST_CONTROL_RING: chan_misdn_log(1, p->bc->port, " --> * IND :\tring pid:%d\n",p->bc?p->bc->pid:-1); + return -1; break; + case AST_CONTROL_RINGING: - if ( p->state == MISDN_ALERTING) { - chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d but I ws Ringing before, so ignoreing it\n",p->bc?p->bc->pid:-1); - break; + switch (p->state) { + case MISDN_ALERTING: + chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoreing it\n",p->bc?p->bc->pid:-1); + break; + case MISDN_CONNECTED: + chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n",p->bc?p->bc->pid:-1); + return -1; + break; + default: + p->state=MISDN_ALERTING; + chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d\n",p->bc?p->bc->pid:-1); + misdn_lib_send_event( p->bc, EVENT_ALERTING); + + if (p->other_ch && p->other_ch->bc) { + if (misdn_inband_avail(p->other_ch->bc)) { + chan_misdn_log(1,p->bc->port, " --> other End is mISDN and has inband info available\n"); + break; + } + + if (!p->other_ch->bc->nt) { + chan_misdn_log(1,p->bc->port, " --> other End is mISDN TE so it has inband info for sure (?)\n"); + break; + } + } + + chan_misdn_log(1, p->bc->port, " --> * SEND: State Ring pid:%d\n",p->bc?p->bc->pid:-1); + ast_setstate(ast,AST_STATE_RINGING); + + if ( !p->bc->nt && (p->orginator==ORG_MISDN) && !p->incoming_early_audio ) + chan_misdn_log(1,p->bc->port, " --> incoming_early_audio off\n"); + else + return -1; } - p->state=MISDN_ALERTING; - - chan_misdn_log(1, p->bc->port, " --> * IND :\tringing pid:%d\n",p->bc?p->bc->pid:-1); - - misdn_lib_send_event( p->bc, EVENT_ALERTING); - - manager_send_tone(p->bc, TONE_ALERTING); - chan_misdn_log(1, p->bc->port, " --> * SEND: State Ring pid:%d\n",p->bc?p->bc->pid:-1); - ast_setstate(ast,AST_STATE_RINGING); break; - case AST_CONTROL_ANSWER: chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n",p->bc?p->bc->pid:-1); + start_bc_tones(p); break; case AST_CONTROL_TAKEOFFHOOK: chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n",p->bc?p->bc->pid:-1); + return -1; break; case AST_CONTROL_OFFHOOK: chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n",p->bc?p->bc->pid:-1); + return -1; break; case AST_CONTROL_FLASH: chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n",p->bc?p->bc->pid:-1); break; case AST_CONTROL_PROGRESS: chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n",p->bc?p->bc->pid:-1); + misdn_lib_send_event( p->bc, EVENT_PROGRESS); + break; + case AST_CONTROL_PROCEEDING: + chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n",p->bc?p->bc->pid:-1); + misdn_lib_send_event( p->bc, EVENT_PROCEEDING); break; case AST_CONTROL_CONGESTION: chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n",p->bc?p->bc->pid:-1); @@ -1555,18 +1915,25 @@ int misdn_indication(struct ast_channel *ast, int cond) p->bc->out_cause=42; if (p->state != MISDN_CONNECTED) { start_bc_tones(p); - //misdn_lib_send_event( p->bc, EVENT_RELEASE_COMPLETE); misdn_lib_send_event( p->bc, EVENT_RELEASE); } else { misdn_lib_send_event( p->bc, EVENT_DISCONNECT); } + if (p->bc->nt) { - manager_send_tone(p->bc, TONE_BUSY); + hanguptone_indicate(p); } break; case -1 : - chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! pid:%d\n",p->bc?p->bc->pid:-1); + chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n",p->bc?p->bc->pid:-1); + + stop_indicate(p); + + if (p->state == MISDN_CONNECTED) + start_bc_tones(p); + break; + case AST_CONTROL_HOLD: chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n",p->bc?p->bc->pid:-1); break; @@ -1574,35 +1941,29 @@ int misdn_indication(struct ast_channel *ast, int cond) chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n",p->bc?p->bc->pid:-1); break; default: - ast_log(LOG_WARNING, " --> * Unknown Indication:%d pid:%d\n",cond,p->bc?p->bc->pid:-1); + ast_log(LOG_NOTICE, " --> * Unknown Indication:%d pid:%d\n",cond,p->bc?p->bc->pid:-1); } return 0; } -int misdn_hangup(struct ast_channel *ast) +static int misdn_hangup(struct ast_channel *ast) { struct chan_list *p; struct misdn_bchannel *bc=NULL; if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1; - release_lock; - - chan_misdn_trace_call(ast,1,"*->I: EVENT_HANGUP cause=%d\n",ast->hangupcause); - ast_log(LOG_DEBUG, "misdn_hangup(%s)\n", ast->name); if (!p) { chan_misdn_log(3, 0, "misdn_hangup called, without chan_list obj.\n"); - release_unlock; return 0 ; } bc=p->bc; if (!bc) { - release_unlock; ast_log(LOG_WARNING,"Hangup with private but no bc ?\n"); return 0; } @@ -1611,31 +1972,32 @@ int misdn_hangup(struct ast_channel *ast) MISDN_ASTERISK_TECH_PVT(ast)=NULL; p->ast=NULL; + bc=p->bc; + if (ast->_state == AST_STATE_RESERVED) { /* between request and call */ MISDN_ASTERISK_TECH_PVT(ast)=NULL; - release_unlock; cl_dequeue_chan(&cl_te, p); free(p); - - misdn_lib_release(bc); + + if (bc) + misdn_lib_release(bc); return 0; } - stop_bc_tones(p); - - release_unlock; - - - - - + p->need_hangup=0; + p->need_queue_hangup=0; + + + if (!p->bc->nt) + stop_bc_tones(p); + { - char *varcause=NULL; - bc->cause=ast->hangupcause?ast->hangupcause:16; + const char *varcause=NULL; + bc->out_cause=ast->hangupcause?ast->hangupcause:16; if ( (varcause=pbx_builtin_getvar_helper(ast, "HANGUPCAUSE")) || (varcause=pbx_builtin_getvar_helper(ast, "PRI_CAUSE"))) { @@ -1647,6 +2009,7 @@ int misdn_hangup(struct ast_channel *ast) chan_misdn_log(2, bc->port, " --> l3id:%x\n",p->l3id); chan_misdn_log(1, bc->port, " --> cause:%d\n",bc->cause); chan_misdn_log(1, bc->port, " --> out_cause:%d\n",bc->out_cause); + chan_misdn_log(1, bc->port, " --> state:%s\n", misdn_get_ch_state(p)); switch (p->state) { case MISDN_CALLING: @@ -1656,81 +2019,112 @@ int misdn_hangup(struct ast_channel *ast) case MISDN_HOLDED: case MISDN_DIALING: start_bc_tones(p); - manager_send_tone(bc, TONE_BUSY); - p->state=MISDN_CLEANING; - - misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE); - + hanguptone_indicate(p); + + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); + break; + + case MISDN_CALLING_ACKNOWLEDGE: + start_bc_tones(p); + hanguptone_indicate(p); + + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); break; case MISDN_ALERTING: - chan_misdn_log(2, bc->port, " --> * State Alerting\n"); - + case MISDN_PROGRESS: + case MISDN_PROCEEDING: if (p->orginator != ORG_AST) - manager_send_tone(bc, TONE_BUSY); + hanguptone_indicate(p); - p->state=MISDN_CLEANING; - misdn_lib_send_event( bc, EVENT_DISCONNECT); + /*p->state=MISDN_CLEANING;*/ + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); break; case MISDN_CONNECTED: + case MISDN_PRECONNECTED: /* Alerting or Disconect */ - chan_misdn_log(2, bc->port, " --> * State Connected\n"); - start_bc_tones(p); - manager_send_tone(bc, TONE_BUSY); - misdn_lib_send_event( bc, EVENT_DISCONNECT); - + if (p->bc->nt) { + start_bc_tones(p); + hanguptone_indicate(p); + p->bc->progress_indicator=8; + } + if (bc->need_disconnect) + misdn_lib_send_event( bc, EVENT_DISCONNECT); + + /*p->state=MISDN_CLEANING;*/ + break; + case MISDN_DISCONNECTED: + misdn_lib_send_event( bc, EVENT_RELEASE); p->state=MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */ break; + case MISDN_RELEASED: case MISDN_CLEANING: + p->state=MISDN_CLEANING; + break; + + case MISDN_BUSY: break; case MISDN_HOLD_DISCONNECT: /* need to send release here */ - chan_misdn_log(2, bc->port, " --> state HOLD_DISC\n"); chan_misdn_log(1, bc->port, " --> cause %d\n",bc->cause); chan_misdn_log(1, bc->port, " --> out_cause %d\n",bc->out_cause); + bc->out_cause=-1; misdn_lib_send_event(bc,EVENT_RELEASE); + p->state=MISDN_CLEANING; break; default: - /* Alerting or Disconect */ - if (bc->nt) + if (bc->nt) { + bc->out_cause=-1; misdn_lib_send_event(bc, EVENT_RELEASE); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT); - p->state=MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */ + p->state=MISDN_CLEANING; + } else { + if (bc->need_disconnect) + misdn_lib_send_event(bc, EVENT_DISCONNECT); + } } + + p->state=MISDN_CLEANING; } - chan_misdn_log(1, bc->port, "Channel: %s hanguped\n",ast->name); + + chan_misdn_log(1, bc->port, "Channel: %s hanguped new state:%s\n",ast->name,misdn_get_ch_state(p)); return 0; } -struct ast_frame *misdn_read(struct ast_channel *ast) +static struct ast_frame *misdn_read(struct ast_channel *ast) { struct chan_list *tmp; + int len; - char blah[255]; - int len =0 ; - - if (!ast) return NULL; - if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) return NULL; - if (!tmp->bc) return NULL; - - - read(tmp->pipe[0],blah,sizeof(blah)); - - - len = misdn_ibuf_usedcount(tmp->bc->astbuf); + if (!ast) { + chan_misdn_log(1,0,"misdn_read called without ast\n"); + return NULL; + } + if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) { + chan_misdn_log(1,0,"misdn_read called without ast->pvt\n"); + return NULL; + } + if (!tmp->bc) { + chan_misdn_log(1,0,"misdn_read called without bc\n"); + return NULL; + } - /*shrinken len if necessary, we transmit at maximum 4k*/ - len = len<=sizeof(tmp->ast_rd_buf)?len:sizeof(tmp->ast_rd_buf); - - misdn_ibuf_memcpy_r(tmp->ast_rd_buf, tmp->bc->astbuf,len); + len=read(tmp->pipe[0],tmp->ast_rd_buf,sizeof(tmp->ast_rd_buf)); + if (len<=0) { + /* we hangup here, since our pipe is closed */ + chan_misdn_log(2,tmp->bc->port,"misdn_read: Pipe closed, hanging up\n"); + return NULL; + } + tmp->frame.frametype = AST_FRAME_VOICE; tmp->frame.subclass = AST_FORMAT_ALAW; tmp->frame.datalen = len; @@ -1739,41 +2133,59 @@ struct ast_frame *misdn_read(struct ast_channel *ast) tmp->frame.offset= 0 ; tmp->frame.src = NULL; tmp->frame.data = tmp->ast_rd_buf ; - - chan_misdn_trace_call(tmp->ast,3,"*->I: EVENT_READ len=%d\n",len); + + if (tmp->faxdetect || tmp->ast_dsp ) { + return process_ast_dsp(tmp, &tmp->frame); + } + return &tmp->frame; } -int misdn_write(struct ast_channel *ast, struct ast_frame *frame) + +static int misdn_write(struct ast_channel *ast, struct ast_frame *frame) { - struct chan_list *p; + struct chan_list *ch; int i = 0; - if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; + if (!ast || ! (ch=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; - if (!p->bc ) { + if (!ch->bc ) { ast_log(LOG_WARNING, "private but no bc\n"); return -1; } - if (p->bc->tone != TONE_NONE) - manager_send_tone(p->bc,TONE_NONE); - - - if (p->holded ) { - chan_misdn_log(5, p->bc->port, "misdn_write: Returning because holded\n"); + if (ch->state == MISDN_HOLDED) { + chan_misdn_log(8, ch->bc->port, "misdn_write: Returning because holded\n"); return 0; } - if (p->notxtone) { - chan_misdn_log(5, p->bc->port, "misdn_write: Returning because notxone\n"); + if (ch->notxtone) { + chan_misdn_log(9, ch->bc->port, "misdn_write: Returning because notxone\n"); + return 0; + } + + + if ( !frame->subclass) { + chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n"); return 0; } if ( !(frame->subclass & prefformat)) { - chan_misdn_log(0, p->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass); + + chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass); + return 0; } + + if ( !frame->samples ) { + chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n"); + return 0; + } + + if ( ! ch->bc->addr ) { + chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples); + return 0; + } #if MISDN_DEBUG { @@ -1785,13 +2197,48 @@ int misdn_write(struct ast_channel *ast, struct ast_frame *frame) printf ("\n"); } #endif - chan_misdn_trace_call(ast,3,"*->I: EVENT_WRITE len=%d\n",frame->samples); - i= manager_tx2misdn_frm(p->bc, frame->data, frame->samples); + + + switch (ch->bc->bc_state) { + case BCHAN_ACTIVATED: + case BCHAN_BRIDGED: + break; + default: + if (!ch->dropped_frame_cnt) + chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) droping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d\n",frame->samples,ch->bc->addr, ast->exten, ast->cid.cid_num,misdn_get_ch_state( ch), ch->bc->bc_state); + + ch->dropped_frame_cnt++; + if (ch->dropped_frame_cnt > 100) { + ch->dropped_frame_cnt=0; + chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) droping: %d frames addr:%x dropped > 100 frames!\n",frame->samples,ch->bc->addr); + + } + + return 0; + } + + 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) { + if (ch->bc->active) + cb_log(0,ch->bc->port,"Misdn Jitterbuffer Overflow.\n"); + } + + } else { + /*transmit without jitterbuffer*/ + i=misdn_lib_tx2misdn_frm(ch->bc, frame->data, frame->samples); + } + + return 0; } + + enum ast_bridge_result misdn_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, @@ -1819,47 +2266,69 @@ enum ast_bridge_result misdn_bridge (struct ast_channel *c0, int bridging; misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int)); if (bridging) { - int ecwb; - misdn_cfg_get( ch1->bc->port, MISDN_CFG_ECHOCANCELWHENBRIDGED, &ecwb, sizeof(int)); - if ( !ecwb ) { - chan_misdn_log(0, ch1->bc->port, "Disabling Echo Cancellor when Bridged\n"); + int ec; + misdn_cfg_get( ch1->bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); + if ( ec ) { + chan_misdn_log(2, ch1->bc->port, "Disabling Echo Cancellor when Bridged\n"); ch1->bc->ec_enable=0; manager_ec_disable(ch1->bc); } - misdn_cfg_get( ch2->bc->port, MISDN_CFG_ECHOCANCELWHENBRIDGED, &ecwb, sizeof(int)); - if ( !ecwb ) { - chan_misdn_log(0, ch2->bc->port, "Disabling Echo Cancellor when Bridged\n"); + misdn_cfg_get( ch2->bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); + if ( ec ) { + chan_misdn_log(2, ch2->bc->port, "Disabling Echo Cancellor when Bridged\n"); ch2->bc->ec_enable=0; - manager_ec_disable(ch2->bc); + manager_ec_disable(ch2->bc); } /* trying to make a mISDN_dsp conference */ - chan_misdn_log(0, ch1->bc->port, "I SEND: Making conference with Number:%d\n", (ch1->bc->pid<<1) +1); - + chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid +1); + misdn_lib_bridge(ch1->bc,ch2->bc); } - chan_misdn_log(1, ch1->bc->port, "* Makeing Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad); - + chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad); + + + if (! (flags&AST_BRIDGE_DTMF_CHANNEL_0) ) + ch1->ignore_dtmf=1; + + if (! (flags&AST_BRIDGE_DTMF_CHANNEL_1) ) + ch2->ignore_dtmf=1; + + while(1) { to=-1; who = ast_waitfor_n(carr, 2, &to); if (!who) { - ast_log(LOG_DEBUG,"misdn_bridge: empty read\n"); - continue; + ast_log(LOG_NOTICE,"misdn_bridge: empty read, breaking out\n"); + break; } f = ast_read(who); if (!f || f->frametype == AST_FRAME_CONTROL) { /* got hangup .. */ + + if (!f) + chan_misdn_log(1,ch1->bc->port,"Read Null Frame\n"); + else + chan_misdn_log(1,ch1->bc->port,"Read Frame Controll class:%d\n",f->subclass); + *fo=f; *rc=who; break; } - - + + if ( f->frametype == AST_FRAME_DTMF ) { + chan_misdn_log(1,0,"Read DTMF %d from %s\n",f->subclass, who->exten); + + *fo=f; + *rc=who; + break; + } + + if (who == c0) { ast_write(c1,f); } @@ -1868,20 +2337,67 @@ enum ast_bridge_result misdn_bridge (struct ast_channel *c0, } } - - if (bridging) { - misdn_lib_split_bridge(ch1->bc,ch2->bc); + + chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1); + + misdn_lib_split_bridge(ch1->bc,ch2->bc); + + + return AST_BRIDGE_COMPLETE; +} + +/** AST INDICATIONS END **/ + +static int dialtone_indicate(struct chan_list *cl) +{ + const struct tone_zone_sound *ts= NULL; + struct ast_channel *ast=cl->ast; + + + int nd=0; + misdn_cfg_get( cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd)); + + if (nd) { + chan_misdn_log(1,cl->bc->port,"Not sending Dialtone, because config wants it\n"); + return 0; } - + + chan_misdn_log(3,cl->bc->port," --> Dial\n"); + ts=ast_get_indication_tone(ast->zone,"dial"); + cl->ts=ts; + + if (ts) { + cl->notxtone=0; + cl->norxtone=0; + ast_playtones_start(ast,0, ts->data, 0); + chan_misdn_log(4,cl->bc->port,"Starting Playtones\n"); + misdn_lib_tone_generator_start(cl->bc); + } + + return 0; +} + +static int hanguptone_indicate(struct chan_list *cl) +{ + misdn_lib_send_tone(cl->bc,TONE_HANGUP); + return 0; +} + +static int stop_indicate(struct chan_list *cl) +{ + struct ast_channel *ast=cl->ast; + chan_misdn_log(3,cl->bc->port," --> None\n"); + misdn_lib_tone_generator_stop(cl->bc); + ast_playtones_stop(ast); + /*ast_deactivate_generator(ast);*/ + return 0; } -/** AST INDICATIONS END **/ static int start_bc_tones(struct chan_list* cl) { - manager_bchannel_activate(cl->bc); - manager_send_tone(cl->bc ,TONE_NONE); + misdn_lib_tone_generator_stop(cl->bc); cl->notxtone=0; cl->norxtone=0; return 0; @@ -1889,9 +2405,8 @@ static int start_bc_tones(struct chan_list* cl) static int stop_bc_tones(struct chan_list *cl) { - if (cl->bc) { - manager_bchannel_deactivate(cl->bc); - } + if (!cl) return -1; + cl->notxtone=1; cl->norxtone=1; @@ -1899,16 +2414,21 @@ static int stop_bc_tones(struct chan_list *cl) } -struct chan_list *init_chan_list(void) +static struct chan_list *init_chan_list(int orig) { struct chan_list *cl=malloc(sizeof(struct chan_list)); if (!cl) { - chan_misdn_log(0, 0, "misdn_request: malloc failed!"); + chan_misdn_log(-1, 0, "misdn_request: malloc failed!"); return NULL; } memset(cl,0,sizeof(struct chan_list)); + + cl->orginator=orig; + cl->need_queue_hangup=1; + cl->need_hangup=1; + cl->need_busy=1; return cl; @@ -1918,30 +2438,22 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat { struct ast_channel *tmp = NULL; - char group[BUFFERSIZE]=""; + char group[BUFFERSIZE+1]=""; char buf[128]; char buf2[128], *ext=NULL, *port_str; char *tokb=NULL, *p=NULL; int channel=0, port=0; struct misdn_bchannel *newbc = NULL; - struct chan_list *cl=init_chan_list(); + struct chan_list *cl=init_chan_list(ORG_AST); + + sprintf(buf,"%s/%s",misdn_type,(char*)data); + ast_copy_string(buf2,data, 128); - sprintf(buf,"%s/%s",type,(char*)data); - strncpy(buf2,data, 128); - buf2[127] = 0; port_str=strtok_r(buf2,"/", &tokb); ext=strtok_r(NULL,"/", &tokb); - /* - if (!ext) { - ast_log(LOG_WARNING, " --> ! IND : CALL dad:%s WITH WRONG ARGS, check extension.conf\n",ext); - - return NULL; - } - */ - if (port_str) { if (port_str[0]=='g' && port_str[1]==':' ) { /* We make a group call lets checkout which ports are in my group */ @@ -1951,11 +2463,11 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat chan_misdn_log(2, 0, " --> Group Call group: %s\n",group); } else if ((p = strchr(port_str, ':'))) { - // we have a preselected channel + /* we have a preselected channel */ *p = 0; channel = atoi(++p); port = atoi(port_str); - chan_misdn_log(2, port, " --> Call on preselected Channel (%d) on Port %d\n", channel, port); + chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel); } else { port = atoi(port_str); @@ -1969,7 +2481,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat if (!ast_strlen_zero(group)) { - char cfg_group[BUFFERSIZE]; + char cfg_group[BUFFERSIZE+1]; struct robin_list *rr = NULL; if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) { @@ -1993,8 +2505,9 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat if (port >= port_start) next_chan = 1; - if (port < port_start && next_chan) { - if (++robin_channel >= MAX_BCHANS) { + if (port <= port_start && next_chan) { + int maxbchans=misdn_lib_get_maxchans(port); + if (++robin_channel >= maxbchans) { robin_channel = 1; } next_chan = 0; @@ -2003,17 +2516,25 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE); if (!strcasecmp(cfg_group, group)) { - int l1, port_up; - - misdn_cfg_get( 0, MISDN_GEN_L1_INFO_OK, &l1, sizeof(l1)); - port_up = misdn_lib_port_up(port); + int port_up; + int check; + misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(int)); + port_up = misdn_lib_port_up(port, check); + + if (check && !port_up) + chan_misdn_log(1,port,"L1 is not Up on this Port\n"); - if ((l1 && port_up) || !l1) { + if (check && port_up<0) { + ast_log(LOG_WARNING,"This port (%d) is blocked\n", port); + } + + + if ( port_up>0 ) { newbc = misdn_lib_get_free_bc(port, robin_channel); if (newbc) { chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel); if (port_up) - chan_misdn_log(4, port, "def_l1:%d, portup:%d\n", l1, port_up); + chan_misdn_log(4, port, "portup:%d\n", port_up); rr->port = newbc->port; rr->channel = newbc->channel; break; @@ -2024,7 +2545,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat } while (!newbc && robin_channel != rr->channel); if (!newbc) - chan_misdn_log(4, port, " Failed! No free channel in group %d!", group); + chan_misdn_log(-1, port, " Failed! No free channel in group %d!", group); } else { @@ -2032,16 +2553,17 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat port=misdn_cfg_get_next_port(port)) { misdn_cfg_get( port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE); - + + chan_misdn_log(3,port, "Group [%s] Port [%d]\n", group, port); if (!strcasecmp(cfg_group, group)) { - int l1, port_up; + int port_up; + int check; + misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(int)); + port_up = misdn_lib_port_up(port, check); - misdn_cfg_get( 0, MISDN_GEN_L1_INFO_OK, &l1, sizeof(l1)); - port_up = misdn_lib_port_up(port); - - chan_misdn_log(4, port, "def_l1:%d, portup:%d\n", l1, port_up); + chan_misdn_log(4, port, "portup:%d\n", port_up); - if ((l1 && port_up) || !l1) { + if ( port_up>0 ) { newbc = misdn_lib_get_free_bc(port, 0); if (newbc) break; @@ -2057,20 +2579,45 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat } if (!newbc) { - chan_misdn_log(1, 0, " --> ! No free channel chan ext:%s even after Group Call\n",ext); - chan_misdn_log(1, 0, " --> SEND: State Down\n"); + chan_misdn_log(-1, 0, "Could not create channel on port:%d with extensions:%s\n",port,ext); return NULL; } - + + /* create ast_channel and link all the objects together */ cl->bc=newbc; - tmp = misdn_new(cl, AST_STATE_RESERVED, buf, "default", ext, ext, format, port, channel); + tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel); + cl->ast=tmp; + + /* register chan in local list */ + cl_queue_chan(&cl_te, cl) ; + + /* fill in the config into the objects */ + read_config(cl, ORG_AST); + + /* important */ + cl->need_hangup=0; return tmp; } -struct ast_channel_tech misdn_tech = { +int misdn_send_text (struct ast_channel *chan, const char *text) +{ + struct chan_list *tmp=chan->tech_pvt; + + if (tmp && tmp->bc) { + ast_copy_string(tmp->bc->display,text,sizeof(tmp->bc->display)); + misdn_lib_send_event(tmp->bc, EVENT_INFORMATION); + } else { + ast_log(LOG_WARNING, "No chan_list but send_text request?\n"); + return -1; + } + + return 0; +} + +static struct ast_channel_tech misdn_tech = { .type="mISDN", .description="Channel driver for mISDN Support (Bri/Pri)", .capabilities= AST_FORMAT_ALAW , @@ -2084,11 +2631,11 @@ struct ast_channel_tech misdn_tech = { .write=misdn_write, .indicate=misdn_indication, .fixup=misdn_fixup, + .send_text=misdn_send_text, .properties=0 - /* .transfer=misdn_transfer */ }; -struct ast_channel_tech misdn_tech_wo_bridge = { +static struct ast_channel_tech misdn_tech_wo_bridge = { .type="mISDN", .description="Channel driver for mISDN Support (Bri/Pri)", .capabilities=AST_FORMAT_ALAW , @@ -2101,69 +2648,64 @@ struct ast_channel_tech misdn_tech_wo_bridge = { .write=misdn_write, .indicate=misdn_indication, .fixup=misdn_fixup, + .send_text=misdn_send_text, .properties=0 - /* .transfer=misdn_transfer */ }; -unsigned long glob_channel=0; +static unsigned long glob_channel=0; -struct ast_channel *misdn_new(struct chan_list *chlist, int state, char * name, char * context, char *exten, char *callerid, int format, int port, int c) +static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char *exten, char *callerid, int format, int port, int c) { struct ast_channel *tmp; tmp = ast_channel_alloc(1); if (tmp) { - chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s ctx:%s\n",exten,callerid, context); + chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n",exten,callerid); if (c<=0) { c=glob_channel++; snprintf(tmp->name, sizeof(tmp->name), "%s/%d-u%d", - type, port, c); + misdn_type, port, c); } else { snprintf(tmp->name, sizeof(tmp->name), "%s/%d-%d", - type, port, c); + misdn_type, port, c); } - tmp->type = type; - + tmp->type = misdn_type; + tmp->nativeformats = prefformat; + tmp->readformat = format; + tmp->rawreadformat = format; tmp->writeformat = format; + tmp->rawwriteformat = format; tmp->tech_pvt = chlist; - + int bridging; misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int)); if (bridging) tmp->tech = &misdn_tech; else tmp->tech = &misdn_tech_wo_bridge; - - + tmp->writeformat = format; tmp->readformat = format; tmp->priority=1; - - if (context) { - ast_copy_string(tmp->context, context, sizeof(tmp->context)); - } else { - chan_misdn_log(1,0,"misdn_new: no context given.\n"); - } - - if (exten) { + if (exten) ast_copy_string(tmp->exten, exten, sizeof(tmp->exten)); - } else { + else chan_misdn_log(1,0,"misdn_new: no exten given.\n"); - } if (callerid) { char *cid_name, *cid_num; ast_callerid_parse(callerid, &cid_name, &cid_num); + if (!ast_strlen_zero(cid_num)) { tmp->cid.cid_num = strdup(cid_num); tmp->cid.cid_ani = strdup(cid_num); @@ -2180,193 +2722,107 @@ struct ast_channel *misdn_new(struct chan_list *chlist, int state, char * name, } - if (chlist->bc) { - int port=chlist->bc->port; - misdn_cfg_get( port, MISDN_CFG_LANGUAGE, tmp->language, sizeof(tmp->language)); - - { - char buf[256]; - ast_group_t pg,cg; - - misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); - misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); - - chan_misdn_log(2, port, " --> * CallGrp:%s PickupGrp:%s\n",ast_print_group(buf,sizeof(buf),cg),ast_print_group(buf,sizeof(buf),pg)); - tmp->pickupgroup=pg; - tmp->callgroup=cg; - } - misdn_cfg_get(port, MISDN_CFG_TXGAIN, &chlist->bc->txgain, sizeof(int)); - misdn_cfg_get(port, MISDN_CFG_RXGAIN, &chlist->bc->rxgain, sizeof(int)); - chan_misdn_log(2, port, " --> rxgain:%d txgain:%d\n",chlist->bc->rxgain,chlist->bc->txgain); - - } else { - chan_misdn_log(3, 0, " --> Not Setting Pickupgroup, we have no bc yet\n"); - } - ast_setstate(tmp, state); if (state == AST_STATE_RING) tmp->rings = 1; else tmp->rings = 0; + + } else { - ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); - chan_misdn_log(0,0,"Unable to allocate channel structure\n"); + chan_misdn_log(-1,0,"Unable to allocate channel structure\n"); } return tmp; } - -int misdn_tx2ast_frm(struct chan_list * tmp, char * buf, int len ) +struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame) { - struct ast_frame frame; - - /* If in hold state we drop frame .. */ - if (tmp->holded ) return 0; - - switch(tmp->state) { - case MISDN_CLEANING: - case MISDN_EXTCANTMATCH: - case MISDN_WAITING4DIGS: - return 0; - default: - break; - } - - if (tmp->norxtone) { - chan_misdn_log(3, tmp->bc->port, "misdn_tx2ast_frm: Returning because norxtone\n"); - return 0; + struct ast_frame *f,*f2; + if (tmp->trans) + f2=ast_translate(tmp->trans, frame,0); + else { + chan_misdn_log(0, tmp->bc->port, "No T-Path found\n"); + return NULL; } - frame.frametype = AST_FRAME_VOICE; - frame.subclass = AST_FORMAT_ALAW; - frame.datalen = len; - frame.samples = len ; - frame.mallocd =0 ; - frame.offset= 0 ; - frame.src = NULL; - frame.data = buf ; - - if (tmp->faxdetect || tmp->ast_dsp ) { - struct ast_frame *f,*f2; - if (tmp->trans) - f2=ast_translate(tmp->trans, &frame,0); - else { - chan_misdn_log(0, tmp->bc->port, "No T-Path found\n"); - return 0; - } - - 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); + 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_DEBUG, "Already in a fax extension, not redirecting\n"); + ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n",ast->context, ast->exten); } else - ast_log(LOG_DEBUG, "Fax already handled\n"); - frame.frametype = AST_FRAME_NULL; - frame.subclass = 0; - f = &frame; - } else if ( tmp->ast_dsp) { - struct ast_frame fr; - memset(&fr, 0 , sizeof(fr)); - fr.frametype = AST_FRAME_DTMF; - fr.subclass = f->subclass ; - fr.src=NULL; - fr.data = NULL ; - fr.datalen = 0; - fr.samples = 0 ; - fr.mallocd =0 ; - fr.offset= 0 ; - - chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n",f->subclass); - ast_queue_frame(tmp->ast, &fr); - - frame.frametype = AST_FRAME_NULL; - frame.subclass = 0; - f = &frame; - } + ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); + } else + ast_log(LOG_DEBUG, "Fax already handled\n"); + + } else if ( tmp->ast_dsp) { + chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n",f->subclass); + return f; } } - - if (tmp && tmp->ast && MISDN_ASTERISK_PVT (tmp->ast) && MISDN_ASTERISK_TECH_PVT(tmp->ast) ) { -#if MISDN_DEBUG - int i, max=5>len?len:5; - - printf("write2* %p %d bytes: ",tmp, len); - - for (i=0; i< max ; i++) printf("%2.2x ",((char*) frame.data)[i]); - printf ("\n"); -#endif - chan_misdn_log(9, tmp->bc->port, "Queueing %d bytes 2 Asterisk\n",len); - ast_queue_frame(tmp->ast,&frame); - - } else { - ast_log (LOG_WARNING, "No ast || ast->pvt || ch\n"); - } - - return 0; + + frame->frametype = AST_FRAME_NULL; + frame->subclass = 0; + return frame; } -/** Channel Queue ***/ -struct chan_list *find_chan_by_l3id(struct chan_list *list, unsigned long l3id) +static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc) { struct chan_list *help=list; for (;help; help=help->next) { - if (help->l3id == l3id ) return help; + if (help->bc == bc) return help; } - chan_misdn_log(4, list? (list->bc? list->bc->port : 0) : 0, "$$$ find_chan: No channel found with l3id:%x\n",l3id); + chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); return NULL; } -struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc) +static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid) { struct chan_list *help=list; for (;help; help=help->next) { - if (help->bc == bc) return help; + if (help->bc->pid == pid) return help; } - chan_misdn_log(4, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); + chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n",pid); return NULL; } - -struct chan_list *find_holded(struct chan_list *list, struct misdn_bchannel *bc) +static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchannel *bc) { struct chan_list *help=list; - chan_misdn_log(4, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n",bc->channel, bc->oad,bc->dad); + chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n",bc->channel, bc->oad,bc->dad); for (;help; help=help->next) { chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n",help->bc->holded, help->bc->channel); if (help->bc->port == bc->port && help->bc->holded ) return help; } - chan_misdn_log(4, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); + chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n",bc->oad,bc->dad); return NULL; } -void cl_queue_chan(struct chan_list **list, struct chan_list *chan) +static void cl_queue_chan(struct chan_list **list, struct chan_list *chan) { chan_misdn_log(4, chan->bc? chan->bc->port : 0, "* Queuing chan %p\n",chan); @@ -2382,12 +2838,13 @@ void cl_queue_chan(struct chan_list **list, struct chan_list *chan) ast_mutex_unlock(&cl_te_lock); } -void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan) +static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan) { if (chan->dsp) ast_dsp_free(chan->dsp); if (chan->trans) ast_translator_free_path(chan->trans); + ast_mutex_lock(&cl_te_lock); @@ -2419,35 +2876,88 @@ void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan) /** Channel Queue End **/ +int pbx_start_chan(struct chan_list *ch) +{ + int ret=ast_pbx_start(ch->ast); + + if (ret>=0) + ch->need_hangup=0; + else + ch->need_hangup=1; + + return ret; +} + +static void hangup_chan(struct chan_list *ch) +{ + if (!ch) { + cb_log(1,0,"Cannot hangup chan, no ch\n"); + return; + } + + cb_log(1,ch->bc?ch->bc->port:0,"hangup_chan\n"); + + if (ch->need_hangup) + { + cb_log(1,ch->bc->port,"-> hangup\n"); + send_cause2ast(ch->ast,ch->bc,ch); + ch->need_hangup=0; + ch->need_queue_hangup=0; + if (ch->ast) + ast_hangup(ch->ast); + return; + } + + if (!ch->need_queue_hangup) { + cb_log(1,ch->bc->port,"No need to queue hangup\n"); + } + + ch->need_queue_hangup=0; + if (ch->ast) { + send_cause2ast(ch->ast,ch->bc,ch); + + if (ch->ast) + ast_queue_hangup(ch->ast); + cb_log(1,ch->bc->port,"-> queue_hangup\n"); + } else { + cb_log(1,ch->bc->port,"Cannot hangup chan, no ast\n"); + } +} /** Isdn asks us to release channel, pendant to misdn_hangup **/ static void release_chan(struct misdn_bchannel *bc) { struct ast_channel *ast=NULL; - { struct chan_list *ch=find_chan_by_bc(cl_te, bc); - if (!ch) ch=find_chan_by_l3id (cl_te, bc->l3_id); + if (!ch) { + chan_misdn_log(0, bc->port, "release_chan: Ch not found!\n"); + return; + } - release_lock; if (ch->ast) { ast=ch->ast; } - release_unlock; - chan_misdn_log(1, bc->port, "Trying to Release bc with l3id: %x\n",bc->l3_id); + chan_misdn_log(1, bc->port, "release_chan: bc with l3id: %x\n",bc->l3_id); + + /*releaseing jitterbuffer*/ + if (ch->jb ) { + misdn_jb_destroy(ch->jb); + ch->jb=NULL; + } else { + if (!bc->nojitter) + chan_misdn_log(5,bc->port,"Jitterbuffer already destroyed.\n"); + } + if (ch) { - if (ast) - chan_misdn_trace_call(ast,1,"I->*: EVENT_RELEASE\n"); close(ch->pipe[0]); close(ch->pipe[1]); + - if (ast && MISDN_ASTERISK_PVT(ast)) { + if (ast && MISDN_ASTERISK_TECH_PVT(ast)) { chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n",bc?bc->pid:-1, ast->context, ast->exten,AST_CID_P(ast),misdn_get_ch_state(ch)); chan_misdn_log(3, bc->port, " --> * State Down\n"); - /* copy cause */ - send_cause2ast(ast,bc); - MISDN_ASTERISK_TECH_PVT(ast)=NULL; @@ -2455,58 +2965,9 @@ static void release_chan(struct misdn_bchannel *bc) { chan_misdn_log(3, bc->port, " --> Setting AST State to down\n"); ast_setstate(ast, AST_STATE_DOWN); } - - switch(ch->state) { - case MISDN_EXTCANTMATCH: - case MISDN_WAITING4DIGS: - { - chan_misdn_log(3, bc->port, " --> * State Wait4dig | ExtCantMatch\n"); - ast_hangup(ast); - } - break; - - case MISDN_DIALING: - case MISDN_CALLING_ACKNOWLEDGE: - case MISDN_PROGRESS: - chan_misdn_log(2, bc->port, "* --> In State Dialin\n"); - chan_misdn_log(2, bc->port, "* --> Queue Hangup\n"); - - - ast_queue_hangup(ast); - break; - case MISDN_CALLING: - - chan_misdn_log(2, bc->port, "* --> In State Callin\n"); - - if (!bc->nt) { - chan_misdn_log(2, bc->port, "* --> Queue Hangup\n"); - ast_queue_hangup(ast); - } else { - chan_misdn_log(2, bc->port, "* --> Hangup\n"); - ast_queue_hangup(ast); - //ast_hangup(ast); - } - break; - - case MISDN_CLEANING: - /* this state comes out of ast so we mustnt call a ast function ! */ - chan_misdn_log(2, bc->port, "* --> In StateCleaning\n"); - break; - case MISDN_HOLD_DISCONNECT: - chan_misdn_log(2, bc->port, "* --> In HOLD_DISC\n"); - break; - default: - chan_misdn_log(2, bc->port, "* --> In State Default\n"); - chan_misdn_log(2, bc->port, "* --> Queue Hangup\n"); - - - if (ast && MISDN_ASTERISK_PVT(ast)) { - ast_queue_hangup(ast); - } else { - chan_misdn_log (0, bc->port, "!! Not really queued!\n"); - } - } } + + ch->state=MISDN_CLEANING; cl_dequeue_chan(&cl_te, ch); free(ch); @@ -2517,7 +2978,7 @@ static void release_chan(struct misdn_bchannel *bc) { } /*** release end **/ -void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan) +static void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan) { chan_misdn_log(4,0,"TRANSFERING %s to %s\n",holded_chan->ast->name, tmp_ch->ast->name); @@ -2526,14 +2987,12 @@ void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan) ast_moh_stop(AST_BRIDGED_P(holded_chan->ast)); holded_chan->state=MISDN_CONNECTED; - holded_chan->holded=0; misdn_lib_transfer(holded_chan->bc?holded_chan->bc:holded_chan->holded_bc); - ast_channel_masquerade(holded_chan->ast, AST_BRIDGED_P(tmp_ch->ast)); } -void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct ast_channel *ast) +static void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct ast_channel *ast) { char predial[256]=""; char *p = predial; @@ -2543,7 +3002,7 @@ void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct strncpy(predial, ast->exten, sizeof(predial) -1 ); ch->state=MISDN_DIALING; - + if (bc->nt) { int ret; ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); @@ -2556,15 +3015,20 @@ void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct } } - manager_send_tone(bc,TONE_DIAL); + if ( !bc->nt && (ch->orginator==ORG_MISDN) && !ch->incoming_early_audio ) + chan_misdn_log(1,bc->port, " --> incoming_early_audio off\n"); + else + dialtone_indicate(ch); chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, AST_CID_P(ast)); strncpy(ast->exten,"s", 2); - if (ast_pbx_start(ast)<0) { + if (pbx_start_chan(ch)<0) { ast=NULL; - manager_send_tone(bc,TONE_BUSY); + hangup_chan(ch); + hanguptone_indicate(ch); + if (bc->nt) misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); else @@ -2591,7 +3055,19 @@ void do_immediate_setup(struct misdn_bchannel *bc,struct chan_list *ch , struct -void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc) { +static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch) { + if (!ast) { + chan_misdn_log(1,0,"send_cause2ast: No Ast\n"); + return; + } + if (!bc) { + chan_misdn_log(1,0,"send_cause2ast: No BC\n"); + return; + } + if (!ch) { + chan_misdn_log(1,0,"send_cause2ast: No Ch\n"); + return; + } ast->hangupcause=bc->cause; @@ -2603,55 +3079,122 @@ void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc) { case 4: case 22: case 27: + /* + * Not Queueing the Congestion anymore, since we want to hear + * the inband message + * chan_misdn_log(1, bc?bc->port:0, " --> * SEND: Queue Congestion pid:%d\n", bc?bc->pid:-1); + ch->state=MISDN_BUSY; ast_queue_control(ast, AST_CONTROL_CONGESTION); + */ break; case 21: case 17: /* user busy */ + + ch->state=MISDN_BUSY; + + if (!ch->need_busy) { + chan_misdn_log(1,bc?bc->port:0, "Queued busy already\n"); + break; + } + chan_misdn_log(1, bc?bc->port:0, " --> * SEND: Queue Busy pid:%d\n", bc?bc->pid:-1); ast_queue_control(ast, AST_CONTROL_BUSY); + ch->need_busy=0; + break; } } +void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) +{ + char *tmp; + tmp=pbx_builtin_getvar_helper(chan,"MISDN_PID"); + if (tmp) { + ch->other_pid=atoi(tmp); + chan_misdn_log(1,bc->port,"IMPORT_PID: importing pid:%s\n",tmp); + + if (ch->other_pid >0) { + ch->other_ch=find_chan_by_pid(cl_te,ch->other_pid); + if (ch->other_ch) ch->other_ch->other_ch=ch; + } + } +} + +void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) +{ + char tmp[32]; + + chan_misdn_log(1,bc->port,"EXPORT_PID: pid:%d\n",bc->pid); + sprintf(tmp,"%d",bc->pid); + pbx_builtin_setvar_helper(chan,"_MISDN_PID",tmp); +} + + + /************************************************************/ /* Receive Events from isdn_lib here */ /************************************************************/ -enum event_response_e +static enum event_response_e cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) { struct chan_list *ch=find_chan_by_bc(cl_te, bc); - if (!ch) - ch=find_chan_by_l3id(cl_te, bc->l3_id); + if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */ + int debuglevel=1; - if (event != EVENT_BCHAN_DATA) { /* Debug Only Non-Bchan */ - chan_misdn_log(1, bc->port, "I IND :%s oad:%s dad:%s port:%d\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->port); - misdn_lib_log_ies(bc); + if ( event==EVENT_CLEANUP && !user_data) + debuglevel=5; + + chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch?misdn_get_ch_state(ch):"none"); + if (debuglevel==1) { + misdn_lib_log_ies(bc); + chan_misdn_log(4,bc->port," --> bc_state:%s\n",bc_state2str(bc->bc_state)); + } } - if (event != EVENT_SETUP) { - if (!ch) { - if (event != EVENT_CLEANUP ) - ast_log(LOG_WARNING, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n",bc->l3_id, bc, manager_isdn_get_info( event), bc->port,bc->channel); - return -1; + if (!ch) { + switch(event) { + case EVENT_SETUP: + case EVENT_DISCONNECT: + case EVENT_PORT_ALARM: + case EVENT_RETRIEVE: + case EVENT_NEW_BC: + break; + case EVENT_RELEASE_COMPLETE: + chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n"); + break; + case EVENT_CLEANUP: + case EVENT_TONE_GENERATE: + case EVENT_BCHAN_DATA: + return -1; + + default: + chan_misdn_log(1,bc->port, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n",bc->l3_id, bc, manager_isdn_get_info( event), bc->port,bc->channel); + return -1; } } if (ch ) { switch (event) { + case EVENT_TONE_GENERATE: + break; + case EVENT_DISCONNECT: case EVENT_RELEASE: case EVENT_RELEASE_COMPLETE: case EVENT_CLEANUP: + case EVENT_TIMEOUT: + if (!ch->ast) + chan_misdn_log(3,bc->port,"ast_hangup already called, so we have no ast ptr anymore in event(%s)\n",manager_isdn_get_info(event)); break; default: if ( !ch->ast || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) { if (event!=EVENT_BCHAN_DATA) - ast_log(LOG_WARNING, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event)); + ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event)); return -1; } } @@ -2659,13 +3202,38 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) switch (event) { + case EVENT_PORT_ALARM: + { + int boa=0; + + misdn_cfg_get( bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(int)); + if (boa) { + cb_log(1,bc->port," --> blocking\n"); + misdn_lib_port_block(bc->port); + } + } + break; + + case EVENT_BCHAN_ACTIVATED: + break; + case EVENT_NEW_L3ID: ch->l3id=bc->l3_id; + ch->addr=bc->addr; break; case EVENT_NEW_BC: + if (!ch) { + ch=find_holded(cl_te,bc); + } + + if (!ch) { + ast_log(LOG_WARNING,"NEW_BC without chan_list?\n"); + break; + } + if (bc) - ch->bc=bc; + ch->bc=(struct misdn_bchannel*)user_data; break; case EVENT_DTMF_TONE: @@ -2682,9 +3250,12 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) fr.mallocd =0 ; fr.offset= 0 ; - chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf); - - ast_queue_frame(ch->ast, &fr); + if (!ch->ignore_dtmf) { + chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf); + ast_queue_frame(ch->ast, &fr); + } else { + chan_misdn_log(2, bc->port, " --> Ingoring DTMF:%c due to bridge flags\n", bc->dtmf); + } } break; case EVENT_STATUS: @@ -2694,8 +3265,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) { int stop_tone; misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int)); - if ( stop_tone && bc->tone != TONE_NONE) { - manager_send_tone(bc,TONE_NONE); + if ( stop_tone ) { + stop_indicate(ch); } if (ch->state == MISDN_WAITING4DIGS ) { @@ -2714,31 +3285,46 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } /* chan_misdn_log(5, bc->port, "Can Match Extension: dad:%s oad:%s\n",bc->dad,bc->oad);*/ - char bc_context[BUFFERSIZE]; - misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, bc_context, BUFFERSIZE); - if(!ast_canmatch_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { - chan_misdn_log(0, bc->port, "Extension can never match, so disconnecting\n"); - manager_send_tone(bc,TONE_BUSY); + /* Check for Pickup Request first */ + if (!strcmp(ch->ast->exten, ast_pickup_ext())) { + int ret;/** Sending SETUP_ACK**/ + ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); + if (ast_pickup_call(ch->ast)) { + hangup_chan(ch); + } else { + struct ast_channel *chan=ch->ast; + ch->state = MISDN_CALLING_ACKNOWLEDGE; + ast_setstate(chan, AST_STATE_DOWN); + hangup_chan(ch); + ch->ast=NULL; + break; + } + } + + if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + + chan_misdn_log(-1, bc->port, "Extension can never match, so disconnecting\n"); + if (bc->nt) + hanguptone_indicate(ch); ch->state=MISDN_EXTCANTMATCH; bc->out_cause=1; - if (bc->nt) - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + + misdn_lib_send_event(bc, EVENT_DISCONNECT ); + break; } - if (ast_exists_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { ch->state=MISDN_DIALING; - manager_send_tone(bc,TONE_NONE); -/* chan_misdn_log(1, bc->port, " --> * Starting Ast ctx:%s\n", ch->ast->context);*/ - if (ast_pbx_start(ch->ast)<0) { - chan_misdn_log(0, bc->port, "ast_pbx_start returned < 0 in INFO\n"); - manager_send_tone(bc,TONE_BUSY); - if (bc->nt) - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + stop_indicate(ch); +/* chan_misdn_log(1, bc->port, " --> * Starting Ast ctx:%s\n", ch->context);*/ + if (pbx_start_chan(ch)<0) { + hangup_chan(ch); + + chan_misdn_log(-1, bc->port, "ast_pbx_start returned < 0 in INFO\n"); + if (bc->nt) hanguptone_indicate(ch); + + misdn_lib_send_event(bc, EVENT_DISCONNECT ); } } @@ -2771,7 +3357,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ast_queue_frame(ch->ast, &fr); } - } } break; @@ -2784,6 +3369,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } } + int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad); if (!bc->nt && ! msn_valid) { chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n"); @@ -2793,119 +3379,61 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) print_bearer(bc); { - struct chan_list *ch=init_chan_list(); + struct chan_list *ch=init_chan_list(ORG_MISDN); struct ast_channel *chan; - char name[128]; - if (!ch) { chan_misdn_log(0, bc->port, "cb_events: malloc for chan_list failed!\n"); return 0;} + + if (!ch) { chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n"); return 0;} ch->bc = bc; ch->l3id=bc->l3_id; ch->addr=bc->addr; ch->orginator = ORG_MISDN; + chan=misdn_new(ch, AST_STATE_RESERVED,bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel); + ch->ast = chan; + + read_config(ch, ORG_MISDN); - { - char prefix[BUFFERSIZE]=""; - switch( bc->onumplan ) { - case NUMPLAN_INTERNATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); - break; - - case NUMPLAN_NATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); - break; - - - case NUMPLAN_SUBSCRIBER: - /* dunno what to do here ? */ - break; + export_ch(chan, bc, ch); - case NUMPLAN_UNKNOWN: - break; - default: - break; - } + ch->ast->rings=1; + ast_setstate(ch->ast, AST_STATE_RINGING); - { - int l = strlen(prefix) + strlen(bc->oad); - char tmp[l+1]; - strcpy(tmp,prefix); - strcat(tmp,bc->oad); - strcpy(bc->oad,tmp); - } - - if (!ast_strlen_zero(bc->oad)) - sprintf(name,"mISDN/%d/%s",bc->port,bc->oad); - else - sprintf(name,"mISDN/%d",bc->port); + int pres,screen; + switch (bc->pres) { + case 1: + pres=AST_PRES_RESTRICTED; chan_misdn_log(2,bc->port," --> PRES: Restricted (1)\n"); + break; + case 2: + pres=AST_PRES_UNAVAILABLE; chan_misdn_log(2,bc->port," --> PRES: Restricted (2)\n"); + break; + default: + pres=AST_PRES_ALLOWED; chan_misdn_log(2,bc->port," --> PRES: Restricted (%d)\n", bc->pres); + } - if (!ast_strlen_zero(bc->dad)) { - strncpy(bc->orig_dad,bc->dad, sizeof(bc->orig_dad)); - bc->orig_dad[sizeof(bc->orig_dad)-1] = 0; - } - - if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) { - strncpy(bc->dad,bc->keypad, sizeof(bc->dad)); - bc->dad[sizeof(bc->dad)-1] = 0; - } - prefix[0] = 0; - - switch( bc->dnumplan ) { - case NUMPLAN_INTERNATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE); - break; - - case NUMPLAN_NATIONAL: - misdn_cfg_get( bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE); - break; - - - case NUMPLAN_SUBSCRIBER: - /* dunno what to do here ? */ - break; - - case NUMPLAN_UNKNOWN: - break; + switch (bc->screen) { + case 0: + screen=AST_PRES_USER_NUMBER_UNSCREENED; chan_misdn_log(2,bc->port," --> SCREEN: Unscreened (0)\n"); + break; + case 1: + screen=AST_PRES_USER_NUMBER_PASSED_SCREEN; chan_misdn_log(2,bc->port," --> SCREEN: Passed screen (1)\n"); + break; + case 2: + screen=AST_PRES_USER_NUMBER_FAILED_SCREEN; chan_misdn_log(2,bc->port," --> SCREEN: failed screen (2)\n"); + break; + case 3: + screen=AST_PRES_NETWORK_NUMBER; chan_misdn_log(2,bc->port," --> SCREEN: Network Number (3)\n"); + break; default: - break; - } - - { - int l = strlen(prefix) + strlen(bc->dad); - char tmp[l+1]; - strcpy(tmp,prefix); - strcat(tmp,bc->dad); - strcpy(bc->dad,tmp); - } - - char bc_context[BUFFERSIZE]; - misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, bc_context, BUFFERSIZE); - chan=misdn_new(ch, AST_STATE_RING,name ,bc_context, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel); - - if (!chan) { - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - return 0; - } - - ch->ast = chan; - pbx_builtin_setvar_helper(ch->ast,"REDIRECTING_NUMBER",bc->rad); - + screen=AST_PRES_USER_NUMBER_UNSCREENED; chan_misdn_log(2,bc->port," --> SCREEN: Unscreened (%d)\n",bc->screen); } - + chan->cid.cid_pres=pres+screen; - chan_misdn_trace_call(chan,1,"I->*: EVENT_SETUP\n"); - - if ( bc->pres ) { - chan->cid.cid_pres=AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; - } else { - chan->cid.cid_pres=AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; - } - pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability)); chan->transfercapability=bc->capability; - + switch (bc->capability) { case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: pbx_builtin_setvar_helper(chan,"CALLTYPE","DIGITAL"); @@ -2917,113 +3445,88 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) /** queue new chan **/ cl_queue_chan(&cl_te, ch) ; - - /* - added support for s extension hope it will help those poor cretains - which haven't overlap dial. - */ - { - - misdn_cfg_get( bc->port, MISDN_CFG_LANGUAGE, chan->language, sizeof(chan->language)); - - } - - { - int eb3; - - misdn_cfg_get( bc->port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int)); - bc->early_bconnect=eb3; - - } - { - int ec, ectr; - - misdn_cfg_get( bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int)); - - misdn_cfg_get( bc->port, MISDN_CFG_ECHOTRAINING, &ectr, sizeof(int)); - if (ec == 1 ) { - bc->ec_enable=1; - } else if ( ec > 1 ) { - bc->ec_enable=1; - bc->ec_deftaps=ec; - } - - if ( ectr>=0 ) { - bc->ec_training=ectr; + if (!strstr(ch->allowed_bearers,"all")) { + int i; + for (i=0; i< sizeof(allowed_bearers_array)/sizeof(struct allowed_bearers); i++) { + if (allowed_bearers_array[i].cap == bc->capability) { + if ( !strstr( ch->allowed_bearers, allowed_bearers_array[i].name)) { + chan_misdn_log(0,bc->port,"Bearer Not allowed\b"); + bc->out_cause=88; + + ch->state=MISDN_EXTCANTMATCH; + misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); + return RESPONSE_OK; + } + } + } } - - if (bc->urate>0) { - char buf[16]; - snprintf(buf,16,"%d",bc->urate); - pbx_builtin_setvar_helper(chan,"MISDN_URATE",buf); - } - - - - /** - from here on we start the PBX, so no configuration should - be considered anymore - **/ - - int ai; - misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai)); - if ( ai ) { - do_immediate_setup(bc, ch , chan); - break; - } - - - int immediate; - misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &immediate, sizeof(int)); - - if (ast_strlen_zero(bc->orig_dad) && immediate ) { - do_immediate_setup(bc, ch , chan); - break; - } - /* Check for Pickup Request first */ if (!strcmp(chan->exten, ast_pickup_ext())) { int ret;/** Sending SETUP_ACK**/ ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); - if (ast_pickup_call(chan)) { - ast_hangup(chan); + hangup_chan(ch); } else { ch->state = MISDN_CALLING_ACKNOWLEDGE; - - ch->ast=NULL; - ast_setstate(chan, AST_STATE_DOWN); - ast_hangup(chan); - + hangup_chan(ch); + ch->ast=NULL; break; } } - /** Now after we've finished configuring our channel object - we'll jump into the dialplan **/ + /* + added support for s extension hope it will help those poor cretains + which haven't overlap dial. + */ + { + int ai; + misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai)); + if ( ai ) { + do_immediate_setup(bc, ch , chan); + break; + } + + + + } + + /* check if we should jump into s when we have no dad */ + { + int im; + misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im)); + if ( im && ast_strlen_zero(bc->dad) ) { + do_immediate_setup(bc, ch , chan); + break; + } + } + - char bc_context[BUFFERSIZE]; - misdn_cfg_get( bc->port, MISDN_CFG_CONTEXT, bc_context, BUFFERSIZE); - if(!ast_canmatch_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { - chan_misdn_log(0, bc->port, "Extension can never match, so disconnecting\n"); - manager_send_tone(bc,TONE_BUSY); + chan_misdn_log(5,bc->port,"CONTEXT:%s\n",ch->context); + if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { + + chan_misdn_log(-1, bc->port, "Extension can never match, so disconnecting\n"); + + if (bc->nt) + hanguptone_indicate(ch); ch->state=MISDN_EXTCANTMATCH; bc->out_cause=1; + if (bc->nt) misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + misdn_lib_send_event(bc, EVENT_RELEASE ); + break; } - if (ast_exists_extension(ch->ast, bc_context, bc->dad, 1, bc->oad)) { + if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { ch->state=MISDN_DIALING; - - if (bc->nt) { + + if (bc->nt || (bc->need_more_infos && misdn_lib_is_ptp(bc->port)) ) { int ret; ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); } else { @@ -3031,31 +3534,53 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ret= misdn_lib_send_event(bc, EVENT_PROCEEDING ); } - if (ast_pbx_start(chan)<0) { - chan_misdn_log(0, bc->port, "ast_pbx_start returned <0 in SETUP\n"); + if (pbx_start_chan(ch)<0) { + hangup_chan(ch); + + chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n"); chan=NULL; - manager_send_tone(bc,TONE_BUSY); - if (bc->nt) + + if (bc->nt) { + hanguptone_indicate(ch); misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); - else - misdn_lib_send_event(bc, EVENT_DISCONNECT ); + } else + misdn_lib_send_event(bc, EVENT_RELEASE); } } else { - int ret= misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); - if (ret == -ENOCHAN) { - ast_log(LOG_WARNING,"Channel was catched, before we could Acknowledge\n"); - misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); + + if (bc->sending_complete) { + ch->state=MISDN_EXTCANTMATCH; + bc->out_cause=1; + + if (bc->nt) { + chan_misdn_log(0,bc->port," --> sending_complete so we never match ..\n"); + misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE); + } else { + chan_misdn_log(0,bc->port," --> sending_complete so we never match ..\n"); + misdn_lib_send_event(bc, EVENT_RELEASE); + } + + } else { + + int ret= misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); + if (ret == -ENOCHAN) { + ast_log(LOG_WARNING,"Channel was catched, before we could Acknowledge\n"); + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); + } + /* send tone to phone :) */ + + /** ADD IGNOREPAT **/ + + int stop_tone; + misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int)); + if ( (!ast_strlen_zero(bc->dad)) && stop_tone ) + stop_indicate(ch); + else { + dialtone_indicate(ch); + } + + ch->state=MISDN_WAITING4DIGS; } - /* send tone to phone :) */ - - int stop_tone; - misdn_cfg_get( 0, MISDN_GEN_STOP_TONE, &stop_tone, sizeof(int)); - if ( (!ast_strlen_zero(bc->dad)) && stop_tone ) - manager_send_tone(bc,TONE_NONE); - else - manager_send_tone(bc,TONE_DIAL); - - ch->state=MISDN_WAITING4DIGS; } } @@ -3094,6 +3619,10 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) misdn_inband_avail(bc) ) { start_bc_tones(ch); } + + ch->state = MISDN_PROCEEDING; + + ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING); } break; case EVENT_PROGRESS: @@ -3121,162 +3650,272 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) cb_log(1,bc->port,"Set State Ringing\n"); if ( misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) { - start_bc_tones(ch); - } + cb_log(1,bc->port,"Starting Tones, we have inband Data\n"); + start_bc_tones(ch); + } else { + cb_log(1,bc->port,"We have no inband Data, the other end must create ringing\n"); + if (ch->far_alerting) { + cb_log(1,bc->port,"The other end can not do ringing eh ?.. we must do all ourself.."); + start_bc_tones(ch); + /*tone_indicate(ch, TONE_FAR_ALERTING);*/ + } + } } break; case EVENT_CONNECT: + { + /*we answer when we've got our very new L3 ID from the NT stack */ misdn_lib_send_event(bc,EVENT_CONNECT_ACKNOWLEDGE); + + struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); + + misdn_lib_echo(bc,0); + stop_indicate(ch); + + if (bridged && !strcasecmp(bridged->tech->type,"mISDN")) { + struct chan_list *bridged_ch=MISDN_ASTERISK_TECH_PVT(bridged); + + chan_misdn_log(1,bc->port," --> copying cpndialplan:%d and cad:%s to the A-Channel\n",bc->cpnnumplan,bc->cad); + if (bridged_ch) { + bridged_ch->bc->cpnnumplan=bc->cpnnumplan; + ast_copy_string(bridged_ch->bc->cad,bc->cad,sizeof(bc->cad)); + } + } + } + + + /* notice that we don't break here!*/ + case EVENT_CONNECT_ACKNOWLEDGE: { - bc->state=STATE_CONNECTED; - ch->l3id=bc->l3_id; ch->addr=bc->addr; start_bc_tones(ch); - chan_misdn_trace_call(ch->ast,1,"I->*: EVENT_CONNECT\n"); ch->state = MISDN_CONNECTED; ast_queue_control(ch->ast, AST_CONTROL_ANSWER); } break; case EVENT_DISCONNECT: - { - + /*we might not have an ch->ast ptr here anymore*/ + if (ch) { struct chan_list *holded_ch=find_holded(cl_te, bc); - - - send_cause2ast(ch->ast,bc); - - if (misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) { + + chan_misdn_log(3,bc->port," --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->orginator, bc->nt, misdn_inband_avail(bc), ch->state); + if ( ch->orginator==ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) { /* If there's inband information available (e.g. a recorded message saying what was wrong with the dialled number, or perhaps even giving an alternative number, then play it instead of immediately releasing the call */ + chan_misdn_log(1,bc->port, " --> Inband Info Avail, not sending RELEASE\n"); + + ch->state=MISDN_DISCONNECTED; start_bc_tones(ch); break; } /*Check for holded channel, to implement transfer*/ - if (holded_ch ) { + if (holded_ch && ch->ast ) { + cb_log(1,bc->port," --> found holded ch\n"); if (ch->state == MISDN_CONNECTED ) { misdn_transfer_bc(ch, holded_ch) ; - misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); - break; } + hangup_chan(ch); + release_chan(bc); + break; } stop_bc_tones(ch); - bc->out_cause=16; - misdn_lib_send_event(bc,EVENT_RELEASE); - + hangup_chan(ch); } + bc->out_cause=-1; + if (bc->need_release) misdn_lib_send_event(bc,EVENT_RELEASE); break; case EVENT_RELEASE: { - - switch ( bc->cause) { - - case -1: - /* - OK, it really sucks, this is a RELEASE from NT-Stack So we take - it and return easylie, It seems that we've send a DISCONNECT - before, so we should RELEASE_COMPLETE after that Disconnect - (looks like ALERTING State at misdn_hangup !! - */ - return RESPONSE_OK; - break; - } - - bc->out_cause=16; - stop_bc_tones(ch); + hangup_chan(ch); release_chan(bc); + + if (bc->need_release_complete) + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); } break; case EVENT_RELEASE_COMPLETE: { stop_bc_tones(ch); + hangup_chan(ch); + release_chan(bc); + if(ch) + ch->state=MISDN_CLEANING; + } + break; + case EVENT_CLEANUP: + { + stop_bc_tones(ch); + + switch(ch->state) { + case MISDN_CALLING: + bc->cause=27; /* Destination out of order */ + break; + default: + break; + } + + hangup_chan(ch); release_chan(bc); } break; + + case EVENT_TONE_GENERATE: + { + int tone_len=bc->tone_cnt; + struct ast_channel *ast=ch->ast; + void *tmp; + int res; + int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples); + + chan_misdn_log(9,bc->port,"TONE_GEN: len:%d\n"); + + if (!ast) break; + + if (!ast->generator) break; + + + tmp = ast->generatordata; + ast->generatordata = NULL; + generate = ast->generator->generate; + + if (tone_len <0 || tone_len > 512 ) { + ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n",tone_len); + tone_len=128; + } + + res = generate(ast, tmp, tone_len, tone_len); + ast->generatordata = tmp; + + if (res) { + ast_log(LOG_WARNING, "Auto-deactivating generator\n"); + ast_deactivate_generator(ast); + } else { + bc->tone_cnt=0; + } + } + break; + case EVENT_BCHAN_DATA: { - chan_misdn_trace_call(ch->ast,3,"I->*: EVENT_B_DATA len=%d\n",bc->bframe_len); - - if ( !misdn_cap_is_speech(ch->bc->capability) || bc->nojitter) { - misdn_tx2ast_frm(ch, bc->bframe, bc->bframe_len ); + if ( !misdn_cap_is_speech(ch->bc->capability) ) { + struct ast_frame frame; + /*In Data Modes we queue frames*/ + frame.frametype = AST_FRAME_VOICE; /*we have no data frames yet*/ + frame.subclass = AST_FORMAT_ALAW; + frame.datalen = bc->bframe_len; + frame.samples = bc->bframe_len ; + frame.mallocd =0 ; + frame.offset= 0 ; + frame.src = NULL; + frame.data = bc->bframe ; + + ast_queue_frame(ch->ast,&frame); } else { - int len=bc->bframe_len; - int free=misdn_ibuf_freecount(bc->astbuf); + fd_set wrfs; + struct timeval tv; + tv.tv_sec=0; + tv.tv_usec=0; + + FD_ZERO(&wrfs); + FD_SET(ch->pipe[1],&wrfs); - if (bc->bframe_len > free) { - ast_log(LOG_DEBUG, "sbuf overflow!\n"); - len=misdn_ibuf_freecount(bc->astbuf); + int t=select(FD_SETSIZE,NULL,&wrfs,NULL,&tv); - if (len == 0) { - ast_log(LOG_WARNING, "BCHAN_DATA: write buffer overflow port:%d channel:%d!\n",bc->port,bc->channel); - } + if (!t) { + chan_misdn_log(9, bc->port, "Select Timed out\n"); + break; } - misdn_ibuf_memcpy_w(bc->astbuf, bc->bframe, len); + if (t<0) { + chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n",strerror(errno)); + break; + } - { - char blah[1]="\0"; -#ifdef FLATTEN_JITTER - { - struct timeval tv; - gettimeofday(&tv,NULL); - - if (tv.tv_usec % 10000 > 0 ) { - write(ch->pipe[1], blah,sizeof(blah)); - bc->time_usec=tv.tv_usec; - } - } -#else - write(ch->pipe[1], blah,sizeof(blah)); -#endif - + if (FD_ISSET(ch->pipe[1],&wrfs)) { + chan_misdn_log(9, bc->port, "writing %d bytes 2 asterisk\n",bc->bframe_len); + int ret=write(ch->pipe[1], bc->bframe, bc->bframe_len); + if (ret<=0) { + chan_misdn_log(-1, bc->port, "Write returned <=0 (err=%s)\n",strerror(errno)); + } + } else { + chan_misdn_log(1, bc->port, "Wripe Pipe full!\n"); } } - } break; case EVENT_TIMEOUT: - break; /* Ignore now .. */ { - switch (ch->state) { + if (ch && bc) + chan_misdn_log(1,bc->port,"--> state: %s\n",misdn_get_ch_state(ch)); + + switch (ch->state) { case MISDN_CALLING: - chan_misdn_log(0, bc?bc->port:0, "GOT TIMOUT AT CALING pid:%d\n", bc?bc->pid:-1); - break; case MISDN_DIALING: case MISDN_PROGRESS: - break; + case MISDN_ALERTING: + case MISDN_PROCEEDING: + case MISDN_CALLING_ACKNOWLEDGE: + if (bc->nt) { + bc->progress_indicator=8; + hanguptone_indicate(ch); + } + + bc->out_cause=1; + misdn_lib_send_event(bc,EVENT_DISCONNECT); + break; + + case MISDN_WAITING4DIGS: + if (bc->nt) { + bc->progress_indicator=8; + bc->out_cause=1; + hanguptone_indicate(ch); + misdn_lib_send_event(bc,EVENT_DISCONNECT); + } else { + bc->out_cause=16; + misdn_lib_send_event(bc,EVENT_RELEASE); + } + + break; + + + case MISDN_CLEANING: + chan_misdn_log(1,bc->port," --> in state cleaning .. so ingoring, the stack should clean it for us\n"); + break; + default: misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); } } break; - case EVENT_CLEANUP: - { - stop_bc_tones(ch); - release_chan(bc); - } - break; + /***************************/ /** Suplementary Services **/ /***************************/ case EVENT_RETRIEVE: { + ch=find_holded(cl_te, bc); + if (!ch) { + ast_log(LOG_WARNING, "Found no Holded channel, cannot Retrieve\n"); + misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT); + break; + } struct ast_channel *hold_ast=AST_BRIDGED_P(ch->ast); ch->state = MISDN_CONNECTED; @@ -3297,34 +3936,77 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) misdn_cfg_get( bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(int)); if (!hold_allowed) { - chan_misdn_log(0, bc->port, "Hold not allowed on port:%d\n", bc->port); + + chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n"); misdn_lib_send_event(bc, EVENT_HOLD_REJECT); break; } +#if 0 { struct chan_list *holded_ch=find_holded(cl_te, bc); if (holded_ch) { misdn_lib_send_event(bc, EVENT_HOLD_REJECT); - chan_misdn_log(0, bc->port, "We can't use RETRIEVE at the moment due to mISDN bug!\n"); + + chan_misdn_log(-1, bc->port, "We can't use RETRIEVE at the moment due to mISDN bug!\n"); break; } } +#endif + struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); - if (AST_BRIDGED_P(ch->ast)){ + if (bridged){ + struct chan_list *bridged_ch=MISDN_ASTERISK_TECH_PVT(bridged); ch->state = MISDN_HOLDED; ch->l3id = bc->l3_id; - ast_moh_start(AST_BRIDGED_P(ch->ast), NULL); + bc->holded_bc=bridged_ch->bc; misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE); + + ast_moh_start(bridged, NULL); } else { misdn_lib_send_event(bc, EVENT_HOLD_REJECT); chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n"); } } break; + + case EVENT_FACILITY: + print_facility(bc); + + switch (bc->fac_type) { + case FACILITY_CALLDEFLECT: + { + struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); + struct chan_list *ch; + + if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) { + ch=MISDN_ASTERISK_TECH_PVT(bridged); + /*ch->state=MISDN_FACILITY_DEFLECTED;*/ + if (ch->bc) { + /* todo */ + } + + } + + } + + break; + default: + chan_misdn_log(1, bc->port," --> not yet handled\n"); + } + + break; + + case EVENT_RESTART: + + stop_bc_tones(ch); + release_chan(bc); + + break; + default: - ast_log(LOG_WARNING, "Got Unknown Event\n"); + ast_log(LOG_NOTICE, "Got Unknown Event\n"); break; } @@ -3341,13 +4023,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) *******************************************/ -int clearl3_true ( void ) { - int default_clearl3; - misdn_cfg_get( 0, MISDN_GEN_CLEAR_L3, &default_clearl3, sizeof(int)); - return default_clearl3; -} - -int g_config_initialized=0; +static int g_config_initialized=0; int load_module(void) { @@ -3359,7 +4035,7 @@ int load_module(void) if (max_ports<=0) { ast_log(LOG_ERROR, "Unable to initialize mISDN\n"); - return -1; + return 0; } @@ -3374,16 +4050,17 @@ int load_module(void) { - char tempbuf[BUFFERSIZE]; + char tempbuf[BUFFERSIZE+1]; misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, tempbuf, BUFFERSIZE); if (strlen(tempbuf)) tracing = 1; } ast_mutex_init(&cl_te_lock); - ast_mutex_init(&release_lock_mutex); + misdn_cfg_update_ptp(); misdn_cfg_get_ports_string(ports); + if (strlen(ports)) chan_misdn_log(0, 0, "Got: %s from get_ports\n",ports); @@ -3391,16 +4068,25 @@ int load_module(void) struct misdn_lib_iface iface = { .cb_event = cb_events, .cb_log = chan_misdn_log, - .cb_clearl3_true = clearl3_true + .cb_jb_empty = chan_misdn_jb_empty, }; if (misdn_lib_init(ports, &iface, NULL)) chan_misdn_log(0, 0, "No te ports initialized\n"); + + int ntflags=0; + char ntfile[BUFFERSIZE+1]; + + misdn_cfg_get( 0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(int)); + misdn_cfg_get( 0, MISDN_GEN_NTDEBUGFILE, &ntfile, BUFFERSIZE); + + misdn_lib_nt_debug_init(ntflags,ntfile); + } { if (ast_channel_register(&misdn_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); + ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type); unload_module(); return -1; } @@ -3418,17 +4104,30 @@ int load_module(void) ast_cli_register(&cli_show_port); ast_cli_register(&cli_show_stacks); + ast_cli_register(&cli_port_block); + ast_cli_register(&cli_port_unblock); ast_cli_register(&cli_restart_port); ast_cli_register(&cli_port_up); + ast_cli_register(&cli_port_down); ast_cli_register(&cli_set_debug); ast_cli_register(&cli_set_crypt_debug); ast_cli_register(&cli_reload); - ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_flags", + ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt", "misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n" "Sets mISDN opts. and optargs\n" "\n" + "The available options are:\n" + " d - Send display text on called phone, text is the optparam\n" + " n - don't detect dtmf tones on called channel\n" + " h - make digital outgoing call\n" + " c - make crypted outgoing call, param is keyindex\n" + " e - perform echo cancelation on this channel,\n" + " takes taps as arguments (32,64,128,256)\n" + " s - send Non Inband DTMF as inband\n" + " vr - rxgain control\n" + " vt - txgain control\n" ); @@ -3439,9 +4138,11 @@ int load_module(void) "Supported Facilities are:\n" "\n" "type=calldeflect args=Nr where to deflect\n" - "\n" ); - + + + misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE); + chan_misdn_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n"); return 0; @@ -3469,8 +4170,11 @@ int unload_module(void) ast_cli_unregister(&cli_show_config); ast_cli_unregister(&cli_show_port); ast_cli_unregister(&cli_show_stacks); + ast_cli_unregister(&cli_port_block); + ast_cli_unregister(&cli_port_unblock); ast_cli_unregister(&cli_restart_port); ast_cli_unregister(&cli_port_up); + ast_cli_unregister(&cli_port_down); ast_cli_unregister(&cli_set_debug); ast_cli_unregister(&cli_set_crypt_debug); ast_cli_unregister(&cli_reload); @@ -3480,6 +4184,7 @@ int unload_module(void) ast_channel_unregister(&misdn_tech); + free_robin_list(); misdn_cfg_destroy(); misdn_lib_destroy(); @@ -3492,6 +4197,13 @@ int unload_module(void) return 0; } +int reload(void) +{ + reload_config(); + + return 0; +} + int usecount(void) { int res; @@ -3511,102 +4223,7 @@ char *key(void) return ASTERISK_GPL_KEY; } -void chan_misdn_log(int level, int port, char *tmpl, ...) -{ - if (! ((0 <= port) && (port <= max_ports))) { - ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port); - return; - } - - va_list ap; - char buf[1024]; - - va_start(ap, tmpl); - vsnprintf( buf, 1023, tmpl, ap ); - va_end(ap); - - if (misdn_debug_only[port] ? (level==1 && misdn_debug[port]) || (level==misdn_debug[port]) : level <= misdn_debug[port]) { - ast_console_puts(buf); - } - - if (level <= misdn_debug[0] && tracing) { - time_t tm = time(NULL); - char *tmp=ctime(&tm),*p; - char file[BUFFERSIZE]; - misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, file, BUFFERSIZE); - FILE *fp= fopen(file, "a+"); - - p=strchr(tmp,'\n'); - if (p) *p=':'; - - if (!fp) { - ast_console_puts("Error opening Tracefile: "); - ast_console_puts(strerror(errno)); - ast_console_puts("\n"); - return ; - } - - fputs(tmp,fp); - fputs(" ", fp); - fputs(buf, fp); - - fclose(fp); - } -} - - -void chan_misdn_trace_call(struct ast_channel *chan, int debug, char *tmpl, ...) -{ - va_list ap; - char buf[1024]; - char name[1024]; - - int trace; - misdn_cfg_get( 0, MISDN_GEN_TRACE_CALLS, &trace, sizeof(int)); - if (!trace) return ; - - if (misdn_debug[0] < debug) return ; - - char tracedir[BUFFERSIZE]; - misdn_cfg_get( 0, MISDN_GEN_TRACE_DIR, tracedir, BUFFERSIZE); - sprintf(name,"%s/%s.%s",tracedir, chan->uniqueid, chan->cid.cid_num ); - - va_start(ap, tmpl); - - vsprintf( buf, tmpl, ap ); - - va_end(ap); - - time_t tm = time(NULL); - char *tmp=ctime(&tm),*p; - FILE *fp= fopen(name, "a"); - int fd; - - if (!fp) { - ast_console_puts("Error opening Tracefile"); - ast_console_puts(strerror(errno)); - ast_console_puts("\n"); - return ; - } - - fd=fileno(fp) ; - - flock(fd, LOCK_EX); - - p=strchr(tmp,'\n'); - if (p) *p=':'; - - - - fputs(tmp,fp); - fputs(" ", fp); - fputs(buf, fp); - flock(fd, LOCK_UN); - - fclose(fp); - -} /*** SOME APPS ;)***/ @@ -3615,9 +4232,10 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data) { struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan); char *tok, *tokb; - - if (strcasecmp(MISDN_ASTERISK_TYPE(chan),"mISDN")) { + chan_misdn_log(0,0,"TYPE: %s\n",chan->tech->type); + + if (strcasecmp(chan->tech->type,"mISDN")) { ast_log(LOG_WARNING, "misdn_facility makes only sense with chan_misdn channels!\n"); return -1; } @@ -3659,8 +4277,9 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) int keyidx=0; int rxgain=0; int txgain=0; - - if (strcasecmp(MISDN_ASTERISK_TYPE(chan),"mISDN")) { + int change_jitter=0; + + if (strcasecmp(chan->tech->type,"mISDN")) { ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n"); return -1; } @@ -3683,7 +4302,7 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) switch(tok[0]) { case 'd' : - strncpy(ch->bc->display,++tok,84); + ast_copy_string(ch->bc->display,++tok,84); chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n",ch->bc->display); break; @@ -3693,8 +4312,32 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) break; case 'j': - chan_misdn_log(1, ch->bc->port, "SETOPT: No jitter\n"); - ch->bc->nojitter=1; + chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n"); + tok++; + change_jitter=1; + + switch ( tok[0] ) { + case 'b' : + ch->jb_len=atoi(++tok); + chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n",ch->jb_len); + break; + case 't' : + ch->jb_upper_threshold=atoi(++tok); + chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n",ch->jb_upper_threshold); + break; + + case 'n': + ch->bc->nojitter=1; + chan_misdn_log(1, ch->bc->port, " --> nojitter\n"); + break; + + default: + ch->jb_len=4000; + ch->jb_upper_threshold=0; + chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n",ch->jb_len); + chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n",ch->jb_upper_threshold); + } + break; case 'v': @@ -3727,10 +4370,9 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) } { - int l = sizeof(ch->bc->crypt_key); - strncpy(ch->bc->crypt_key, misdn_key_vector[keyidx], l); - ch->bc->crypt_key[l-1] = 0; + ast_copy_string(ch->bc->crypt_key, misdn_key_vector[keyidx], sizeof(ch->bc->crypt_key)); } + chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n",misdn_key_vector[keyidx]); break; @@ -3738,7 +4380,9 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n"); if (neglect) { + chan_misdn_log(1, ch->bc->port, " --> disabled\n"); ch->bc->ec_enable=0; + } else { ch->bc->ec_enable=1; ch->bc->orig=ch->orginator; @@ -3752,18 +4396,12 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) case 'h': chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n"); + if (strlen(tok) > 1 && tok[1]=='1') { - chan_misdn_log(1, ch->bc->port, "SETOPT: Digital TRANS_DIGITAL\n"); - ch->bc->async=1; - ch->bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; - /*ch->bc->state=STATE_CONNECTED; - misdn_lib_setup_bc(ch->bc);*/ - } else { - ch->bc->async=0; - ch->bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; - /*ch->bc->state=STATE_CONNECTED; - misdn_lib_setup_bc(ch->bc);*/ - } + chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n"); + ch->bc->hdlc=1; + } + ch->bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; break; case 's': @@ -3798,6 +4436,10 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) break; } } + + if (change_jitter) + config_jitterbuffer(ch); + if (ch->faxdetect || ch->ast_dsp) { @@ -3816,3 +4458,246 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) } +int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len) +{ + struct chan_list *ch=find_chan_by_bc(cl_te, bc); + + if (ch && ch->jb) { + return misdn_jb_empty(ch->jb, buf, len); + } + + return -1; +} + + + +/*******************************************************/ +/***************** JITTERBUFFER ************************/ +/*******************************************************/ + + +/* allocates the jb-structure and initialise the elements*/ +struct misdn_jb *misdn_jb_init(int size, int upper_threshold) +{ + int i; + struct misdn_jb *jb = (struct misdn_jb*) malloc(sizeof(struct misdn_jb)); + jb->size = size; + jb->upper_threshold = upper_threshold; + jb->wp = 0; + jb->rp = 0; + jb->state_full = 0; + jb->state_empty = 0; + jb->bytes_wrote = 0; + jb->samples = (char *)malloc(size*sizeof(char)); + + if (!jb->samples) { + chan_misdn_log(-1,0,"No free Mem for jb->samples\n"); + return NULL; + } + + jb->ok = (char *)malloc(size*sizeof(char)); + + if (!jb->ok) { + chan_misdn_log(-1,0,"No free Mem for jb->ok\n"); + return NULL; + } + + for(i=0; i<size; i++) + jb->ok[i]=0; + + ast_mutex_init(&jb->mutexjb); + + return jb; +} + +/* frees the data and destroys the given jitterbuffer struct */ +void misdn_jb_destroy(struct misdn_jb *jb) +{ + ast_mutex_destroy(&jb->mutexjb); + + free(jb->samples); + free(jb); +} + +/* fills the jitterbuffer with len data returns < 0 if there was an + error (bufferoverflow). */ +int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len) +{ + int i, j, rp, wp; + + if (!jb || ! data) return 0; + + ast_mutex_lock (&jb->mutexjb); + + wp=jb->wp; + rp=jb->rp; + + for(i=0; i<len; i++) + { + jb->samples[wp]=data[i]; + jb->ok[wp]=1; + wp = (wp!=jb->size-1 ? wp+1 : 0); + + if(wp==jb->rp) + jb->state_full=1; + } + + if(wp>=rp) + jb->state_buffer=wp-rp; + else + jb->state_buffer= jb->size-rp+wp; + chan_misdn_log(9,0,"misdn_jb_fill: written:%d | Bufferstatus:%d p:%x\n",len,jb->state_buffer,jb); + + if(jb->state_full) + { + jb->wp=wp; + + rp=wp; + for(j=0; j<jb->upper_threshold; j++) + rp = (rp!=0 ? rp-1 : jb->size-1); + jb->rp=rp; + jb->state_full=0; + jb->state_empty=1; + + ast_mutex_unlock (&jb->mutexjb); + + return -1; + } + + if(!jb->state_empty) + { + jb->bytes_wrote+=len; + if(jb->bytes_wrote>=jb->upper_threshold) + { + jb->state_empty=1; + jb->bytes_wrote=0; + } + } + jb->wp=wp; + + ast_mutex_unlock (&jb->mutexjb); + + return 0; +} + +/* gets len bytes out of the jitterbuffer if available, else only the +available data is returned and the return value indicates the number +of data. */ +int misdn_jb_empty(struct misdn_jb *jb, char *data, int len) +{ + int i, wp, rp, read=0; + + ast_mutex_lock (&jb->mutexjb); + + rp=jb->rp; + wp=jb->wp; + + if(jb->state_empty) + { + for(i=0; i<len; i++) + { + if(wp==rp) + { + jb->rp=rp; + jb->state_empty=0; + + ast_mutex_unlock (&jb->mutexjb); + + return read; + } + else + { + if(jb->ok[rp]==1) + { + data[i]=jb->samples[rp]; + jb->ok[rp]=0; + rp=(rp!=jb->size-1 ? rp+1 : 0); + read+=1; + } + } + } + + if(wp >= rp) + jb->state_buffer=wp-rp; + else + jb->state_buffer= jb->size-rp+wp; + chan_misdn_log(9,0,"misdn_jb_empty: read:%d | Bufferstatus:%d p:%x\n",len,jb->state_buffer,jb); + + jb->rp=rp; + } + else + chan_misdn_log(9,0,"misdn_jb_empty: Wait...requested:%d p:%x\n",len,jb); + + ast_mutex_unlock (&jb->mutexjb); + + return read; +} + + + + +/*******************************************************/ +/*************** JITTERBUFFER END *********************/ +/*******************************************************/ + + + + +void chan_misdn_log(int level, int port, char *tmpl, ...) +{ + if (! ((0 <= port) && (port <= max_ports))) { + ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port); + port=0; + level=-1; + } + + va_list ap; + char buf[1024]; + char port_buf[8]; + sprintf(port_buf,"P[%2d] ",port); + + va_start(ap, tmpl); + vsnprintf( buf, 1023, tmpl, ap ); + va_end(ap); + + if (level == -1) + ast_log(LOG_WARNING, buf); + + else if (misdn_debug_only[port] ? + (level==1 && misdn_debug[port]) || (level==misdn_debug[port]) + : level <= misdn_debug[port]) { + + ast_console_puts(port_buf); + ast_console_puts(buf); + } + + if ((level <= misdn_debug[0]) && !ast_strlen_zero(global_tracefile) ) { + time_t tm = time(NULL); + char *tmp=ctime(&tm),*p; + + FILE *fp= fopen(global_tracefile, "a+"); + + p=strchr(tmp,'\n'); + if (p) *p=':'; + + if (!fp) { + ast_console_puts("Error opening Tracefile: [ "); + ast_console_puts(global_tracefile); + ast_console_puts(" ] "); + + ast_console_puts(strerror(errno)); + ast_console_puts("\n"); + return ; + } + + fputs(tmp,fp); + fputs(" ", fp); + fputs(port_buf,fp); + fputs(" ", fp); + fputs(buf, fp); + + fclose(fp); + } +} + + diff --git a/channels/chan_misdn_config.c b/channels/chan_misdn_config.c deleted file mode 100644 index 26598717c..000000000 --- a/channels/chan_misdn_config.c +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2005, Christian Richter - * - * Christian Richter <crich@beronet.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - * - */ - -/*! - * \file - * - * \brief chan_misdn configuration management - * \author Christian Richter <crich@beronet.com> - * - * \ingroup channel_drivers - */ - - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "chan_misdn_config.h" - -#include <asterisk/config.h> -#include <asterisk/channel.h> -#include <asterisk/logger.h> -#include <asterisk/lock.h> -#include <asterisk/strings.h> - -#include <asterisk/utils.h> -#define AST_LOAD_CFG ast_config_load -#define AST_DESTROY_CFG ast_config_destroy - -#define DEF_ECHOCANCEL 128 -#define DEF_ECHOTRAINING 1 - -struct msn_list { - char *msn; - struct msn_list *next; -}; - -struct port_config { - char *name; - int *rxgain; - int *txgain; - int *te_choose_channel; - char *context; - char *language; - char *callerid; - char *method; - int *dialplan; - int *localdialplan; - char *nationalprefix; - char *internationalprefix; - int *pres; - int *always_immediate; - int *immediate; - int *hold_allowed; - int *early_bconnect; - int *use_callingpres; - int *echocancel; - int *echocancelwhenbridged; - int *echotraining; - struct msn_list *msn_list; - ast_group_t *callgroup; /* Call group */ - ast_group_t *pickupgroup; /* Pickup group */ -}; - -struct general_config { - int *debug; - char *tracefile; - int *trace_calls; - char *trace_dir; - int *bridging; - int *stop_tone_after_first_digit; - int *append_digits2exten; - int *l1_info_ok; - int *clear_l3; - int *dynamic_crypt; - char *crypt_prefix; - char *crypt_keys; -}; - -/* array of port configs, default is at position 0. */ -static struct port_config **port_cfg; -/* max number of available ports, is set on init */ -static int max_ports; -/* general config */ -static struct general_config *general_cfg; -/* storing the ptp flag separated to save memory */ -static int *ptp; - -static ast_mutex_t config_mutex; - - -static inline void misdn_cfg_lock (void) { - ast_mutex_lock(&config_mutex); -} - -static inline void misdn_cfg_unlock (void) { - ast_mutex_unlock(&config_mutex); -} - -static void free_msn_list (struct msn_list* iter) { - if (iter->next) - free_msn_list(iter->next); - if (iter->msn) - free(iter->msn); - free(iter); -} - -static void free_port_cfg (void) { - - struct port_config **free_list = (struct port_config **)calloc(max_ports + 1, sizeof(struct port_config *)); - - int i, j; - - for (i = 0; i < max_ports; i++) { - if (port_cfg[i]) { - for (j = 0; j < max_ports && free_list[j]; j++) { - if (free_list[j] && free_list[j] == port_cfg[i]) - continue; /* already in list */ - free_list[j] = port_cfg[i]; - } - } - } - -#define FREE_ELEM(elem) ({ \ - if (free_list[i]->elem) \ - free(free_list[i]->elem); \ - }) - - for (i = 0; i < max_ports; i++) { - if (free_list[i]) { - FREE_ELEM(name); - FREE_ELEM(rxgain); - FREE_ELEM(txgain); - FREE_ELEM(te_choose_channel); - FREE_ELEM(context); - FREE_ELEM(language); - FREE_ELEM(callerid); - FREE_ELEM(method); - FREE_ELEM(dialplan); - FREE_ELEM(localdialplan); - FREE_ELEM(nationalprefix); - FREE_ELEM(internationalprefix); - FREE_ELEM(pres); - FREE_ELEM(always_immediate); - FREE_ELEM(immediate); - FREE_ELEM(hold_allowed); - FREE_ELEM(early_bconnect); - FREE_ELEM(use_callingpres); - FREE_ELEM(echocancel); - FREE_ELEM(echocancelwhenbridged); - FREE_ELEM(echotraining); - if (free_list[i]->msn_list) - free_msn_list(free_list[i]->msn_list); - FREE_ELEM(callgroup); - FREE_ELEM(pickupgroup); - free(free_list[i]); - } - } - free(free_list); -} - -static void free_general_cfg (void) { - -#define FREE_GEN_ELEM(elem) ({ \ - if (general_cfg->elem) \ - free(general_cfg->elem); \ - }) - - FREE_GEN_ELEM(debug); - FREE_GEN_ELEM(tracefile); - FREE_GEN_ELEM(trace_calls); - FREE_GEN_ELEM(trace_dir); - FREE_GEN_ELEM(bridging); - FREE_GEN_ELEM(stop_tone_after_first_digit); - FREE_GEN_ELEM(append_digits2exten); - FREE_GEN_ELEM(l1_info_ok); - FREE_GEN_ELEM(clear_l3); - FREE_GEN_ELEM(dynamic_crypt); - FREE_GEN_ELEM(crypt_prefix); - FREE_GEN_ELEM(crypt_keys); -} - -#define GET_PORTCFG_STRCPY(item) ({ \ - char *temp; \ - if (port_cfg[port] && port_cfg[port]->item) \ - temp = port_cfg[port]->item; \ - else \ - temp = port_cfg[0]->item; \ - if (!temp || !memccpy((void *)buf, (void *)temp, '\0', bufsize)) \ - memset(buf, 0, 1); \ - }) - -#define GET_GENCFG_STRCPY(item) ({ \ - if (general_cfg && general_cfg->item) { \ - if (!memccpy((void *)buf, (void *)general_cfg->item, '\0', bufsize)) \ - memset(buf, 0, 1); \ - } else \ - memset(buf, 0, 1); \ - }) - -#define GET_PORTCFG_MEMCPY(item) ({ \ - typeof(port_cfg[0]->item) temp; \ - if (port_cfg[port] && port_cfg[port]->item) \ - temp = port_cfg[port]->item; \ - else \ - temp = port_cfg[0]->item; \ - if (temp) { \ - int l = sizeof(*temp); \ - if (l > bufsize) \ - memset(buf, 0, bufsize); \ - else \ - memcpy(buf, temp, l); \ - } else \ - memset(buf, 0, bufsize); \ - }) - -#define GET_GENCFG_MEMCPY(item) ({ \ - if (general_cfg && general_cfg->item) { \ - typeof(general_cfg->item) temp = general_cfg->item; \ - int l = sizeof(*temp); \ - if (l > bufsize) \ - memset(buf, 0, bufsize); \ - else \ - memcpy(buf, temp, l); \ - } else \ - memset(buf, 0, bufsize); \ - }) - -void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void *buf, int bufsize) { - - if (!(elem > MISDN_GEN_FIRST) && !misdn_cfg_is_port_valid(port)) { - memset(buf, 0, bufsize); - ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port); - return; - } - - misdn_cfg_lock(); - - switch (elem) { - - /* port config elements */ - - case MISDN_CFG_PTP: if (sizeof(ptp[port]) <= bufsize) - memcpy(buf, &ptp[port], sizeof(ptp[port])); - else - buf = 0; /* error, should not happen */ - break; - case MISDN_CFG_GROUPNAME: GET_PORTCFG_STRCPY(name); - break; - case MISDN_CFG_RXGAIN: GET_PORTCFG_MEMCPY(rxgain); - break; - case MISDN_CFG_TXGAIN: GET_PORTCFG_MEMCPY(txgain); - break; - case MISDN_CFG_TE_CHOOSE_CHANNEL: - GET_PORTCFG_MEMCPY(te_choose_channel); - break; - case MISDN_CFG_CONTEXT: GET_PORTCFG_STRCPY(context); - break; - case MISDN_CFG_LANGUAGE: GET_PORTCFG_STRCPY(language); - break; - case MISDN_CFG_CALLERID: GET_PORTCFG_STRCPY(callerid); - break; - case MISDN_CFG_METHOD: GET_PORTCFG_STRCPY(method); - break; - case MISDN_CFG_DIALPLAN: GET_PORTCFG_MEMCPY(dialplan); - break; - case MISDN_CFG_LOCALDIALPLAN: GET_PORTCFG_MEMCPY(localdialplan); - break; - case MISDN_CFG_NATPREFIX: GET_PORTCFG_STRCPY(nationalprefix); - break; - case MISDN_CFG_INTERNATPREFIX: - GET_PORTCFG_STRCPY(internationalprefix); - break; - case MISDN_CFG_PRES: GET_PORTCFG_MEMCPY(pres); - break; - case MISDN_CFG_ALWAYS_IMMEDIATE: - GET_PORTCFG_MEMCPY(always_immediate); - break; - case MISDN_CFG_IMMEDIATE: GET_PORTCFG_MEMCPY(immediate); - break; - case MISDN_CFG_HOLD_ALLOWED: - GET_PORTCFG_MEMCPY(hold_allowed); - break; - case MISDN_CFG_EARLY_BCONNECT: - GET_PORTCFG_MEMCPY(early_bconnect); - break; - case MISDN_CFG_USE_CALLINGPRES: - GET_PORTCFG_MEMCPY(use_callingpres); - break; - case MISDN_CFG_ECHOCANCEL: - GET_PORTCFG_MEMCPY(echocancel ); - break; - case MISDN_CFG_ECHOCANCELWHENBRIDGED: - GET_PORTCFG_MEMCPY(echocancelwhenbridged); - break; - case MISDN_CFG_ECHOTRAINING: - GET_PORTCFG_MEMCPY(echotraining); - break; - case MISDN_CFG_CALLGROUP: GET_PORTCFG_MEMCPY(callgroup); - break; - case MISDN_CFG_PICKUPGROUP: GET_PORTCFG_MEMCPY(pickupgroup); - break; - - /* general config elements */ - - case MISDN_GEN_DEBUG: GET_GENCFG_MEMCPY(debug); - break; - case MISDN_GEN_TRACEFILE: GET_GENCFG_STRCPY(tracefile); - break; - case MISDN_GEN_TRACE_CALLS: GET_GENCFG_MEMCPY(trace_calls); - break; - case MISDN_GEN_TRACE_DIR: GET_GENCFG_STRCPY(trace_dir); - break; - case MISDN_GEN_BRIDGING: GET_GENCFG_MEMCPY(bridging); - break; - case MISDN_GEN_STOP_TONE: GET_GENCFG_MEMCPY(stop_tone_after_first_digit); - break; - case MISDN_GEN_APPEND_DIGITS2EXTEN: - GET_GENCFG_MEMCPY(append_digits2exten); - break; - case MISDN_GEN_L1_INFO_OK: GET_GENCFG_MEMCPY(l1_info_ok); - break; - case MISDN_GEN_CLEAR_L3: GET_GENCFG_MEMCPY(clear_l3); - break; - case MISDN_GEN_DYNAMIC_CRYPT: GET_GENCFG_MEMCPY(dynamic_crypt); - break; - case MISDN_GEN_CRYPT_PREFIX: GET_GENCFG_STRCPY(crypt_prefix); - break; - case MISDN_GEN_CRYPT_KEYS: GET_GENCFG_STRCPY(crypt_keys); - break; - default: memset(buf, 0, bufsize); - } - - misdn_cfg_unlock(); -} - -int misdn_cfg_is_msn_valid (int port, char* msn) { - - if (!misdn_cfg_is_port_valid(port)) { - ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port); - return 0; - } - - struct msn_list *iter; - - misdn_cfg_lock(); - - if (port_cfg[port]->msn_list) - iter = port_cfg[port]->msn_list; - else - iter = port_cfg[0]->msn_list; - for (; iter; iter = iter->next) - if (*(iter->msn) == '*' || !strcasecmp(iter->msn, msn)) { - misdn_cfg_unlock(); - return 1; - } - - misdn_cfg_unlock(); - - return 0; -} - -int misdn_cfg_is_port_valid (int port) { - - misdn_cfg_lock(); - - if (port < 1 || port > max_ports) { - misdn_cfg_unlock(); - return 0; - } - - int valid = (port_cfg[port] != NULL); - - misdn_cfg_unlock(); - - return valid; -} - -int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth) { - - int i, re = 0; - char *method = NULL; - - misdn_cfg_lock(); - - for (i = 0; i < max_ports; i++) { - if (port_cfg[i]) { - if (!strcasecmp(port_cfg[i]->name, group)) - method = port_cfg[i]->method ? port_cfg[i]->method : port_cfg[0]->method; - } - } - - if (method) { - switch (meth) { - case METHOD_STANDARD: re = !strcasecmp(method, "standard"); - break; - case METHOD_ROUND_ROBIN: re = !strcasecmp(method, "round_robin"); - break; - } - } - - misdn_cfg_unlock(); - - return re; -} - -void misdn_cfg_get_ports_string (char *ports) { - *ports = 0; - char tmp[16]; - int l; - - misdn_cfg_lock(); - - int i = 1; - for (; i <= max_ports; i++) { - if (port_cfg[i]) { - if (ptp[i]) - sprintf(tmp, "%dptp,", i); - else - sprintf(tmp, "%d,", i); - strcat(ports, tmp); - } - } - - misdn_cfg_unlock(); - - if ((l = strlen(ports))) - ports[l-1] = 0; -} - -#define GET_CFG_STRING(typestr, type) ({ \ - if (port_cfg[port] && port_cfg[port]->type) \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, port_cfg[port]->type); \ - else \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, port_cfg[0]->type); \ - }) \ - -#define GET_GEN_STRING(typestr, type) ({ \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, general_cfg->type ? general_cfg->type : "not set"); \ - }) \ - -#define GET_CFG_INT(typestr, type) ({ \ - if (port_cfg[port] && port_cfg[port]->type) \ - snprintf(buf, bufsize, "%s " #typestr ": %d", begin, *port_cfg[port]->type); \ - else \ - snprintf(buf, bufsize, "%s " #typestr ": %d", begin, *port_cfg[0]->type); \ - }) \ - -#define GET_GEN_INT(typestr, type) ({ \ - snprintf(buf, bufsize, "%s " #typestr ": %d", begin, general_cfg->type ? *general_cfg->type : 0); \ - }) \ - -#define GET_CFG_BOOL(typestr, type, yes, no) ({ \ - int bool; \ - if (port_cfg[port] && port_cfg[port]->type) \ - bool = *port_cfg[port]->type; \ - else \ - bool = *port_cfg[0]->type; \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, bool ? #yes : #no); \ - }) \ - -#define GET_CFG_HYBRID(typestr, type, yes, no) ({ \ - int bool; \ - if (port_cfg[port] && port_cfg[port]->type) \ - bool = *port_cfg[port]->type; \ - else \ - bool = *port_cfg[0]->type; \ - if (bool == 1 || bool == 0) \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, bool ? #yes : #no); \ - else \ - snprintf(buf, bufsize, "%s " #typestr ": %d", begin, bool); \ - }) \ - -#define GET_GEN_BOOL(typestr, type, yes, no) ({ \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, general_cfg->type ? (*general_cfg->type ? #yes : #no) : "not set"); \ - }) \ - -#define GET_CFG_AST_GROUP_T(typestr, type) ({ \ - ast_group_t *tmp; \ - if (port_cfg[port] && port_cfg[port]->type) \ - tmp = port_cfg[port]->type; \ - else \ - tmp = port_cfg[0]->type; \ - if (tmp) { \ - char tmpbuf[256]; \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, ast_print_group(tmpbuf, sizeof(tmpbuf), *tmp)); \ - } else \ - snprintf(buf, bufsize, "%s " #typestr ": %s", begin, "none"); \ - }) \ - -void misdn_cfg_get_config_string(int port, enum misdn_cfg_elements elem, char* buf, int bufsize) { - - if (!(elem > MISDN_GEN_FIRST) && !misdn_cfg_is_port_valid(port)) { - *buf = 0; - ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port); - return; - } - - char begin[] = " -> "; - - misdn_cfg_lock(); - - switch (elem) { - - case MISDN_CFG_PTP: snprintf(buf, bufsize, "%s PTP: %s", begin, ptp[port] ? "yes" : "no"); - break; - case MISDN_CFG_GROUPNAME: GET_CFG_STRING(GROUPNAME, name); - break; - case MISDN_CFG_RXGAIN: GET_CFG_INT(RXGAIN, rxgain); - break; - case MISDN_CFG_TXGAIN: GET_CFG_INT(TXGAIN, txgain); - break; - case MISDN_CFG_TE_CHOOSE_CHANNEL: - GET_CFG_BOOL(TE_CHOOSE_CHANNEL, te_choose_channel, yes, no); - break; - case MISDN_CFG_CONTEXT: GET_CFG_STRING(CONTEXT, context); - break; - case MISDN_CFG_LANGUAGE: GET_CFG_STRING(LANGUAGE, language); - break; - case MISDN_CFG_CALLERID: GET_CFG_STRING(CALLERID, callerid); - break; - case MISDN_CFG_METHOD: GET_CFG_STRING(METHOD, method); - break; - case MISDN_CFG_DIALPLAN: GET_CFG_INT(DIALPLAN, dialplan); - break; - case MISDN_CFG_LOCALDIALPLAN: GET_CFG_INT(LOCALDIALPLAN, localdialplan); - break; - case MISDN_CFG_NATPREFIX: GET_CFG_STRING(NATIONALPREFIX, nationalprefix); - break; - case MISDN_CFG_INTERNATPREFIX: - GET_CFG_STRING(INTERNATIONALPREFIX, internationalprefix); - break; - case MISDN_CFG_PRES: GET_CFG_BOOL(PRESENTATION, pres, allowed, not_screened); - break; - case MISDN_CFG_ALWAYS_IMMEDIATE: - GET_CFG_BOOL(ALWAYS_IMMEDIATE, always_immediate, yes, no); - break; - case MISDN_CFG_IMMEDIATE: GET_CFG_BOOL(IMMEDIATE, immediate, yes, no); - break; - case MISDN_CFG_HOLD_ALLOWED: - GET_CFG_BOOL(HOLD_ALLOWED, hold_allowed, yes, no); - break; - case MISDN_CFG_EARLY_BCONNECT: - GET_CFG_BOOL(EARLY_BCONNECT, early_bconnect, yes, no); - break; - case MISDN_CFG_USE_CALLINGPRES: - GET_CFG_BOOL(USE_CALLINGPRES, use_callingpres, yes, no); - break; - case MISDN_CFG_ECHOCANCEL: GET_CFG_HYBRID(ECHOCANCEL, echocancel, yes, no); - break; - case MISDN_CFG_ECHOCANCELWHENBRIDGED: - GET_CFG_BOOL(ECHOCANCELWHENBRIDGED, echocancelwhenbridged, yes, no); - break; - case MISDN_CFG_ECHOTRAINING: - GET_CFG_HYBRID(ECHOTRAINING, echotraining, yes, no); - break; - case MISDN_CFG_CALLGROUP: GET_CFG_AST_GROUP_T(CALLINGGROUP, callgroup); - break; - case MISDN_CFG_PICKUPGROUP: GET_CFG_AST_GROUP_T(PICKUPGROUP, pickupgroup); - break; - case MISDN_CFG_MSNS: { - char tmpbuffer[BUFFERSIZE]; - tmpbuffer[0] = 0; - struct msn_list *iter; - if (port_cfg[port]->msn_list) - iter = port_cfg[port]->msn_list; - else - iter = port_cfg[0]->msn_list; - if (iter) { - for (; iter; iter = iter->next) - sprintf(tmpbuffer, "%s%s, ", tmpbuffer, iter->msn); - tmpbuffer[strlen(tmpbuffer)-2] = 0; - } - snprintf(buf, bufsize, "%s MSNs: %s", begin, *tmpbuffer ? tmpbuffer : "none"); \ - } - break; - - /* general config elements */ - - case MISDN_GEN_DEBUG: GET_GEN_INT(DEBUG_LEVEL, debug); - break; - case MISDN_GEN_TRACEFILE: GET_GEN_STRING(TRACEFILE, tracefile); - break; - case MISDN_GEN_TRACE_CALLS: GET_GEN_BOOL(TRACE_CALLS, trace_calls, true, false); - break; - case MISDN_GEN_TRACE_DIR: GET_GEN_STRING(TRACE_DIR, trace_dir); - break; - case MISDN_GEN_BRIDGING: GET_GEN_BOOL(BRIDGING, bridging, yes, no); - break; - case MISDN_GEN_STOP_TONE: GET_GEN_BOOL(STOP_TONE_AFTER_FIRST_DIGIT, stop_tone_after_first_digit, yes, no); - break; - case MISDN_GEN_APPEND_DIGITS2EXTEN: - GET_GEN_BOOL(APPEND_DIGITS2EXTEN, append_digits2exten, yes, no); - break; - case MISDN_GEN_L1_INFO_OK: GET_GEN_BOOL(L1_INFO_OK, l1_info_ok, yes, no); - break; - case MISDN_GEN_CLEAR_L3: GET_GEN_BOOL(CLEAR_L3, clear_l3, yes, no); - break; - case MISDN_GEN_DYNAMIC_CRYPT: - GET_GEN_BOOL(DYNAMIC_CRYPT,dynamic_crypt, yes, no); - break; - case MISDN_GEN_CRYPT_PREFIX: - GET_GEN_STRING(CRYPT_PREFIX, crypt_prefix); - break; - case MISDN_GEN_CRYPT_KEYS: GET_GEN_STRING(CRYPT_KEYS, crypt_keys); - break; - - default: *buf = 0; - break; - } - - misdn_cfg_unlock(); -} - -int misdn_cfg_get_next_port (int port) { - - misdn_cfg_lock(); - - for (port++; port <= max_ports; port++) { - if (port_cfg[port]) { - misdn_cfg_unlock(); - return port; - } - } - - misdn_cfg_unlock(); - - return -1; -} - -int misdn_cfg_get_next_port_spin (int port) { - - int ret = misdn_cfg_get_next_port(port); - - if (ret > 0) - return ret; - - return misdn_cfg_get_next_port(0); -} - -#define PARSE_GEN_INT(item) ({ \ - if (!strcasecmp(v->name, #item)) { \ - int temp; \ - if (!sscanf(v->value, "%d", &temp)) { \ - ast_log(LOG_WARNING, "Value \"%s\" for \"" #item "\" (generals section) invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", v->value); \ - } else { \ - general_cfg->item = (int *)malloc(sizeof(int)); \ - memcpy(general_cfg->item, &temp, sizeof(int)); \ - } \ - continue; \ - } \ - }) \ - -#define PARSE_GEN_BOOL(item) ({ \ - if (!strcasecmp(v->name, #item)) { \ - general_cfg->item = (int *)malloc(sizeof(int)); \ - *(general_cfg->item) = ast_true(v->value)?1:0; \ - continue; \ - } \ - }) - -#define PARSE_GEN_STR(item) ({ \ - if (!strcasecmp(v->name, #item)) { \ - int l = strlen(v->value); \ - if (l) { \ - general_cfg->item = (char *)calloc(l+1, sizeof(char)); \ - strncpy(general_cfg->item,v->value, l); \ - } \ - continue; \ - } \ - }) - -static void build_general_config(struct ast_variable *v) { - - if (!v) - return; - - for (; v; v = v->next) { - - PARSE_GEN_INT(debug); - PARSE_GEN_STR(tracefile); - PARSE_GEN_BOOL(trace_calls); - PARSE_GEN_STR(trace_dir); - PARSE_GEN_BOOL(bridging); - PARSE_GEN_BOOL(stop_tone_after_first_digit); - PARSE_GEN_BOOL(append_digits2exten); - PARSE_GEN_BOOL(l1_info_ok); - PARSE_GEN_BOOL(clear_l3); - PARSE_GEN_BOOL(dynamic_crypt); - PARSE_GEN_STR(crypt_prefix); - PARSE_GEN_STR(crypt_keys); - - } -} - -#define PARSE_CFG_HYBRID(item, def) ({ \ - if (!strcasecmp(v->name, #item)) { \ - new->item = (int *)malloc(sizeof(int)); \ - if (!sscanf(v->value, "%d", new->item)) { \ - if (ast_true(v->value)) \ - *new->item = def; \ - else \ - *new->item = 0; \ - } \ - continue; \ - } \ - }) \ - -#define PARSE_CFG_INT(item) ({ \ - if (!strcasecmp(v->name, #item)) { \ - new->item = (int *)malloc(sizeof(int)); \ - if (!sscanf(v->value, "%d", new->item)) { \ - ast_log(LOG_WARNING, "Value \"%s\" for \"" #item "\" of group \"%s\" invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", v->value, cat); \ - free(new->item); \ - new->item = NULL; \ - } \ - continue; \ - } \ - }) \ - -#define PARSE_CFG_BOOL(item) ({ \ - if (!strcasecmp(v->name, #item)) { \ - new->item = (int *)malloc(sizeof(int)); \ - *(new->item) = ast_true(v->value)?1:0; \ - continue; \ - } \ - }) - -#define PARSE_CFG_STR(item) ({ \ - if (!strcasecmp(v->name, #item)) { \ - int l = strlen(v->value); \ - if (l) { \ - new->item = (char *)calloc(l+1, sizeof(char)); \ - strncpy(new->item,v->value,l); \ - } \ - continue; \ - } \ - }) - -static void build_port_config(struct ast_variable *v, char *cat) { - if (!v || !cat) - return; - - int cfg_for_ports[max_ports + 1]; - int i = 0; - for (; i < (max_ports + 1); i++) { - cfg_for_ports[i] = 0; - } - - /* we store the default config at position 0 */ - if (!strcasecmp(cat, "default")) { - cfg_for_ports[0] = 1; - } - - struct port_config* new = (struct port_config *)calloc(1, sizeof(struct port_config)); - - { - int l = strlen(cat); - new->name = (char *)calloc(l+1, sizeof(char)); - strncpy(new->name, cat, l); - } - - for (; v; v=v->next) { - if (!strcasecmp(v->name, "ports")) { - /* TODO check for value not beeing set, like PORTS= */ - char *iter; - char *value = v->value; - while ((iter = strchr(value, ',')) != NULL) { - *iter = 0; - /* strip spaces */ - while (*value && *value == ' ') { - value++; - } - /* TODO check for char not 0-9 */ - - if (*value){ - int p = atoi(value); - if (p <= max_ports && p > 0) { - cfg_for_ports[p] = 1; - if (strstr(value, "ptp")) - ptp[p] = 1; - } else - ast_log(LOG_WARNING, "Port value \"%s\" of group %s invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", value, cat); - value = ++iter; - } - } - /* the remaining or the only one */ - /* strip spaces */ - while (*value && *value == ' ') { - value++; - } - /* TODO check for char not 0-9 */ - if (*value) { - int p = atoi(value); - if (p <= max_ports && p > 0) { - cfg_for_ports[p] = 1; - if (strstr(value, "ptp")) - ptp[p] = 1; - } else - ast_log(LOG_WARNING, "Port value \"%s\" of group %s invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", value, cat); - } - continue; - } - PARSE_CFG_STR(context); - PARSE_CFG_INT(dialplan); - PARSE_CFG_INT(localdialplan); - PARSE_CFG_STR(nationalprefix); - PARSE_CFG_STR(internationalprefix); - PARSE_CFG_STR(language); - if (!strcasecmp(v->name, "presentation")) { - if (v->value && strlen(v->value)) { - new->pres = (int *)malloc(sizeof(int)); - if (!strcasecmp(v->value, "allowed")) { - *(new->pres) = 1; - } - /* TODO: i assume if it is not "allowed", it is "not_screened" */ - else { - *(new->pres) = 0; - } - } - continue; - } - PARSE_CFG_INT(rxgain); - PARSE_CFG_INT(txgain); - PARSE_CFG_BOOL(te_choose_channel); - PARSE_CFG_BOOL(immediate); - PARSE_CFG_BOOL(always_immediate); - PARSE_CFG_BOOL(hold_allowed); - PARSE_CFG_BOOL(early_bconnect); - PARSE_CFG_BOOL(use_callingpres); - PARSE_CFG_HYBRID(echocancel, DEF_ECHOCANCEL); - PARSE_CFG_BOOL(echocancelwhenbridged); - PARSE_CFG_HYBRID(echotraining, DEF_ECHOTRAINING); - PARSE_CFG_STR(callerid); - PARSE_CFG_STR(method); - if (!strcasecmp(v->name, "msns")) { - /* TODO check for value not beeing set, like msns= */ - char *iter; - char *value = v->value; - - while ((iter = strchr(value, ',')) != NULL) { - *iter = 0; - /* strip spaces */ - while (*value && *value == ' ') { - value++; - } - /* TODO check for char not 0-9 */ - if (*value){ - int l = strlen(value); - if (l) { - struct msn_list *ml = (struct msn_list *)calloc(1, sizeof(struct msn_list)); - ml->msn = (char *)calloc(l+1, sizeof(char)); - strncpy(ml->msn,value,l); - ml->next = new->msn_list; - new->msn_list = ml; - } - value = ++iter; - } - } - /* the remaining or the only one */ - /* strip spaces */ - while (*value && *value == ' ') { - value++; - } - /* TODO check for char not 0-9 */ - if (*value) { - int l = strlen(value); - if (l) { - struct msn_list *ml = (struct msn_list *)calloc(1, sizeof(struct msn_list)); - ml->msn = (char *)calloc(l+1, sizeof(char)); - strncpy(ml->msn,value,l); - ml->next = new->msn_list; - new->msn_list = ml; - } - } - continue; - } - if (!strcasecmp(v->name, "callgroup")) { - new->callgroup = (ast_group_t *)malloc(sizeof(ast_group_t)); - *(new->callgroup)=ast_get_group(v->value); - continue; - } - if (!strcasecmp(v->name, "pickupgroup")) { - new->pickupgroup = (ast_group_t *)malloc(sizeof(ast_group_t)); - *(new->pickupgroup)=ast_get_group(v->value); - continue; - } - } - /* store the new config in our array of port configs */ - for (i = 0; i < (max_ports + 1); i++) { - if (cfg_for_ports[i]) - port_cfg[i] = new; - } -} - - -static void fill_defaults (void) { - - /* general defaults */ - if (!general_cfg->debug) - general_cfg->debug = (int*)calloc(1, sizeof(int)); - if (!general_cfg->trace_calls) - general_cfg->trace_calls = (int*)calloc(1, sizeof(int)); - if (!general_cfg->trace_dir) { - general_cfg->trace_dir = (char *)malloc(10 * sizeof(char)); - sprintf(general_cfg->trace_dir, "/var/log/"); - } - if (!general_cfg->bridging) { - general_cfg->bridging = (int*)malloc(sizeof(int)); - *general_cfg->bridging = 1; - } - if (!general_cfg->stop_tone_after_first_digit) { - general_cfg->stop_tone_after_first_digit = (int*)malloc(sizeof(int)); - *general_cfg->stop_tone_after_first_digit = 1; - } - if (!general_cfg->append_digits2exten) { - general_cfg->append_digits2exten = (int*)malloc(sizeof(int)); - *general_cfg->append_digits2exten = 1; - } - if (!general_cfg->l1_info_ok) { - general_cfg->l1_info_ok = (int*)malloc(sizeof(int)); - *general_cfg->l1_info_ok = 1; - } - if (!general_cfg->clear_l3) - general_cfg->clear_l3 =(int*)calloc(1, sizeof(int)); - if (!general_cfg->dynamic_crypt) - general_cfg->dynamic_crypt = (int*)calloc(1, sizeof(int)); - - /* defaults for default port config */ - if (!port_cfg[0]) - port_cfg[0] = (struct port_config*)calloc(1, sizeof(struct port_config)); - if (!port_cfg[0]->name) { - port_cfg[0]->name = (char *)malloc(8 * sizeof(char)); - sprintf(port_cfg[0]->name, "default"); - } - if (!port_cfg[0]->rxgain) - port_cfg[0]->rxgain = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->txgain) - port_cfg[0]->txgain = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->te_choose_channel) - port_cfg[0]->te_choose_channel = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->context) { - port_cfg[0]->context = (char *)malloc(8 * sizeof(char)); - sprintf(port_cfg[0]->context, "default"); - } - if (!port_cfg[0]->language) { - port_cfg[0]->language = (char *)malloc(3 * sizeof(char)); - sprintf(port_cfg[0]->language, "en"); - } - if (!port_cfg[0]->callerid) - port_cfg[0]->callerid = (char *)calloc(1, sizeof(char)); - if (!port_cfg[0]->method) { - port_cfg[0]->method = (char *)malloc(9 * sizeof(char)); - sprintf(port_cfg[0]->method, "standard"); - } - if (!port_cfg[0]->dialplan) - port_cfg[0]->dialplan = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->localdialplan) - port_cfg[0]->localdialplan = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->nationalprefix) { - port_cfg[0]->nationalprefix = (char *)malloc(2 * sizeof(char)); - sprintf(port_cfg[0]->nationalprefix, "0"); - } - if (!port_cfg[0]->internationalprefix) { - port_cfg[0]->internationalprefix = (char *)malloc(3 * sizeof(char)); - sprintf(port_cfg[0]->internationalprefix, "00"); - } - if (!port_cfg[0]->pres) { - port_cfg[0]->pres = (int *)malloc(sizeof(int)); - *port_cfg[0]->pres = 1; - } - if (!port_cfg[0]->always_immediate) - port_cfg[0]->always_immediate = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->immediate) - port_cfg[0]->immediate = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->hold_allowed) - port_cfg[0]->hold_allowed = (int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->early_bconnect) { - port_cfg[0]->early_bconnect = (int *)malloc(sizeof(int)); - *port_cfg[0]->early_bconnect = 1; - } - if (!port_cfg[0]->echocancel) - port_cfg[0]->echocancel=(int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->echocancelwhenbridged) - port_cfg[0]->echocancelwhenbridged=(int *)calloc(1, sizeof(int)); - if (!port_cfg[0]->echotraining) { - port_cfg[0]->echotraining=(int *)malloc(sizeof(int)); - *port_cfg[0]->echotraining = 1; - } - if (!port_cfg[0]->use_callingpres) { - port_cfg[0]->use_callingpres = (int *)malloc(sizeof(int)); - *port_cfg[0]->use_callingpres = 1; - } - if (!port_cfg[0]->msn_list) { - port_cfg[0]->msn_list = (struct msn_list *)malloc(sizeof(struct msn_list)); - port_cfg[0]->msn_list->next = NULL; - port_cfg[0]->msn_list->msn = (char *)calloc(2, sizeof(char)); - *(port_cfg[0]->msn_list->msn) = '*'; - } -} - -void misdn_cfg_reload (void) { - misdn_cfg_init (0); -} - -void misdn_cfg_destroy (void) { - - misdn_cfg_lock(); - - free_port_cfg(); - free_general_cfg(); - - free(port_cfg); - free(general_cfg); - free(ptp); - - misdn_cfg_unlock(); - ast_mutex_destroy(&config_mutex); -} - -void misdn_cfg_init (int this_max_ports) -{ - char config[]="misdn.conf"; - - struct ast_config *cfg; - cfg = AST_LOAD_CFG(config); - if (!cfg) { - ast_log(LOG_WARNING,"no misdn.conf ?\n"); - return; - } - - misdn_cfg_lock(); - - if (this_max_ports) { - /* this is the first run */ - max_ports = this_max_ports; - port_cfg = (struct port_config **)calloc(max_ports + 1, sizeof(struct port_config *)); - general_cfg = (struct general_config*)calloc(1, sizeof(struct general_config)); - ptp = (int *)calloc(max_ports + 1, sizeof(int)); - } - else { - free_port_cfg(); - free_general_cfg(); - port_cfg = memset(port_cfg, 0, sizeof(struct port_config *) * (max_ports + 1)); - general_cfg = memset(general_cfg, 0, sizeof(struct general_config)); - ptp = memset(ptp, 0, sizeof(int) * (max_ports + 1)); - } - - char *cat; - cat = ast_category_browse(cfg, NULL); - - while(cat) { - struct ast_variable *v=ast_variable_browse(cfg,cat); - if (!strcasecmp(cat,"general")) { - build_general_config (v); - } else { - build_port_config (v, cat); - } - cat=ast_category_browse(cfg,cat); - } - - fill_defaults(); - - misdn_cfg_unlock(); - - AST_DESTROY_CFG(cfg); -} diff --git a/channels/misdn/Makefile b/channels/misdn/Makefile index e0e18cf85..1374e75e3 100644 --- a/channels/misdn/Makefile +++ b/channels/misdn/Makefile @@ -5,10 +5,13 @@ # # Verify those options with main Makefile -CFLAGS += -pipe -c -DMISDNUSER_JOLLY +CFLAGS = -pipe -c -Wall -ggdb +ifeq ($(shell uname -m),x86_64) +CFLAGS += -fPIC +endif SOURCES = isdn_lib.c isdn_msg_parser.c OBJDIR = . -OBJS = isdn_lib.o isdn_msg_parser.o +OBJS = isdn_lib.o isdn_msg_parser.o fac.o all: chan_misdn_lib.a @@ -16,57 +19,24 @@ all: chan_misdn_lib.a %.o: %.c $(CC) $(CFLAGS) -o $@ $< - + chan_misdn_lib.a: $(OBJS) ar crv $@ $(OBJS) -misdn: test_preempt - if [ ! -d lib ] ; then \ - mkdir lib; \ - cd lib ; \ - wget http://isdn.jolly.de/download/v3.1/mISDN_for_PBX4Linux-3.0.tar.gz ;\ - tar xzf mISDN_for_PBX4Linux-3.0.tar.gz; \ - wget http://isdn.jolly.de/download/v3.1/mISDNuser_for_PBX4Linux-3.0.tar.gz ;\ - tar xzf mISDNuser_for_PBX4Linux-3.0.tar.gz ;\ - cd mISDN; patch -p1 <../../mISDN.patch; \ - cd ../mISDNuser ; patch -p1 <../../mISDNuser.patch; \ - fi +misdn: + @mkdir -p lib + cd lib ; cvs -d:pserver:anonymous:readonly@cvs.isdn4linux.de:/i4ldev co mISDN mISDNuser ; cd lib/mISDN ; make install cd lib/mISDNuser ; make install -LINUX=/lib/modules/$(uname -r)/build -GCCVERSION=$(shell $(CC) --version | grep GCC | cut -d " " -f 3 | cut -d "." -f 1) - -test_preempt: - @if grep 'CONFIG_DEBUG_SPINLOCK=y' $(LINUX)/.config ; then \ - echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nDisable the DEBUG_SPINLOCK Setting in your Kernel Config.\n with this option set, mISDN will not work! \n\n" ;\ - read ; \ - exit 1 ; \ - fi - @if grep 'CONFIG_DEBUG_SPINLOCK_SLEEP=y' $(LINUX)/.config ; then \ - echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nDisable the DEBUG_SPINLOCK_SLEEP Setting in your Kernel Config.\n with this option set, mISDN will not work! \n\n" ;\ - read ; \ - exit 1 ; \ - fi - @if grep 'CONFIG_SMP=y' $(LINUX)/.config ; then \ - echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nDisable the SMP Setting in your Kernel Config.\n\n" ; \ - read ; \ - exit 1 ; \ - fi - @if test "$(GCCVERSION)" -gt 3 ; then \ - echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nYou're using GCC 4! Please downgrade to gcc-3.x and type:\nexport CC=gcc-3.x\nbefore issuing make again.\nyou won't have success with gcc-4!\n\n" ; \ - read ; \ - exit 1 ; \ - fi - - - +portinfo: portinfo.o + $(CC) -L/usr/lib -o $@ $^ -lisdnnet -lmISDN -lpthread + + FORCE: clean: rm -rf *.a *.o *.so - -misdn_clean: rm -rf lib - + rm -rf portinfo diff --git a/channels/misdn/chan_misdn_config.h b/channels/misdn/chan_misdn_config.h index 250a74e54..58fca2c8b 100644 --- a/channels/misdn/chan_misdn_config.h +++ b/channels/misdn/chan_misdn_config.h @@ -22,47 +22,58 @@ enum misdn_cfg_elements { /* port config items */ MISDN_CFG_FIRST = 0, - MISDN_CFG_PTP, /* int (bool) */ MISDN_CFG_GROUPNAME, /* char[] */ + MISDN_CFG_ALLOWED_BEARERS, /* char[] */ + MISDN_CFG_FAR_ALERTING, /* int (bool) */ MISDN_CFG_RXGAIN, /* int */ MISDN_CFG_TXGAIN, /* int */ MISDN_CFG_TE_CHOOSE_CHANNEL, /* int (bool) */ + MISDN_CFG_PMP_L1_CHECK, /* int (bool) */ + MISDN_CFG_ALARM_BLOCK, /* int (bool) */ + MISDN_CFG_HDLC, /* int (bool) */ MISDN_CFG_CONTEXT, /* char[] */ MISDN_CFG_LANGUAGE, /* char[] */ + MISDN_CFG_MUSICCLASS, /* char[] */ MISDN_CFG_CALLERID, /* char[] */ MISDN_CFG_METHOD, /* char[] */ MISDN_CFG_DIALPLAN, /* int */ MISDN_CFG_LOCALDIALPLAN, /* int */ + MISDN_CFG_CPNDIALPLAN, /* int */ MISDN_CFG_NATPREFIX, /* char[] */ MISDN_CFG_INTERNATPREFIX, /* char[] */ - MISDN_CFG_PRES, /* int (bool) */ + MISDN_CFG_PRES, /* int */ + MISDN_CFG_SCREEN, /* int */ MISDN_CFG_ALWAYS_IMMEDIATE, /* int (bool) */ + MISDN_CFG_NODIALTONE, /* int (bool) */ MISDN_CFG_IMMEDIATE, /* int (bool) */ + MISDN_CFG_SENDDTMF, /* int (bool) */ MISDN_CFG_HOLD_ALLOWED, /* int (bool) */ MISDN_CFG_EARLY_BCONNECT, /* int (bool) */ - MISDN_CFG_USE_CALLINGPRES, /* int (bool) */ + MISDN_CFG_INCOMING_EARLY_AUDIO, /* int (bool) */ MISDN_CFG_ECHOCANCEL, /* int */ MISDN_CFG_ECHOCANCELWHENBRIDGED, /* int (bool) */ - MISDN_CFG_ECHOTRAINING, /* int (bool) */ + MISDN_CFG_NEED_MORE_INFOS, /* bool */ + MISDN_CFG_JITTERBUFFER, /* int */ + MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, /* int */ MISDN_CFG_CALLGROUP, /* ast_group_t */ MISDN_CFG_PICKUPGROUP, /* ast_group_t */ MISDN_CFG_MSNS, /* char[] */ + MISDN_CFG_PTP, /* int (bool) */ MISDN_CFG_LAST, /* general config items */ MISDN_GEN_FIRST, + MISDN_GEN_MISDN_INIT, /* char[] */ MISDN_GEN_DEBUG, /* int */ MISDN_GEN_TRACEFILE, /* char[] */ - MISDN_GEN_TRACE_CALLS, /* int (bool) */ - MISDN_GEN_TRACE_DIR, /* char[] */ MISDN_GEN_BRIDGING, /* int (bool) */ MISDN_GEN_STOP_TONE, /* int (bool) */ MISDN_GEN_APPEND_DIGITS2EXTEN, /* int (bool) */ - MISDN_GEN_L1_INFO_OK, /* int (bool) */ - MISDN_GEN_CLEAR_L3, /* int (bool) */ MISDN_GEN_DYNAMIC_CRYPT, /* int (bool) */ MISDN_GEN_CRYPT_PREFIX, /* char[] */ MISDN_GEN_CRYPT_KEYS, /* char[] */ + MISDN_GEN_NTDEBUGFLAGS, /* int */ + MISDN_GEN_NTDEBUGFILE, /* char[] */ MISDN_GEN_LAST }; @@ -76,6 +87,8 @@ void misdn_cfg_init(int max_ports); void misdn_cfg_reload(void); void misdn_cfg_destroy(void); +void misdn_cfg_update_ptp( void ); + /* if you requst a general config element, the port value is ignored. if the requested * value is not available, or the buffer is too small, the buffer will be nulled (in * case of a char* only its first byte will be nulled). */ diff --git a/channels/misdn/fac.c b/channels/misdn/fac.c new file mode 100644 index 000000000..383a60f26 --- /dev/null +++ b/channels/misdn/fac.c @@ -0,0 +1,313 @@ + +#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) +{ + if (len > dst_len-1) + len = dst_len-1; + strncpy((char *)dest, (char *)src, len); + dest[len] = '\0'; +} + + + + +/**********************/ +/*** 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; + Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); + int l; + + + if (!facility || facility_len<=0) + { + return; + } + + + l = facility_len; + p = msg_put(msg, l+2); + if (nt) + *ntmode = p+1; + else + qi->QI_ELEMENT(facility) = p - (unsigned char *)qi - sizeof(Q931_info_t); + p[0] = IE_FACILITY; + p[1] = l; + memcpy(p+2, facility, facility_len); +} + + +/* facility for siemens CENTEX (known parts implemented only) */ +void enc_ie_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup, int nt, struct misdn_bchannel *bc) +{ + unsigned char centrex[256]; + int i = 0; + + if (!cnip) + return; + + /* centrex facility */ + centrex[i++] = FACILITY_CENTREX; + centrex[i++] = CENTREX_ID; + + /* cnip */ + if (strlen((char *)cnip) > 15) + { +/* if (options.deb & DEBUG_PORT) */ + cb_log(1,0,"%s: CNIP/CONP text too long (max 13 chars), cutting.\n", __FUNCTION__); + cnip[15] = '\0'; + } + /* dunno what the 8 bytes mean */ + if (setup) + { + centrex[i++] = 0x17; + centrex[i++] = 0x02; + centrex[i++] = 0x02; + centrex[i++] = 0x44; + centrex[i++] = 0x18; + centrex[i++] = 0x02; + centrex[i++] = 0x01; + centrex[i++] = 0x09; + } else + { + centrex[i++] = 0x18; + centrex[i++] = 0x02; + centrex[i++] = 0x02; + centrex[i++] = 0x81; + centrex[i++] = 0x09; + centrex[i++] = 0x02; + centrex[i++] = 0x01; + centrex[i++] = 0x0a; + } + + centrex[i++] = 0x80; + centrex[i++] = strlen((char *)cnip); + strcpy((char *)(¢rex[i]), (char *)cnip); + i += strlen((char *)cnip); + cb_log(4,0," cnip='%s'\n", cnip); + + /* encode facility */ + enc_ie_facility(ntmode, msg, centrex, i, nt , bc); +} + +void dec_ie_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *centrex, int facility_len, unsigned char *cnip, int cnip_len, int nt, struct misdn_bchannel *bc) +{ + + int i = 0; + *cnip = '\0'; + + if (facility_len >= 2) + { + if (centrex[i++] != FACILITY_CENTREX) + return; + if (centrex[i++] != CENTREX_ID) + return; + } + + /* loop sub IEs of facility */ + while(facility_len > i+1) + { + if (centrex[i+1]+i+1 > facility_len) + { + printf("%s: ERROR: short read of centrex facility.\n", __FUNCTION__); + return; + } + switch(centrex[i]) + { + case 0x80: + strnncpy(cnip, ¢rex[i+2], centrex[i+1], cnip_len); + cb_log(4,0," CENTREX cnip='%s'\n", cnip); + break; + } + i += 1+centrex[i+1]; + } +} + + + + +/* facility for CALL Deflect (known parts implemented only) */ +void enc_ie_facility_calldeflect(unsigned char **ntmode, msg_t *msg, unsigned char *nr, int nt, struct misdn_bchannel *bc) +{ + unsigned char fac[256]; + + if (!nr) + return; + + int len = strlen(nr); + /* calldeflect facility */ + + /* cnip */ + if (strlen((char *)nr) > 15) + { +/* if (options.deb & DEBUG_PORT) */ + cb_log(1,0,"%s: NR text too long (max 13 chars), cutting.\n", __FUNCTION__); + nr[15] = '\0'; + } + + fac[0]=FACILITY_CALLDEFLECT; // .. + fac[1]=CALLDEFLECT_ID; + fac[2]=0x0f + len; // strlen destination + 15 = 26 + fac[3]=0x02; + fac[4]=0x01; + //fac[5]=0x70; + fac[5]=0x09; + fac[6]=0x02; + fac[7]=0x01; + fac[8]=0x0d; + fac[9]=0x30; + fac[10]=0x07 + len; // strlen destination + 7 = 18 + fac[11]=0x30; // ...hm 0x30 + fac[12]=0x02+ len; // strlen destination + 2 + fac[13]=0x80; // CLIP + fac[14]= len; // strlen destination + + memcpy((unsigned char *)fac+15,nr,len); + fac[15+len]=0x01; //sending complete + fac[16+len]=0x01; + fac[17+len]=0x80; + + enc_ie_facility(ntmode, msg, fac, 17+len +1 , nt , bc); +} + + +void dec_ie_facility_calldeflect(unsigned char *p, Q931_info_t *qi, unsigned char *fac, int fac_len, unsigned char *cd_nr, int nt, struct misdn_bchannel *bc) +{ + *cd_nr = '\0'; + + if (fac_len >= 15) + { + if (fac[0] != FACILITY_CALLDEFLECT) + return; + if (fac[1] != CALLDEFLECT_ID) + return; + } 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); + } +} + + + +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); + } +} + +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]; + + if (!bc->nt) + { + p = NULL; + if (qi->QI_ELEMENT(facility)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1; + } + if (!p) + return; + + fac_len = p[0] & 0xff; + + memcpy(facility, p+1, fac_len); + + switch(facility[0]) { + case FACILITY_CENTREX: + { + int cnip_len=15; + + dec_ie_facility_centrex(p, qi,facility, fac_len, fac->cnip, cnip_len, bc->nt, bc); + + *type=FACILITY_CENTREX; + } + break; + case FACILITY_CALLDEFLECT: + dec_ie_facility_calldeflect(p, qi,facility, fac_len, fac->calldeflect_nr, bc->nt, bc); + + *type=FACILITY_CALLDEFLECT; + 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; + } + + +} + +/*** FACILITY END **/ + diff --git a/channels/misdn/fac.h b/channels/misdn/fac.h new file mode 100644 index 000000000..acc41f17f --- /dev/null +++ b/channels/misdn/fac.h @@ -0,0 +1,8 @@ +#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); + +void fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc); + +#endif diff --git a/channels/misdn/ie.c b/channels/misdn/ie.c index 4d1815f65..a3eb255f8 100644 --- a/channels/misdn/ie.c +++ b/channels/misdn/ie.c @@ -23,17 +23,12 @@ #include <string.h> - -#include "isdn_lib_intern.h" - #include <mISDNuser/mISDNlib.h> #include <mISDNuser/isdn_net.h> #include <mISDNuser/l3dss1.h> #include <mISDNuser/net_l3.h> -#define CENTREX_FAC 0x88 -#define CENTREX_ID 0xa1 #define MISDN_IE_DEBG 0 @@ -69,7 +64,8 @@ void enc_ie_complete(unsigned char **ntmode, msg_t *msg, int complete, int nt, s { *ntmode = p; } else - qi->sending_complete = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(sending_complete) = p - (unsigned char *)qi - sizeof(Q931_info_t); + p[0] = IE_COMPLETE; } } @@ -79,7 +75,7 @@ void dec_ie_complete(unsigned char *p, Q931_info_t *qi, int *complete, int nt, s *complete = 0; if (!nt) { - if (qi->sending_complete) + if (qi->QI_ELEMENT(sending_complete)) *complete = 1; } else if (p) @@ -140,7 +136,7 @@ void enc_ie_bearer(unsigned char **ntmode, msg_t *msg, int coding, int capabilit if (nt) *ntmode = p+1; else - qi->bearer_capability = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(bearer_capability) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_BEARER; p[1] = l; p[2] = 0x80 + (coding<<5) + capability; @@ -166,23 +162,28 @@ void dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capabili *stopbits = -1; *dbits = -1; *parity = -1; - + if (!nt) { p = NULL; - if (qi->llc) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->llc + 1; - else if (qi->bearer_capability) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->bearer_capability + 1; +#ifdef LLC_SUPPORT + if (qi->QI_ELEMENT(llc)) { + + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(llc) + 1; + } +#endif + if (qi->QI_ELEMENT(bearer_capability)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(bearer_capability) + 1; } if (!p) return; + if (p[0] < 2) { printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]); return; } - + *coding = (p[1]&0x60) >> 5; *capability = p[1] & 0x1f; octet = 2; @@ -292,7 +293,7 @@ void enc_ie_call_id(unsigned char **ntmode, msg_t *msg, unsigned char *callid, i if (nt) *ntmode = p+1; else - qi->call_id = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(call_id) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CALL_ID; p[1] = l; memcpy(p+2, callid, callid_len); @@ -308,8 +309,8 @@ void dec_ie_call_id(unsigned char *p, Q931_info_t *qi, unsigned char *callid, in if (!nt) { p = NULL; - if (qi->call_id) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->call_id + 1; + if (qi->QI_ELEMENT(call_id)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(call_id) + 1; } if (!p) return; @@ -363,7 +364,7 @@ void enc_ie_called_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, un if (nt) *ntmode = p+1; else - qi->called_nr = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(called_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CALLED_PN; p[1] = l; p[2] = 0x80 + (type<<4) + plan; @@ -379,8 +380,8 @@ void dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, u if (!nt) { p = NULL; - if (qi->called_nr) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->called_nr + 1; + if (qi->QI_ELEMENT(called_nr)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(called_nr) + 1; } if (!p) return; @@ -437,7 +438,7 @@ void enc_ie_calling_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, i if (nt) *ntmode = p+1; else - qi->calling_nr = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(calling_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CALLING_PN; p[1] = l; if (present >= 0) @@ -465,8 +466,8 @@ void dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, if (!nt) { p = NULL; - if (qi->calling_nr) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->calling_nr + 1; + if (qi->QI_ELEMENT(calling_nr)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(calling_nr) + 1; } if (!p) return; @@ -539,7 +540,7 @@ void enc_ie_connected_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, if (nt) *ntmode = p+1; else - qi->connected_nr = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(connected_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CONNECT_PN; p[1] = l; if (present >= 0) @@ -567,8 +568,8 @@ void dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan if (!nt) { p = NULL; - if (qi->connected_nr) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->connected_nr + 1; + if (qi->QI_ELEMENT(connected_nr)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(connected_nr) + 1; } if (!p) return; @@ -624,7 +625,7 @@ void enc_ie_cause(unsigned char **ntmode, msg_t *msg, int location, int cause, i if (nt) *ntmode = p+1; else - qi->cause = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(cause) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CAUSE; p[1] = l; p[2] = 0x80 + location; @@ -637,7 +638,7 @@ void enc_ie_cause_standalone(unsigned char **ntmode, msg_t *msg, int location, i if (ntmode) *ntmode = p+1; else - qi->cause = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(cause) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CAUSE; p[1] = 2; p[2] = 0x80 + location; @@ -653,8 +654,8 @@ void dec_ie_cause(unsigned char *p, Q931_info_t *qi, int *location, int *cause, if (!nt) { p = NULL; - if (qi->cause) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->cause + 1; + if (qi->QI_ELEMENT(cause)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(cause) + 1; } if (!p) return; @@ -705,7 +706,7 @@ void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int ch if (nt) *ntmode = p+1; else - qi->channel_id = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(channel_id) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CHANNEL_ID; p[1] = l; if (channel == 0xff) @@ -725,7 +726,7 @@ void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int ch if (nt) *ntmode = p+1; else - qi->channel_id = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(channel_id) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CHANNEL_ID; p[1] = l; p[2] = 0x80 + 0x20 + 0x03; @@ -737,7 +738,7 @@ void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int ch if (nt) *ntmode = p+1; else - qi->channel_id = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(channel_id) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_CHANNEL_ID; p[1] = l; p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01; @@ -758,8 +759,8 @@ void dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive, int *c if (!nt) { p = NULL; - if (qi->channel_id) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->channel_id + 1; + if (qi->QI_ELEMENT(channel_id)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(channel_id) + 1; } if (!p) return; @@ -863,7 +864,7 @@ void enc_ie_date(unsigned char **ntmode, msg_t *msg, time_t ti, int nt, struct m if (nt) *ntmode = p+1; else - qi->date = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(date) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_DATE; p[1] = l; p[2] = tm->tm_year % 100; @@ -900,7 +901,7 @@ void enc_ie_display(unsigned char **ntmode, msg_t *msg, unsigned char *display, if (nt) *ntmode = p+1; else - qi->display = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(display) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_DISPLAY; p[1] = l; strncpy((char *)p+2, (char *)display, strlen((char *)display)); @@ -913,8 +914,8 @@ void dec_ie_display(unsigned char *p, Q931_info_t *qi, unsigned char *display, i if (!nt) { p = NULL; - if (qi->display) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->display + 1; + if (qi->QI_ELEMENT(display)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(display) + 1; } if (!p) return; @@ -950,7 +951,7 @@ void enc_ie_keypad(unsigned char **ntmode, msg_t *msg, unsigned char *keypad, in if (nt) *ntmode = p+1; else - qi->keypad = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(keypad) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_KEYPAD; p[1] = l; strncpy((char *)p+2, (char *)keypad, strlen((char *)keypad)); @@ -963,8 +964,8 @@ void dec_ie_keypad(unsigned char *p, Q931_info_t *qi, unsigned char *keypad, int if (!nt) { p = NULL; - if (qi->keypad) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->keypad + 1; + if (qi->QI_ELEMENT(keypad)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(keypad) + 1; } if (!p) return; @@ -1000,7 +1001,7 @@ void enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify, int nt, struc if (nt) *ntmode = p+1; else - qi->notify = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(notify) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_NOTIFY; p[1] = l; p[2] = 0x80 + notify; @@ -1013,8 +1014,8 @@ void dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify, int nt, struc if (!nt) { p = NULL; - if (qi->notify) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->notify + 1; + if (qi->QI_ELEMENT(notify)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(notify) + 1; } if (!p) return; @@ -1060,7 +1061,7 @@ void enc_ie_progress(unsigned char **ntmode, msg_t *msg, int coding, int locatio if (nt) *ntmode = p+1; else - qi->progress = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(progress) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_PROGRESS; p[1] = l; p[2] = 0x80 + (coding<<5) + location; @@ -1077,8 +1078,8 @@ void dec_ie_progress(unsigned char *p, Q931_info_t *qi, int *coding, int *locati if (!nt) { p = NULL; - if (qi->progress) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->progress + 1; + if (qi->QI_ELEMENT(progress)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(progress) + 1; } if (!p) return; @@ -1144,7 +1145,7 @@ void enc_ie_redir_nr(unsigned char **ntmode, msg_t *msg, int type, int plan, int if (nt) *ntmode = p+1; else - qi->redirect_nr = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(redirect_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_REDIR_NR; p[1] = l; if (present >= 0) @@ -1183,8 +1184,8 @@ void dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, in if (!nt) { p = NULL; - if (qi->redirect_nr) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_nr + 1; + if (qi->QI_ELEMENT(redirect_nr)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(redirect_nr) + 1; } if (!p) return; @@ -1252,7 +1253,7 @@ void enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int *ntmode = p+1; else /* #warning REINSERT redir_dn, when included in te-mode */ - /*qi->redir_dn = p - (unsigned char *)qi - sizeof(Q931_info_t)*/; + /*qi->QI_ELEMENT(redir_dn) = p - (unsigned char *)qi - sizeof(Q931_info_t)*/; p[0] = IE_REDIR_DN; p[1] = l; if (present >= 0) @@ -1280,8 +1281,8 @@ void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, in { p = NULL; /* #warning REINSERT redir_dn, when included in te-mode */ -/* if (qi->redir_dn) */ -/* p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redir_dn + 1; */ +/* if (qi->QI_ELEMENT(redir_dn)) */ +/* p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(redir_dn) + 1; */ } if (!p) return; @@ -1306,242 +1307,6 @@ void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, in } -/* 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; - Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); - int l; - - char debug[768]; - int i; - - if (!facility || facility_len<=0) - { - return; - } - - i = 0; - while(i < facility_len) - { - if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", facility[i]); - i++; - } - - if (MISDN_IE_DEBG) printf(" facility%s\n", debug); - - l = facility_len; - p = msg_put(msg, l+2); - if (nt) - *ntmode = p+1; - else - qi->facility = p - (unsigned char *)qi - sizeof(Q931_info_t); - p[0] = IE_FACILITY; - p[1] = l; - memcpy(p+2, facility, facility_len); -} - -void dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *facility, int *facility_len, int nt, struct misdn_bchannel *bc) -{ - int i; - struct misdn_stack *stack=get_stack_by_bc(bc); - - *facility_len = 0; - - if (!nt) - { - p = NULL; - if (qi->facility) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->facility + 1; - } - if (!p) - return; - - *facility_len = p[0]; - memcpy(facility, p+1, *facility_len); - - i = 0; - while(i < *facility_len) - { - cb_log(3, stack->port, " %02x", facility[i]); - i++; - } - cb_log(3, stack->port, " facility\n"); -} - - -/* facility for siemens CENTEX (known parts implemented only) */ -void enc_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup, int nt, struct misdn_bchannel *bc) -{ - unsigned char centrex[256]; - int i = 0; - - if (!cnip) - return; - - /* centrex facility */ - centrex[i++] = CENTREX_FAC; - centrex[i++] = CENTREX_ID; - - /* cnip */ - if (strlen((char *)cnip) > 15) - { -/* if (options.deb & DEBUG_PORT) */ - if (MISDN_IE_DEBG) printf("%s: CNIP/CONP text too long (max 13 chars), cutting.\n", __FUNCTION__); - cnip[15] = '\0'; - } - /* dunno what the 8 bytes mean */ - if (setup) - { - centrex[i++] = 0x17; - centrex[i++] = 0x02; - centrex[i++] = 0x02; - centrex[i++] = 0x44; - centrex[i++] = 0x18; - centrex[i++] = 0x02; - centrex[i++] = 0x01; - centrex[i++] = 0x09; - } else - { - centrex[i++] = 0x18; - centrex[i++] = 0x02; - centrex[i++] = 0x02; - centrex[i++] = 0x81; - centrex[i++] = 0x09; - centrex[i++] = 0x02; - centrex[i++] = 0x01; - centrex[i++] = 0x0a; - } - - centrex[i++] = 0x80; - centrex[i++] = strlen((char *)cnip); - strcpy((char *)(¢rex[i]), (char *)cnip); - i += strlen((char *)cnip); - if (MISDN_IE_DEBG) printf(" cnip='%s'\n", cnip); - - /* encode facility */ - enc_ie_facility(ntmode, msg, centrex, i, nt , bc); -} - -void dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len, int nt, struct misdn_bchannel *bc) -{ - unsigned char centrex[256]; - char debug[768]; - int facility_len = 0; - int i = 0, j; - *cnip = '\0'; - - dec_ie_facility(p, qi, centrex, &facility_len, nt, bc); - if (facility_len >= 2) - { - if (centrex[i++] != CENTREX_FAC) - return; - if (centrex[i++] != CENTREX_ID) - return; - } - - /* loop sub IEs of facility */ - while(facility_len > i+1) - { - if (centrex[i+1]+i+1 > facility_len) - { - printf("%s: ERROR: short read of centrex facility.\n", __FUNCTION__); - return; - } - switch(centrex[i]) - { - case 0x80: - strnncpy(cnip, ¢rex[i+2], centrex[i+1], cnip_len); - if (MISDN_IE_DEBG) printf(" CENTREX cnip='%s'\n", cnip); - break; - - default: - j = 0; - while(j < centrex[i+1]) - { - if (MISDN_IE_DEBG) printf(debug+(j*3), " %02x", centrex[i+1+j]); - i++; - } - if (MISDN_IE_DEBG) printf(" CENTREX unknown=0x%2x len=%d%s\n", centrex[i], centrex[i+1], debug); - } - i += 1+centrex[i+1]; - } -} - - - - -/* facility for siemens CENTEX (known parts implemented only) */ -void enc_facility_calldeflect(unsigned char **ntmode, msg_t *msg, unsigned char *nr, int nt, struct misdn_bchannel *bc) -{ - unsigned char fac[256]; - - if (!nr) - return; - - /* calldeflect facility */ - - /* cnip */ - if (strlen((char *)nr) > 15) - { -/* if (options.deb & DEBUG_PORT) */ - if (MISDN_IE_DEBG) printf("%s: NR text too long (max 13 chars), cutting.\n", __FUNCTION__); - nr[15] = '\0'; - } - - fac[0]=0; // len - fac[1]=0; //len - fac[2]=0x01; // Use D-Chan - fac[3]=0; // Keypad len - fac[4]=31; // user user data? len = 31 = 29 + 2 - fac[5]=0x1c; // magic? - fac[6]=0x1d; // strlen destination + 18 = 29 - fac[7]=0x91; // .. - fac[8]=0xA1; - fac[9]=0x1A; // strlen destination + 15 = 26 - fac[10]=0x02; - fac[11]=0x01; - fac[12]=0x70; - fac[13]=0x02; - fac[14]=0x01; - fac[15]=0x0d; - fac[16]=0x30; - fac[17]=0x12; // strlen destination + 7 = 18 - fac[18]=0x30; // ...hm 0x30 - fac[19]=0x0d; // strlen destination + 2 - fac[20]=0x80; // CLIP - fac[21]=0x0b; // strlen destination - fac[22]=0x01; // destination start - fac[23]=0x01; // - fac[24]=0x01; // - fac[25]=0x01; // - fac[26]=0x01; // - fac[27]=0x01; // - fac[28]=0x01; // - fac[29]=0x01; // - fac[30]=0x01; // - fac[31]=0x01; // - fac[32]=0x01; // - fac[33]=0x01; // 0x1 = sending complete - fac[34]=0x01; - fac[35]=0x01; - - memcpy((unsigned char *)fac+22,nr,strlen(nr)); - fac[22+strlen( nr)]=0x01; // fill with 0x01 if number is only 6 numbers (local call) - fac[23+strlen(nr)]=0x01; - fac[24+strlen(nr)]=0x01; - fac[25+strlen(nr)]=0x01; - fac[26+strlen(nr)]=0x01; - - fac[6]=18+strlen(nr); - fac[9]=15+strlen(nr); - fac[17]=7+strlen(nr); - fac[19]=2+strlen(nr); - fac[21]=strlen(nr); - - enc_ie_facility(ntmode, msg, &fac[4], 36-4, nt , bc); -} - /* IE_USERUSER */ void enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned char *user, int user_len, int nt, struct misdn_bchannel *bc) @@ -1577,7 +1342,7 @@ void enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned if (nt) *ntmode = p+1; else - qi->useruser = p - (unsigned char *)qi - sizeof(Q931_info_t); + qi->QI_ELEMENT(useruser) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_USER_USER; p[1] = l; p[2] = 0x80 + protocol; @@ -1595,8 +1360,8 @@ void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned if (!nt) { p = NULL; - if (qi->useruser) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->useruser + 1; + if (qi->QI_ELEMENT(useruser)) + p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(useruser) + 1; } if (!p) return; @@ -1619,3 +1384,5 @@ void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned } + + diff --git a/channels/misdn/isdn_lib.c b/channels/misdn/isdn_lib.c index aa1d51cea..ea7c20849 100644 --- a/channels/misdn/isdn_lib.c +++ b/channels/misdn/isdn_lib.c @@ -11,31 +11,56 @@ * the GNU General Public License */ + +#include <syslog.h> #include "isdn_lib_intern.h" +#include <mISDNuser/isdn_debug.h> +void misdn_join_conf(struct misdn_bchannel *bc, int conf_id); +void misdn_split_conf(struct misdn_bchannel *bc, int conf_id); -int misdn_ibuf_freecount(void *buf) -{ - return ibuf_freecount( (ibuffer_t*)buf); -} +int queue_cleanup_bc(struct misdn_bchannel *bc) ; -int misdn_ibuf_usedcount(void *buf) -{ - return ibuf_usedcount( (ibuffer_t*)buf); -} +int misdn_lib_get_l2_up(struct misdn_stack *stack); -void misdn_ibuf_memcpy_r(char *to, void *buf, int len) +struct misdn_stack* get_misdn_stack( void ); + +int misdn_lib_port_block(int port) { - ibuf_memcpy_r( to, (ibuffer_t*)buf, len); + struct misdn_stack *stack=get_misdn_stack(); + for ( ; stack; stack=stack->next) { + if (stack->port == port) { + stack->blocked=1; + return 0; + } + } + return -1; + } -void misdn_ibuf_memcpy_w(void *buf, char *from, int len) +int misdn_lib_port_unblock(int port) { - ibuf_memcpy_w((ibuffer_t*)buf, from, len); -} + struct misdn_stack *stack=get_misdn_stack(); + for ( ; stack; stack=stack->next) { + if (stack->port == port) { + stack->blocked=0; + return 0; + } + } + return -1; -struct misdn_stack* get_misdn_stack( void ); +} +int misdn_lib_is_port_blocked(int port) +{ + struct misdn_stack *stack=get_misdn_stack(); + for ( ; stack; stack=stack->next) { + if (stack->port == port) { + return stack->blocked; + } + } + return -1; +} int misdn_lib_is_ptp(int port) { @@ -46,6 +71,20 @@ int misdn_lib_is_ptp(int port) return -1; } +int misdn_lib_get_maxchans(int port) +{ + struct misdn_stack *stack=get_misdn_stack(); + for ( ; stack; stack=stack->next) { + if (stack->port == port) { + if (stack->pri) + return 30; + else + return 2; + } + } + return -1; +} + struct misdn_stack* get_stack_by_bc(struct misdn_bchannel *bc) { @@ -73,7 +112,8 @@ void get_show_stack_details(int port, char *buf) } if (stack) { - sprintf(buf, "* Stack Addr: Port %d Type %s Prot. %s L2Link %s L1Link:%s", stack->upper_id & IF_CONTRMASK, stack->mode==NT_MODE?"NT":"TE", stack->ptp?"PTP":"PMP", stack->l2link?"UP":"DOWN", stack->l1link?"UP":"DOWN"); + sprintf(buf, "* Port %d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d", stack->port, stack->nt?"NT":"TE", stack->ptp?"PTP":"PMP", stack->l2link?"UP":"DOWN", stack->l1link?"UP":"DOWN",stack->blocked); + } else { buf[0]=0; } @@ -125,6 +165,8 @@ struct misdn_lib { #define MISDN_DEBUG 0 +void misdn_tx_jitter(struct misdn_bchannel *bc, int len); + struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id); int setup_bc(struct misdn_bchannel *bc); @@ -165,14 +207,13 @@ struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned lon /* from isdn_lib.h */ int init_bc(struct misdn_stack * stack, struct misdn_bchannel *bc, int midev, int port, int bidx, char *msn, int firsttime); -struct misdn_stack* stack_te_init(int midev, int port, int ptp); -void stack_te_destroy(struct misdn_stack* stack); +struct misdn_stack* stack_init(int midev, int port, int ptp); +void stack_destroy(struct misdn_stack* stack); /* user iface */ int te_lib_init( void ) ; /* returns midev */ void te_lib_destroy(int midev) ; struct misdn_bchannel *manager_find_bc_by_pid(int pid); struct misdn_bchannel *manager_find_bc_holded(struct misdn_bchannel* bc); -unsigned char * manager_flip_buf_bits ( unsigned char * buf , int len); void manager_ph_control_block(struct misdn_bchannel *bc, int c1, void *c2, int c2_len); void manager_clean_bc(struct misdn_bchannel *bc ); void manager_bchannel_setup (struct misdn_bchannel *bc); @@ -234,7 +275,7 @@ void init_flip_bits(void) } } -static unsigned char * flip_buf_bits ( unsigned char * buf , int len) +unsigned char * flip_buf_bits ( unsigned char * buf , int len) { int i; char * start = buf; @@ -315,21 +356,27 @@ int send_msg (int midev, struct misdn_bchannel *bc, msg_t *dmsg) iframe_t *frm; frm = (iframe_t *)dmsg->data; struct misdn_stack *stack=get_stack_by_bc(bc); + + if (!stack) { + cb_log(0,bc->port,"send_msg: IEK!! no stack\n "); + return -1; + } - frm->addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN ; + frm->addr = (stack->upper_id | FLG_MSG_DOWN); frm->dinfo = bc->l3_id; - frm->len = (dmsg->len) - mISDN_HEADER_LEN; - + + cb_log(4,stack->port,"Sending msg, prim:%x addr:%x dinfo:%x\n",frm->prim,frm->addr,frm->dinfo); + mISDN_write(midev, dmsg->data, dmsg->len, TIMEOUT_1SEC); - free_msg(dmsg); return 0; } -static int mypid=0; +static int mypid=1; + int misdn_cap_is_speech(int cap) /** Poor mans version **/ @@ -362,7 +409,7 @@ void dump_chan_list(struct misdn_stack *stack) int i; for (i=0; i <stack->b_num; i++) { - cb_log(3, stack->port, "Idx:%d stack->cchan:%d Chan:%d\n",i,stack->channels[i], i+1); + cb_log(6, stack->port, "Idx:%d stack->cchan:%d Chan:%d\n",i,stack->channels[i], i+1); } } @@ -373,8 +420,10 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, int channel) { int i; + cb_log(1,stack->port,"find_free_chan: req_chan:%d\n",channel); + if (channel < 0 || channel > MAX_BCHANS) { - cb_log(4, stack->port, " !! out of bound call to find_free_chan_in_stack! (port:%d ch:%d)\n", stack->port, channel); + cb_log(4, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel); return 0; } @@ -383,7 +432,7 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, int channel) for (i = 0; i < stack->b_num; i++) { if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 Dchannel ;) and work with chan preselection */ if (!stack->channels[i]) { - cb_log (4, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1); + cb_log (1, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1); stack->channels[i] = 1; return i+1; } @@ -398,24 +447,96 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, int channel) int empty_chan_in_stack(struct misdn_stack *stack, int channel) { - cb_log (4, stack?stack->port:0, " --> empty chan %d\n",channel); + if (channel<=0) { + cb_log(0,stack?stack->port:0, "empty_chan_inst_stack: cannot empty channel %d\n",channel); + return -1; + } + + cb_log (4, stack?stack->port:0, "empty_chan_in_stack: %d\n",channel); stack->channels[channel-1] = 0; dump_chan_list(stack); return 0; } +char *bc_state2str(enum bchannel_state state) { + int i; + + struct bchan_state_s { + char *n; + enum bchannel_state s; + } states[] = { + {"BCHAN_CLEANED", BCHAN_CLEANED }, + {"BCHAN_EMPTY", BCHAN_EMPTY}, + {"BCHAN_SETUP", BCHAN_SETUP}, + {"BCHAN_SETUPED", BCHAN_SETUPED}, + {"BCHAN_ACTIVE", BCHAN_ACTIVE}, + {"BCHAN_ACTIVATED", BCHAN_ACTIVATED}, + {"BCHAN_BRIDGE", BCHAN_BRIDGE}, + {"BCHAN_BRIDGED", BCHAN_BRIDGED}, + {"BCHAN_RELEASE", BCHAN_RELEASE}, + {"BCHAN_RELEASED", BCHAN_RELEASED}, + {"BCHAN_CLEAN", BCHAN_CLEAN}, + {"BCHAN_CLEAN_REQUEST", BCHAN_CLEAN_REQUEST}, + {"BCHAN_ERROR", BCHAN_ERROR} + }; + + for (i=0; i< sizeof(states)/sizeof(struct bchan_state_s); i++) + if ( states[i].s == state) + return states[i].n; + + return "UNKNOWN"; +} + +void bc_state_change(struct misdn_bchannel *bc, enum bchannel_state state) +{ + cb_log(5,bc->port,"BC_STATE_CHANGE: from:%s to:%s\n", + bc_state2str(bc->bc_state), + bc_state2str(state) ); + + switch (state) { + case BCHAN_ACTIVATED: + if (bc->next_bc_state == BCHAN_BRIDGED) { + misdn_join_conf(bc, bc->conf_id); + bc->next_bc_state = BCHAN_EMPTY; + return; + } + default: + bc->bc_state=state; + break; + } +} + +void bc_next_state_change(struct misdn_bchannel *bc, enum bchannel_state state) +{ + cb_log(5,bc->port,"BC_NEXT_STATE_CHANGE: from:%s to:%s\n", + bc_state2str(bc->next_bc_state), + bc_state2str(state) ); + + bc->next_bc_state=state; +} + void empty_bc(struct misdn_bchannel *bc) { - bc->state=STATE_NOTHING; + bc->bframe_len=0; + + bc->in_use= 0; + bc->channel = 0; - bc->in_use = 0; + bc->sending_complete = 0; + + bc->restart_channel=0; + + bc->conf_id = 0; + + bc->need_more_infos = 0; + bc->send_dtmf=0; bc->nodsp=0; bc->nojitter=0; - + bc->time_usec=0; bc->rxgain=0; @@ -426,12 +547,13 @@ void empty_bc(struct misdn_bchannel *bc) bc->crypt_key[0] = 0; - bc->tone=TONE_NONE; - bc->tone_cnt2 = bc->tone_cnt=0; + bc->generate_tone=0; + bc->tone_cnt=0; bc->dnumplan=NUMPLAN_UNKNOWN; bc->onumplan=NUMPLAN_UNKNOWN; bc->rnumplan=NUMPLAN_UNKNOWN; + bc->cpnnumplan=NUMPLAN_UNKNOWN; bc->active = 0; @@ -441,8 +563,10 @@ void empty_bc(struct misdn_bchannel *bc) bc->ec_enable = 0; bc->ec_deftaps = 128; bc->ec_whenbridged = 0; + +#ifdef EC_TRAIN bc->ec_training = 1; - +#endif bc->orig=0; @@ -460,24 +584,28 @@ void empty_bc(struct misdn_bchannel *bc) bc->capability=INFO_CAPABILITY_SPEECH; bc->law=INFO_CODEC_ALAW; bc->mode=0; - bc->rate=0; + bc->rate=0x10; bc->user1=0; - bc->async=0; bc->urate=0; + bc->hdlc=0; bc->info_dad[0] = 0; bc->display[0] = 0; bc->infos_pending[0] = 0; + bc->cad[0] = 0; bc->oad[0] = 0; bc->dad[0] = 0; + bc->rad[0] = 0; bc->orig_dad[0] = 0; - bc->facility=FACILITY_NONE; - bc->facility_calldeflect_nr[0]=0; - + bc->fac_type=FACILITY_NONE; + bc->out_fac_type=FACILITY_NONE; + bc->te_choose_channel = 0; + + bc->holded_bc=NULL; } @@ -486,29 +614,38 @@ int clean_up_bc(struct misdn_bchannel *bc) int ret=0; unsigned char buff[32]; struct misdn_stack * stack; + + cb_log(3, bc?bc->port:0, "$$$ CLEANUP CALLED pid:%d\n", bc?bc->pid:-1); if (!bc ) return -1; stack=get_stack_by_bc(bc); + if (!stack) return -1; - if (!bc->upset) { + switch (bc->bc_state ) { + case BCHAN_CLEANED: cb_log(5, stack->port, "$$$ Already cleaned up bc with stid :%x\n", bc->b_stid); return -1; + + default: + break; } - - cb_log(5, stack->port, "$$$ Cleaning up bc with stid :%x\n", bc->b_stid); - - if ( misdn_cap_is_speech(bc->capability) && bc->ec_enable) { - manager_ec_disable(bc); - } + cb_log(2, stack->port, "$$$ Cleaning up bc with stid :%x pid:%d\n", bc->b_stid, bc->pid); - mISDN_write_frame(stack->midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + manager_bchannel_deactivate(bc); + + + manager_ec_disable(bc); + + + mISDN_write_frame(stack->midev, buff, bc->layer_id|FLG_MSG_TARGET|FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + /*mISDN_clear_stack(stack->midev, bc->b_stid);*/ + bc->b_stid = 0; - - bc->upset=0; + bc_state_change(bc, BCHAN_CLEANED); return ret; } @@ -518,13 +655,13 @@ int clean_up_bc(struct misdn_bchannel *bc) void clear_l3(struct misdn_stack *stack) { int i; + for (i=0; i<stack->b_num; i++) { if (global_state == MISDN_INITIALIZED) { - cb_event(EVENT_CLEANUP, &stack->bc[i], glob_mgr->user_data); + cb_event(EVENT_CLEANUP, &stack->bc[i], NULL); empty_chan_in_stack(stack,i+1); empty_bc(&stack->bc[i]); clean_up_bc(&stack->bc[i]); - } } @@ -532,7 +669,13 @@ void clear_l3(struct misdn_stack *stack) int set_chan_in_stack(struct misdn_stack *stack, int channel) { - stack->channels[channel-1] = 1; + + cb_log(4,stack->port,"set_chan_in_stack: %d\n",channel); + if (channel >=1 ) { + stack->channels[channel-1] = 1; + } else { + cb_log(0,stack->port,"couldn't set channel %d in\n", channel ); + } return 0; } @@ -549,19 +692,59 @@ int chan_in_stack_free(struct misdn_stack *stack, int channel) static int newteid=0; -#ifdef MISDNUSER_JOLLY #define MAXPROCS 0x100 -#else -#define MAXPROCS 0x10 -#endif + +int misdn_lib_get_l1_down(struct misdn_stack *stack) +{ + /* Pull Up L1 */ + iframe_t act; + act.prim = PH_DEACTIVATE | REQUEST; + act.addr = (stack->upper_id | FLG_MSG_DOWN) ; + + + act.dinfo = 0; + act.len = 0; + + return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); + + +} + + +int misdn_lib_get_l2_down(struct misdn_stack *stack) +{ + + if (stack->ptp && (stack->nt) ) { + msg_t *dmsg; + /* L2 */ + dmsg = create_l2msg(DL_RELEASE| REQUEST, 0, 0); + + if (stack->nst.manager_l3(&stack->nst, dmsg)) + free_msg(dmsg); + + } else { + iframe_t act; + + act.prim = DL_RELEASE| REQUEST; + act.addr = (stack->upper_id |FLG_MSG_DOWN) ; + + act.dinfo = 0; + act.len = 0; + return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); + } + + return 0; +} int misdn_lib_get_l1_up(struct misdn_stack *stack) { - /* Pull Up L1 if we have JOLLY */ + /* Pull Up L1 */ iframe_t act; act.prim = PH_ACTIVATE | REQUEST; - act.addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN ; + act.addr = (stack->upper_id | FLG_MSG_DOWN) ; + + act.dinfo = 0; act.len = 0; @@ -572,7 +755,7 @@ int misdn_lib_get_l1_up(struct misdn_stack *stack) int misdn_lib_get_l2_up(struct misdn_stack *stack) { - if (stack->ptp && (stack->mode == NT_MODE) ) { + if (stack->ptp && (stack->nt) ) { msg_t *dmsg; /* L2 */ dmsg = create_l2msg(DL_ESTABLISH | REQUEST, 0, 0); @@ -584,8 +767,8 @@ int misdn_lib_get_l2_up(struct misdn_stack *stack) iframe_t act; act.prim = DL_ESTABLISH | REQUEST; - - act.addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN; + act.addr = (stack->upper_id |FLG_MSG_DOWN) ; + act.dinfo = 0; act.len = 0; return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); @@ -594,23 +777,37 @@ int misdn_lib_get_l2_up(struct misdn_stack *stack) return 0; } - -int misdn_lib_get_l2_status(struct misdn_stack *stack) +int misdn_lib_get_l2_te_ptp_up(struct misdn_stack *stack) { iframe_t act; - -#ifdef DL_STATUS - act.prim = DL_STATUS | REQUEST; -#else + act.prim = DL_ESTABLISH | REQUEST; -#endif - act.addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN; + act.addr = (stack->upper_id & ~LAYER_ID_MASK) | 3 | FLG_MSG_DOWN; + act.dinfo = 0; act.len = 0; return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); + return 0; } +int misdn_lib_get_short_status(struct misdn_stack *stack) +{ + iframe_t act; + + + act.prim = MGR_SHORTSTATUS | REQUEST; + + act.addr = (stack->upper_id | MSG_BROADCAST) ; + + act.dinfo = SSTATUS_BROADCAST_BIT | SSTATUS_ALL; + + act.len = 0; + return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); +} + + + static int create_process (int midev, struct misdn_bchannel *bc) { iframe_t ncr; int l3_id; @@ -618,35 +815,32 @@ static int create_process (int midev, struct misdn_bchannel *bc) { struct misdn_stack *stack=get_stack_by_bc(bc); int free_chan; - if (stack->mode == NT_MODE) { + if (stack->nt) { free_chan = find_free_chan_in_stack(stack, bc->channel_preselected?bc->channel:0); if (!free_chan) return -1; bc->channel=free_chan; + + cb_log(4,stack->port, " --> found channel: %d\n",free_chan); for (i=0; i <= MAXPROCS; i++) if (stack->procids[i]==0) break; if (i== MAXPROCS) { - cb_log(0, stack->port, "Couldnt Create New ProcId Port:%d\n",stack->port); + cb_log(0, stack->port, "Couldnt Create New ProcId.\n"); return -1; } stack->procids[i]=1; -#ifdef MISDNUSER_JOLLY l3_id = 0xff00 | i; -#else - l3_id = 0xfff0 | i; -#endif ncr.prim = CC_NEW_CR | REQUEST; - ncr.addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN ; + + ncr.addr = (stack->upper_id | FLG_MSG_DOWN) ; + ncr.dinfo = l3_id; ncr.len = 0; bc->l3_id = l3_id; - if (mypid>5000) mypid=0; - bc->pid=mypid++; - cb_log(3, stack->port, " --> new_l3id %x\n",l3_id); } else { @@ -655,6 +849,7 @@ static int create_process (int midev, struct misdn_bchannel *bc) { free_chan = find_free_chan_in_stack(stack, bc->channel_preselected?bc->channel:0); if (!free_chan) return -1; bc->channel=free_chan; + cb_log(2,stack->port, " --> found channel: %d\n",free_chan); } else { /* other phones could have made a call also on this port (ptmp) */ bc->channel=0xff; @@ -668,15 +863,14 @@ static int create_process (int midev, struct misdn_bchannel *bc) { l3_id = (entity<<16) | newteid; /* preparing message */ ncr.prim = CC_NEW_CR | REQUEST; - ncr.addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN ; + + ncr.addr = (stack->upper_id | FLG_MSG_DOWN) ; + ncr.dinfo =l3_id; ncr.len = 0; /* send message */ bc->l3_id = l3_id; - if (mypid>5000) mypid=0; - bc->pid=mypid++; - cb_log(3, stack->port, "--> new_l3id %x\n",l3_id); mISDN_write(midev, &ncr, mISDN_HEADER_LEN+ncr.len, TIMEOUT_1SEC); @@ -698,34 +892,38 @@ int setup_bc(struct misdn_bchannel *bc) mISDN_pid_t pid; int ret; + struct misdn_stack *stack=get_stack_by_bc(bc); + + if (!stack) { + cb_log(0, bc->port, "setup_bc: NO STACK FOUND!!\n"); + return -1; + } int midev=stack->midev; int channel=bc->channel-1-(bc->channel>16); int b_stid=stack->b_stids[channel>=0?channel:0]; - - if (bc->nodsp ) - clean_up_bc(bc); - - if ( !misdn_cap_is_speech(bc->capability)) - clean_up_bc(bc); - - - if (bc->upset) { - cb_log(4, stack->port, "$$$ bc already upsetted stid :%x\n", b_stid); - return -1; + + switch (bc->bc_state) { + case BCHAN_CLEANED: + break; + default: + cb_log(4, stack->port, "$$$ bc already upsetted stid :%x (state:%s)\n", b_stid, bc_state2str(bc->bc_state) ); + return -1; } cb_log(5, stack->port, "$$$ Setting up bc with stid :%x\n", b_stid); if (b_stid <= 0) { - cb_log(0, stack->port," -- Stid <=0 at the moment on port:%d channel:%d\n",stack->port,channel); + cb_log(0, stack->port," -- Stid <=0 at the moment in channel:%d\n",channel); + + bc_state_change(bc,BCHAN_ERROR); return 1; } - + bc->b_stid = b_stid; { @@ -738,78 +936,117 @@ int setup_bc(struct misdn_bchannel *bc) li.st = bc->b_stid; /* given idx */ - if ( misdn_cap_is_speech(bc->capability) && !bc->nodsp && bc->async != 1) { - cb_log(4, stack->port,"setup_bc: with dsp\n"); +#define MISDN_DSP +#ifndef MISDN_DSP + bc->nodsp=1; +#endif + if ( bc->hdlc || bc->nodsp) { + cb_log(4, stack->port,"setup_bc: without dsp\n"); { int l = sizeof(li.name); - strncpy(li.name, "B L4", l); + strncpy(li.name, "B L3", l); li.name[l-1] = 0; } - li.pid.layermask = ISDN_LAYER((4)); - li.pid.protocol[4] = ISDN_PID_L4_B_USER; + li.pid.layermask = ISDN_LAYER((3)); + li.pid.protocol[3] = ISDN_PID_L3_B_USER; + bc->layer=3; } else { - cb_log(4, stack->port,"setup_bc: without dsp\n"); + cb_log(4, stack->port,"setup_bc: with dsp\n"); { int l = sizeof(li.name); - strncpy(li.name, "B L3", l); + strncpy(li.name, "B L4", l); li.name[l-1] = 0; } - li.pid.layermask = ISDN_LAYER((3)); - li.pid.protocol[3] = ISDN_PID_L3_B_USER; - } + li.pid.layermask = ISDN_LAYER((4)); + li.pid.protocol[4] = ISDN_PID_L4_B_USER +; + bc->layer=4; + + } ret = mISDN_new_layer(midev, &li); - if (ret <= 0) { - cb_log(0, stack->port,"New Layer Err: %d %s port:%d\n",ret,strerror(errno), stack->port); + if (ret ) { + cb_log(0, stack->port,"New Layer Err: %d %s\n",ret,strerror(errno)); + + bc_state_change(bc,BCHAN_ERROR); return(-EINVAL); } - - bc->layer_id = ret; + + bc->layer_id = li.id; } memset(&pid, 0, sizeof(pid)); - bc->addr = ( bc->layer_id & IF_ADDRMASK) | IF_DOWN; - cb_log(4, stack->port," --> Got Adr %x\n", bc->addr); - cb_log(4, stack->port," --> Channel is %d\n", bc->channel); - if (bc->async == 1 || bc->nodsp) { - cb_log(4, stack->port," --> TRANSPARENT Mode (no DSP, no HDLC)\n"); + cb_log(4, stack->port," --> Channel is %d\n", bc->channel); + + if (bc->nodsp) { + cb_log(2, stack->port," --> TRANSPARENT Mode (no DSP, no HDLC)\n"); pid.protocol[1] = ISDN_PID_L1_B_64TRANS; pid.protocol[2] = ISDN_PID_L2_B_TRANS; pid.protocol[3] = ISDN_PID_L3_B_USER; pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)); - } else if ( misdn_cap_is_speech(bc->capability)) { - cb_log(4, stack->port," --> TRANSPARENT Mode\n"); + } else if ( bc->hdlc ) { + cb_log(2, stack->port," --> HDLC Mode\n"); +#ifdef ACK_HDLC + bc->ack_hdlc=(sem_t*)malloc(sizeof(sem_t)); + if ( sem_init((sem_t*)bc->ack_hdlc, 1, 0)<0 ) + sem_init((sem_t*)bc->ack_hdlc, 0, 0); +#endif + + pid.protocol[1] = ISDN_PID_L1_B_64HDLC ; + pid.protocol[2] = ISDN_PID_L2_B_TRANS ; + pid.protocol[3] = ISDN_PID_L3_B_USER; + pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) ; + } else { + cb_log(2, stack->port," --> TRANSPARENT Mode\n"); pid.protocol[1] = ISDN_PID_L1_B_64TRANS; pid.protocol[2] = ISDN_PID_L2_B_TRANS; pid.protocol[3] = ISDN_PID_L3_B_DSP; pid.protocol[4] = ISDN_PID_L4_B_USER; pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4)); - } else { - cb_log(4, stack->port," --> HDLC Mode\n"); - pid.protocol[1] = ISDN_PID_L1_B_64HDLC ; - pid.protocol[2] = ISDN_PID_L2_B_TRANS ; - pid.protocol[3] = ISDN_PID_L3_B_USER; - pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) ; - } - + } + ret = mISDN_set_stack(midev, bc->b_stid, &pid); - - + if (ret){ - cb_log(5, stack->port,"$$$ Set Stack Err: %d %s\n",ret,strerror(errno)); - - mISDN_write_frame(midev, buff, bc->addr, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + cb_log(0, stack->port,"$$$ Set Stack Err: %d %s\n",ret,strerror(errno)); + + mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + + bc_state_change(bc,BCHAN_ERROR); return(-EINVAL); } - - bc->upset=1; - + + ret = mISDN_get_setstack_ind(midev, bc->layer_id); + + if (ret) { + cb_log(0, stack->port,"$$$ Set StackIND Err: %d %s\n",ret,strerror(errno)); + mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + + bc_state_change(bc,BCHAN_ERROR); + return(-EINVAL); + } + + ret = mISDN_get_layerid(midev, bc->b_stid, bc->layer) ; + + bc->addr = ret>0? ret : 0; + + if (!bc->addr) { + cb_log(0, stack->port,"$$$ Get Layerid Err: %d %s\n",ret,strerror(errno)); + mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); + + bc_state_change(bc,BCHAN_ERROR); + } + + manager_bchannel_activate(bc); + + bc_state_change(bc,BCHAN_ACTIVATED); + return 0; } @@ -824,7 +1061,7 @@ int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, in if (!bc) return -1; - cb_log(4, port, "Init.BC %d on port:%d\n",bidx, port); + cb_log(8, port, "Init.BC %d.\n",bidx); memset(bc, 0,sizeof(struct misdn_bchannel)); @@ -836,30 +1073,24 @@ int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, in empty_bc(bc); - bc->upset=0; + bc_state_change(bc, BCHAN_CLEANED); + bc->port=stack->port; - bc->nt=stack->mode==NT_MODE?1:0; + bc->nt=stack->nt?1:0; { ibuffer_t* ibuf= init_ibuffer(MISDN_IBUF_SIZE); - ibuffer_t* mbuf= init_ibuffer(MISDN_IBUF_SIZE); if (!ibuf) return -1; - if (!mbuf) return -1; clear_ibuffer( ibuf); - clear_ibuffer( mbuf); ibuf->rsem=malloc(sizeof(sem_t)); - mbuf->rsem=malloc(sizeof(sem_t)); bc->astbuf=ibuf; - bc->misdnbuf=mbuf; if (sem_init(ibuf->rsem,1,0)<0) sem_init(ibuf->rsem,0,0); - if (sem_init(mbuf->rsem,1,0)< 0) - sem_init(mbuf->rsem,0,0); } @@ -870,13 +1101,13 @@ int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, in stack_info_t *stinf; ret = mISDN_get_stack_info(midev, stack->port, buff, sizeof(buff)); if (ret < 0) { - cb_log(0, port, "%s: Cannot get stack info for port:%d (ret=%d)\n", __FUNCTION__, port, ret); + cb_log(0, port, "%s: Cannot get stack info for this port. (ret=%d)\n", __FUNCTION__, ret); return -1; } stinf = (stack_info_t *)&frm->data.p; - cb_log(4, port, " --> Child %x\n",stinf->child[bidx]); + cb_log(8, port, " --> Child %x\n",stinf->child[bidx]); } return 0; @@ -884,98 +1115,7 @@ int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, in -struct misdn_stack * stack_nt_init(struct misdn_stack *stack, int midev, int port) -{ - int ret; - layer_info_t li; - interface_info_t ii; - - - cb_log(4, port, "Init. Stack on port:%d\n",port); - stack->mode = NT_MODE; - - stack->lower_id = mISDN_get_layerid(midev, stack->d_stid, 1); - if (stack->lower_id <= 0) { - cb_log(0, port, "%s: Cannot get layer(%d) id of port:%d\n", __FUNCTION__, 1, port); - return(NULL); - } - - - memset(&li, 0, sizeof(li)); - { - int l = sizeof(li.name); - strncpy(li.name,"net l2", l); - li.name[l-1] = 0; - } - li.object_id = -1; - li.extentions = 0; - li.pid.protocol[2] = ISDN_PID_L2_LAPD_NET; - li.pid.layermask = ISDN_LAYER((2)); - li.st = stack->d_stid; - - - stack->upper_id = mISDN_new_layer(midev, &li); - if (stack->upper_id <= 0) { - cb_log(0, port, "%s: Cannot add layer %d of port:%d\n", __FUNCTION__, 2, port); - return(NULL); - } - - cb_log(4, port, "NT Stacks upper_id %x\n",stack->upper_id); - - memset(&ii, 0, sizeof(ii)); - ii.extentions = EXT_IF_EXCLUSIV; - ii.owner = stack->upper_id; - ii.peer = stack->lower_id; - ii.stat = IF_DOWN; - ret = mISDN_connect(midev, &ii); - if (ret) { - cb_log(0, port, "%s: Cannot connect layer %d of port:%d exclusively.\n", __FUNCTION__, 2, port); - return(NULL); - } - - /* create nst (nt-mode only) */ - { - memset(&stack->nst, 0, sizeof(net_stack_t)); - memset(&stack->mgr, 0, sizeof(manager_t)); - - stack->mgr.nst = &stack->nst; - stack->nst.manager = &stack->mgr; - - stack->nst.l3_manager = handle_event_nt; - stack->nst.device = midev; - stack->nst.cardnr = port; - stack->nst.d_stid = stack->d_stid; - -#ifdef MISDNUSER_JOLLY - stack->nst.feature = FEATURE_NET_HOLD; - if (stack->ptp) - stack->nst.feature |= FEATURE_NET_PTP; - if (stack->pri) - stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID; -#endif - - stack->nst.l1_id = stack->lower_id; - stack->nst.l2_id = stack->upper_id; - - msg_queue_init(&stack->nst.down_queue); - - Isdnl2Init(&stack->nst); - Isdnl3Init(&stack->nst); - } - - misdn_lib_get_l1_up(stack); - - if (stack->ptp) { - misdn_lib_get_l2_up(stack); - stack->l2link=0; - } - - - return stack; -} - - -struct misdn_stack* stack_te_init( int midev, int port, int ptp ) +struct misdn_stack* stack_init( int midev, int port, int ptp ) { int ret; unsigned char buff[1025]; @@ -983,18 +1123,16 @@ struct misdn_stack* stack_te_init( int midev, int port, int ptp ) stack_info_t *stinf; int i; layer_info_t li; - interface_info_t ii; + struct misdn_stack *stack = malloc(sizeof(struct misdn_stack)); if (!stack ) return NULL; - - //cb_log(2, "Init. Stack on port:%d\n",port); - cb_log(4, port, "Init. Stack on port:%d\n",port); + cb_log(8, port, "Init. Stack.\n"); memset(stack,0,sizeof(struct misdn_stack)); for (i=0; i<MAX_BCHANS + 1; i++ ) stack->channels[i]=0; - + stack->port=port; stack->midev=midev; stack->ptp=ptp; @@ -1003,11 +1141,12 @@ struct misdn_stack* stack_te_init( int midev, int port, int ptp ) stack->pri=0; msg_queue_init(&stack->downqueue); + msg_queue_init(&stack->upqueue); /* query port's requirements */ ret = mISDN_get_stack_info(midev, port, buff, sizeof(buff)); if (ret < 0) { - cb_log(0, port, "%s: Cannot get stack info for port:%d (ret=%d)\n", __FUNCTION__, port, ret); + cb_log(0, port, "%s: Cannot get stack info for this port. (ret=%d)\n", __FUNCTION__, ret); return(NULL); } @@ -1021,13 +1160,12 @@ struct misdn_stack* stack_te_init( int midev, int port, int ptp ) switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) { case ISDN_PID_L0_TE_S0: - //cb_log(2, "TE Stack\n"); - stack->mode = TE_MODE; + stack->nt=0; break; case ISDN_PID_L0_NT_S0: - cb_log(4, port, "NT Stack\n"); + cb_log(8, port, "NT Stack\n"); - return stack_nt_init(stack,midev,port); + stack->nt=1; break; case ISDN_PID_L0_TE_U: @@ -1039,82 +1177,138 @@ struct misdn_stack* stack_te_init( int midev, int port, int ptp ) case ISDN_PID_L0_NT_UP2: break; case ISDN_PID_L0_TE_E1: - cb_log(4, port, "TE S2M Stack\n"); - stack->mode = TE_MODE; + cb_log(8, port, "TE S2M Stack\n"); + stack->nt=0; stack->pri=1; break; case ISDN_PID_L0_NT_E1: - cb_log(4, port, "TE S2M Stack\n"); - stack->mode = NT_MODE; + cb_log(8, port, "TE S2M Stack\n"); + stack->nt=1; stack->pri=1; - - return stack_nt_init(stack,midev,port); + break; default: - cb_log(0, port, "unknown port(%d) type 0x%08x\n", port, stinf->pid.protocol[0]); + cb_log(0, port, "this is a unknown port type 0x%08x\n", stinf->pid.protocol[0]); } - - if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP ) { /* || (nt&&ptp) || pri */ - stack->ptp = 1; - } else { - stack->ptp = 0; - } - stack->lower_id = mISDN_get_layerid(midev, stack->d_stid, 3); - if (stack->lower_id <= 0) { - cb_log(0, stack->port, "No lower Id port:%d\n", stack->port); - return(NULL); + if (!stack->nt) { + if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP ) { + stack->ptp = 1; + } else { + stack->ptp = 0; + } } - - memset(&li, 0, sizeof(li)); + { - int l = sizeof(li.name); - strncpy(li.name, "user L4", l); - li.name[l-1] = 0; - } - li.object_id = -1; - li.extentions = 0; - - li.pid.protocol[4] = ISDN_PID_L4_CAPI20; - - li.pid.layermask = ISDN_LAYER((4)); - li.st = stack->d_stid; - stack->upper_id = mISDN_new_layer(midev, &li); - - if (stack->upper_id <= 0) { - cb_log(0, stack->port, "No Upper ID port:%d\n",stack->port); - return(NULL); - } - - memset(&ii, 0, sizeof(ii)); - ii.extentions = EXT_IF_EXCLUSIV | EXT_IF_CREATE; - ii.owner = stack->upper_id; - ii.peer = stack->lower_id; - ii.stat = IF_DOWN; - ret = mISDN_connect(midev, &ii); - if (ret) { - cb_log(0, stack->port, "No Connect port:%d\n", stack->port); - return NULL; + int ret; + int nt=stack->nt; + + cb_log(8, port, "Init. Stack.\n"); + + memset(&li, 0, sizeof(li)); + { + int l = sizeof(li.name); + strncpy(li.name,nt?"net l2":"user l4", l); + li.name[l-1] = 0; + } + li.object_id = -1; + li.extentions = 0; + li.pid.protocol[nt?2:4] = nt?ISDN_PID_L2_LAPD_NET:ISDN_PID_L4_CAPI20; + li.pid.layermask = ISDN_LAYER((nt?2:4)); + li.st = stack->d_stid; + + + ret = mISDN_new_layer(midev, &li); + if (ret) { + cb_log(0, port, "%s: Cannot add layer %d to this port.\n", __FUNCTION__, nt?2:4); + return(NULL); + } + + + stack->upper_id = li.id; + ret = mISDN_register_layer(midev, stack->d_stid, stack->upper_id); + if (ret) + { + cb_log(0,port,"Cannot register layer %d of this port.\n", nt?2:4); + return(NULL); + } + + stack->lower_id = mISDN_get_layerid(midev, stack->d_stid, nt?1:3); + if (stack->lower_id < 0) { + cb_log(0, port, "%s: Cannot get layer(%d) id of this port.\n", __FUNCTION__, nt?1:3); + return(NULL); + } + + stack->upper_id = mISDN_get_layerid(midev, stack->d_stid, nt?2:4); + if (stack->upper_id < 0) { + cb_log(0, port, "%s: Cannot get layer(%d) id of this port.\n", __FUNCTION__, 2); + return(NULL); + } + + cb_log(8, port, "NT Stacks upper_id %x\n",stack->upper_id); + + + /* create nst (nt-mode only) */ + if (nt) { + + memset(&stack->nst, 0, sizeof(net_stack_t)); + memset(&stack->mgr, 0, sizeof(manager_t)); + + stack->mgr.nst = &stack->nst; + stack->nst.manager = &stack->mgr; + + stack->nst.l3_manager = handle_event_nt; + stack->nst.device = midev; + stack->nst.cardnr = port; + stack->nst.d_stid = stack->d_stid; + + stack->nst.feature = FEATURE_NET_HOLD; + if (stack->ptp) + stack->nst.feature |= FEATURE_NET_PTP; + if (stack->pri) + stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID; + + stack->nst.l1_id = stack->lower_id; + stack->nst.l2_id = stack->upper_id; + + msg_queue_init(&stack->nst.down_queue); + + Isdnl2Init(&stack->nst); + Isdnl3Init(&stack->nst); + } + + stack->l1link=0; + stack->l2link=0; +#if 0 + if (!stack->nt) { + misdn_lib_get_short_status(stack); + } else { + misdn_lib_get_l1_up(stack); + if (!stack->ptp) misdn_lib_get_l1_up(stack); + misdn_lib_get_l2_up(stack); + } +#endif + misdn_lib_get_short_status(stack); + misdn_lib_get_l1_up(stack); + misdn_lib_get_l2_up(stack); } - - misdn_lib_get_l1_up(stack); - misdn_lib_get_l2_status(stack); + + cb_log(8,0,"stack_init: port:%d lowerId:%x upperId:%x\n",stack->port,stack->lower_id, stack->upper_id); - /* initially, we assume that the link is NOT up */ - stack->l2link = 0; - stack->l1link = 0; - - stack->next=NULL; - return stack; - } -void stack_te_destroy(struct misdn_stack* stack) + +void stack_destroy(struct misdn_stack* stack) { char buf[1024]; if (!stack) return; + + if (stack->nt) { + cleanup_Isdnl2(&stack->nst); + cleanup_Isdnl3(&stack->nst); + } if (stack->lower_id) mISDN_write_frame(stack->midev, buf, stack->lower_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); @@ -1127,11 +1321,12 @@ void stack_te_destroy(struct misdn_stack* stack) struct misdn_stack * find_stack_by_addr(int addr) { struct misdn_stack *stack; - + for (stack=glob_mgr->stack_list; stack; stack=stack->next) { - if ( stack->upper_id == addr) return stack; + if ( (stack->upper_id&STACK_ID_MASK) == (addr&STACK_ID_MASK)) return stack; + } return NULL; @@ -1193,72 +1388,113 @@ struct misdn_bchannel *find_bc_holded(struct misdn_stack *stack) struct misdn_bchannel *find_bc_by_addr(unsigned long addr) { - int port = addr & IF_CONTRMASK; struct misdn_stack* stack; int i; - + for (stack=glob_mgr->stack_list; stack; stack=stack->next) { - - if (stack->port == port) { - for (i=0; i< stack->b_num; i++) { - if (stack->bc[i].addr==addr) { - return &stack->bc[i]; - } + + for (i=0; i< stack->b_num; i++) { + + if ( (stack->bc[i].addr&STACK_ID_MASK)==(addr&STACK_ID_MASK) || stack->bc[i].layer_id== addr ) { + return &stack->bc[i]; } } + } - + + + return NULL; +} + + +struct misdn_bchannel *find_bc_by_channel(int port, int channel) +{ + struct misdn_stack* stack=find_stack_by_port(port); + int i; + + if (!stack) return NULL; + + for (i=0; i< stack->b_num; i++) { + if ( stack->bc[i].channel== channel ) { + return &stack->bc[i]; + } + } + return NULL; } + int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_t *frm) { struct misdn_stack *stack=get_stack_by_bc(bc); - if (stack->mode == TE_MODE) { + + if (!stack->nt) { + switch (event) { case EVENT_CONNECT_ACKNOWLEDGE: - manager_bchannel_activate(bc); +#if 0 + if ( !misdn_cap_is_speech(bc->capability)) { + int ret=setup_bc(bc); + if (ret == -EINVAL){ + cb_log(0,bc->port,"send_event: setup_bc failed\n"); + } + } +#endif break; case EVENT_CONNECT: - + if ( *bc->crypt_key ) { - cb_log(4, stack->port, "ENABLING BLOWFISH port:%d channel:%d oad%d:%s dad%d:%s\n", stack->port, bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); - + cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); } - case EVENT_SETUP: - if (bc->channel>0 && bc->channel<255) - set_chan_in_stack(stack, bc->channel); - break; case EVENT_ALERTING: case EVENT_PROGRESS: case EVENT_PROCEEDING: case EVENT_SETUP_ACKNOWLEDGE: + + setup_bc(bc); + + case EVENT_SETUP: { - struct misdn_stack *stack=find_stack_by_port(frm->addr&IF_CONTRMASK); - if (!stack) return -1; - if (bc->channel == 0xff) { bc->channel=find_free_chan_in_stack(stack, 0); if (!bc->channel) { cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n"); break; } - } - - if (stack->mode == TE_MODE) { - setup_bc(bc); + } + + if (bc->channel >0 && bc->channel<255) { + set_chan_in_stack(stack ,bc->channel); + } + +#if 0 + int ret=setup_bc(bc); + if (ret == -EINVAL){ + cb_log(0,bc->port,"handle_event: setup_bc failed\n"); + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); } +#endif } - + break; + + case EVENT_RELEASE_COMPLETE: + case EVENT_RELEASE: + if (bc->channel>0) + empty_chan_in_stack(stack,bc->channel); + int tmpcause=bc->cause; + empty_bc(bc); + bc->cause=tmpcause; + clean_up_bc(bc); + break; default: break; } @@ -1271,31 +1507,28 @@ int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_t *frm) int handle_new_process(struct misdn_stack *stack, iframe_t *frm) { - struct misdn_bchannel* bc=misdn_lib_get_free_bc(frm->addr&IF_CONTRMASK, 0); + struct misdn_bchannel* bc=misdn_lib_get_free_bc(stack->port, 0); + if (!bc) { - cb_log(0, 0, " --> !! lib: No free channel!\n"); + cb_log(0, stack->port, " --> !! lib: No free channel!\n"); return -1; } - cb_log(4, stack->port, " --> new_process: New L3Id: %x\n",frm->dinfo); + cb_log(7, stack->port, " --> new_process: New L3Id: %x\n",frm->dinfo); bc->l3_id=frm->dinfo; - - if (mypid>5000) mypid=0; - bc->pid=mypid++; return 0; } -int handle_cr ( iframe_t *frm) +int handle_cr ( struct misdn_stack *stack, iframe_t *frm) { - struct misdn_stack *stack=find_stack_by_port(frm->addr&IF_CONTRMASK); - if (!stack) return -1; switch (frm->prim) { case CC_NEW_CR|INDICATION: - cb_log(4, stack->port, " --> lib: NEW_CR Ind with l3id:%x port:%d\n",frm->dinfo, stack->port); - handle_new_process(stack, frm); + cb_log(7, stack->port, " --> lib: NEW_CR Ind with l3id:%x on this port.\n",frm->dinfo); + if (handle_new_process(stack, frm) <0) + return -1; return 1; case CC_NEW_CR|CONFIRM: return 1; @@ -1312,22 +1545,29 @@ int handle_cr ( iframe_t *frm) struct misdn_bchannel dummybc; if (!bc) { - cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on port:%d\n", frm->dinfo, stack->port); + cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on this port.\n", frm->dinfo); memset (&dummybc,0,sizeof(dummybc)); dummybc.port=stack->port; dummybc.l3_id=frm->dinfo; + dummybc.nt=stack->nt; bc=&dummybc; } if (bc) { cb_log(4, stack->port, " --> lib: CLEANING UP l3id: %x\n",frm->dinfo); - empty_chan_in_stack(stack,bc->channel); + if (bc->channel>0) + empty_chan_in_stack(stack,bc->channel); empty_bc(bc); + clean_up_bc(bc); + dump_chan_list(stack); - bc->pid = 0; - cb_event(EVENT_CLEANUP, bc, glob_mgr->user_data); + /*bc->pid = 0;*/ + bc->need_disconnect=0; + bc->need_release=0; + bc->need_release_complete=0; + cb_event(EVENT_CLEANUP, bc, glob_mgr->user_data); if (bc->stack_holder) { cb_log(4,stack->port, "REMOVEING Holder\n"); stack_holder_remove( stack, bc); @@ -1335,7 +1575,7 @@ int handle_cr ( iframe_t *frm) } } else { - if (stack->mode == NT_MODE) + if (stack->nt) cb_log(4, stack->port, "BC with dinfo: %x not found.. (prim was %x and addr %x)\n",frm->dinfo, frm->prim, frm->addr); } @@ -1358,10 +1598,10 @@ void misdn_lib_release(struct misdn_bchannel *bc) return; } - if (bc->channel>=0) { + if (bc->channel>0) { empty_chan_in_stack(stack,bc->channel); - empty_bc(bc); } + empty_bc(bc); clean_up_bc(bc); } @@ -1369,7 +1609,7 @@ void misdn_lib_release(struct misdn_bchannel *bc) int misdn_lib_get_port_up (int port) -{ /* Pull Up L1 if we have JOLLY */ +{ /* Pull Up L1 */ struct misdn_stack *stack; for (stack=glob_mgr->stack_list; @@ -1390,37 +1630,75 @@ int misdn_lib_get_port_up (int port) } +int misdn_lib_get_port_down (int port) +{ /* Pull Down L1 */ + struct misdn_stack *stack; + for (stack=glob_mgr->stack_list; + stack; + stack=stack->next) { + if (stack->port == port) { + if (stack->l2link) + misdn_lib_get_l2_down(stack); + misdn_lib_get_l1_down(stack); + return 0; + } + } + return 0; +} + int misdn_lib_send_facility(struct misdn_bchannel *bc, enum facility_type fac, void *data) { - bc->facility=fac; - strcpy(bc->facility_calldeflect_nr,(char*)data); + switch (fac) { + case FACILITY_CALLDEFLECT: + strcpy(bc->out_fac.calldeflect_nr,(char*)data); + break; + default: + cb_log(1,bc?bc->port:0,"We don't handle this facility yet: %d\n",fac); + return 0; + } + + bc->out_fac_type=fac; misdn_lib_send_event(bc,EVENT_FACILITY); return 0; } -int misdn_lib_port_up(int port) +int misdn_lib_port_up(int port, int check) { struct misdn_stack *stack; - + + for (stack=glob_mgr->stack_list; stack; stack=stack->next) { + if ( !stack->ptp && !check) return 1; + if (stack->port == port) { - if (stack->mode == NT_MODE) { - if (stack->l1link) + + if (stack->blocked) { + cb_log(0,port, "Port Blocked:%d L2:%d L1:%d\n", stack->blocked, stack->l2link, stack->l1link); + return -1; + } + + if (stack->ptp ) { + + if (stack->l1link && stack->l2link) { return 1; - else + } else { + cb_log(0,port, "Port Down L2:%d L1:%d\n", + stack->l2link, stack->l1link); return 0; + } } else { - if (stack->l1link) + if ( stack->l1link) return 1; - else + else { + cb_log(0,port, "Port down PMP\n"); return 0; + } } - } } @@ -1433,38 +1711,31 @@ handle_event_nt(void *dat, void *arg) { manager_t *mgr = (manager_t *)dat; msg_t *msg = (msg_t *)arg; -#ifdef MISDNUSER_JOLLY mISDNuser_head_t *hh; -#else - mISDN_head_t *hh; -#endif + int reject=0; + struct misdn_stack *stack=find_stack_by_mgr(mgr); int port; if (!msg || !mgr) return(-EINVAL); -#ifdef MISDNUSER_JOLLY hh=(mISDNuser_head_t*)msg->data; -#else - hh=(mISDN_head_t*)msg->data; -#endif - - port=hh->dinfo & IF_CONTRMASK; - - cb_log(4, stack->port, " --> lib: prim %x dinfo %x port: %d\n",hh->prim, hh->dinfo ,stack->port); - + port=stack->port; + + cb_log(5, stack->port, " --> lib: prim %x dinfo %x\n",hh->prim, hh->dinfo); { switch(hh->prim){ - case CC_RETRIEVE|INDICATION: { iframe_t frm; /* fake te frm to add callref to global callreflist */ frm.dinfo = hh->dinfo; - frm.addr=stack->upper_id; + + frm.addr=stack->upper_id | FLG_MSG_DOWN; + frm.prim = CC_NEW_CR|INDICATION; - if (handle_cr(&frm)< 0) { + if (handle_cr( stack, &frm)< 0) { msg_t *dmsg; cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo); dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1); @@ -1474,11 +1745,16 @@ handle_event_nt(void *dat, void *arg) } struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); - cb_event(EVENT_NEW_BC, bc, glob_mgr->user_data); struct misdn_bchannel *hold_bc=stack_holder_find(stack,bc->l3_id); + if (hold_bc) { + cb_log(4, stack->port, "REMOVEING Holder\n"); stack_holder_remove(stack, hold_bc); + + memcpy(bc,hold_bc,sizeof(struct misdn_bchannel)); + cb_event(EVENT_NEW_BC, hold_bc, bc); + free(hold_bc); } @@ -1486,16 +1762,14 @@ handle_event_nt(void *dat, void *arg) break; - case CC_SETUP|CONFIRM: { struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); int l3id = *((int *)(((u_char *)msg->data)+ mISDNUSER_HEAD_SIZE)); - - cb_log(4, bc?stack->port:0, " --> lib: Event_ind:SETUP CONFIRM [NT] : new L3ID is %x\n",l3id ); - - if (!bc) { cb_log(4, 0, "Bc Not found (after SETUP CONFIRM)\n"); return 0; } + cb_log(4, stack->port, " --> lib: Event_ind:SETUP CONFIRM [NT] : new L3ID is %x\n",l3id ); + if (!bc) { cb_log(4, stack->port, "Bc Not found (after SETUP CONFIRM)\n"); return 0; } + cb_log (2,bc->port,"I IND :CC_SETUP|CONFIRM: old l3id:%x new l3id:%x\n", bc->l3_id, l3id); bc->l3_id=l3id; cb_event(EVENT_NEW_L3ID, bc, glob_mgr->user_data); } @@ -1509,7 +1783,7 @@ handle_event_nt(void *dat, void *arg) frm.addr=stack->upper_id; frm.prim = CC_NEW_CR|INDICATION; - if (handle_cr(&frm)< 0) { + if (handle_cr(stack, &frm)< 0) { msg_t *dmsg; cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo); dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1); @@ -1520,17 +1794,35 @@ handle_event_nt(void *dat, void *arg) } break; - - case CC_CONNECT|INDICATION: + case CC_CONNECT_ACKNOWLEDGE|INDICATION: +#if 0 + { + struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); + if (bc) { + if ( !misdn_cap_is_speech(bc->capability)) { + int ret=setup_bc(bc); + if (ret == -EINVAL){ + cb_log(0,bc->port,"send_event: setup_bc failed\n"); + + } + } + } + } +#endif + break; + case CC_ALERTING|INDICATION: case CC_PROCEEDING|INDICATION: - + case CC_SETUP_ACKNOWLEDGE|INDICATION: + if(!stack->ptp) break; + case CC_CONNECT|INDICATION: { +#if 0 struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); if (!bc) { msg_t *dmsg; - cb_log(0, stack->port,"!!!! We didn't found our bc, dinfo:%x port:%d\n",hh->dinfo, stack->port); + cb_log(0, stack->port,"!!!! We didn't found our bc, dinfo:%x on this port.\n",hh->dinfo); cb_log(0, stack->port, "Releaseing call %x (No free Chan for you..)\n", hh->dinfo); dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1); @@ -1539,8 +1831,12 @@ handle_event_nt(void *dat, void *arg) return 0; } - - setup_bc(bc); + int ret=setup_bc(bc); + if (ret == -EINVAL){ + cb_log(0,bc->port,"handle_event_nt: setup_bc failed\n"); + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); + } +#endif } break; case CC_DISCONNECT|INDICATION: @@ -1548,15 +1844,30 @@ handle_event_nt(void *dat, void *arg) struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); if (!bc) { bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000); - if (bc) { //repair reject bug + if (bc) { /*repair reject bug*/ int myprocid=bc->l3_id&0x0000ffff; hh->dinfo=(hh->dinfo&0xffff0000)|myprocid; - cb_log(4,stack->port,"Repaired reject Bug, new dinfo: %x\n",hh->dinfo); + cb_log(3,stack->port,"Reject dinfo: %x cause:%d\n",hh->dinfo,bc->cause); + reject=1; } } } break; - + + case CC_FACILITY|INDICATION: + { + struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); + if (!bc) { + bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000); + if (bc) { + int myprocid=bc->l3_id&0x0000ffff; + hh->dinfo=(hh->dinfo&0xffff0000)|myprocid; + cb_log(4,bc->port,"Repaired reject Bug, new dinfo: %x\n",hh->dinfo); + } + } + } + break; + case CC_RELEASE_COMPLETE|INDICATION: break; @@ -1574,13 +1885,8 @@ handle_event_nt(void *dat, void *arg) break; case CC_RELEASE|CONFIRM: - { - struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); - cb_log(4, stack->port, " --> RELEASE CONFIRM, sending RELEASE_COMPLETE\n"); - if (bc) misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); - } - hh->prim=CC_RELEASE|INDICATION; - break; + break; + case CC_RELEASE|INDICATION: break; @@ -1590,42 +1896,35 @@ handle_event_nt(void *dat, void *arg) struct misdn_bchannel dummybc; iframe_t frm; /* fake te frm to remove callref from global callreflist */ frm.dinfo = hh->dinfo; - frm.addr=stack->upper_id; + + frm.addr=stack->upper_id | FLG_MSG_DOWN; + frm.prim = CC_RELEASE_CR|INDICATION; cb_log(4, stack->port, " --> Faking Realease_cr for %x\n",frm.addr); /** removing procid **/ - if (!bc) { - cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on port:%d\n", hh->dinfo, stack->port); + cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on this port.\n", hh->dinfo); memset (&dummybc,0,sizeof(dummybc)); dummybc.port=stack->port; dummybc.l3_id=hh->dinfo; + dummybc.nt=stack->nt; bc=&dummybc; } if (bc) { -#ifdef MISDNUSER_JOLLY if ( (bc->l3_id & 0xff00) == 0xff00) { - cb_log(4, stack->port, " --> Removing Process Id:%x on port:%d\n", bc->l3_id&0xff, stack->port); + cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", bc->l3_id&0xff); stack->procids[bc->l3_id&0xff] = 0 ; } -#else - if ( (bc->l3_id & 0xfff0) == 0xfff0) { - cb_log(4, stack->port, " --> Removing Process Id:%x on port:%d\n", bc->l3_id&0xf, stack->port); - stack->procids[bc->l3_id&0xf] = 0 ; - - } - -#endif - } - else cb_log(0, stack->port, "Couldnt find BC so I couldnt remove the Process!!!! this is bad Port:%d\n", stack->port ); + else cb_log(0, stack->port, "Couldnt find BC so I couldnt remove the Process!!!! this is a bad port.\n"); - handle_cr(&frm); + if (handle_cr(stack, &frm)<0) { + } + free_msg(msg); return 0 ; } - break; case CC_NEW_CR|INDICATION: @@ -1634,25 +1933,16 @@ handle_event_nt(void *dat, void *arg) { struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo); int l3id = *((int *)(((u_char *)msg->data)+ mISDNUSER_HEAD_SIZE)); - if (!bc) { cb_log(0, 0, " --> In NEW_CR: didn't found bc ??\n"); return -1;}; -#ifdef MISDNUSER_JOLLY + if (!bc) { cb_log(0, stack->port, " --> In NEW_CR: didn't found bc ??\n"); return -1;}; if (((l3id&0xff00)!=0xff00) && ((bc->l3_id&0xff00)==0xff00)) { - cb_log(4, stack->port, " --> Removing Process Id:%x on port:%d\n", 0xff&bc->l3_id, stack->port); + cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", 0xff&bc->l3_id); stack->procids[bc->l3_id&0xff] = 0 ; } -#else - if (((l3id&0xfff0)!=0xfff0) && ((bc->l3_id&0xfff0)==0xfff0)) { - cb_log(4, stack->port, "Removing Process Id:%x on port:%d\n", 0xf&bc->l3_id, stack->port); - stack->procids[bc->l3_id&0xf] = 0 ; - } - -#endif cb_log(4, stack->port, "lib: Event_ind:CC_NEW_CR : very new L3ID is %x\n",l3id ); bc->l3_id =l3id; cb_event(EVENT_NEW_L3ID, bc, glob_mgr->user_data); - free_msg(msg); return 0; } @@ -1660,24 +1950,44 @@ handle_event_nt(void *dat, void *arg) case DL_ESTABLISH | INDICATION: case DL_ESTABLISH | CONFIRM: { - cb_log(4, stack->port, "%% GOT L2 Activate Info port:%d\n",stack->port); + cb_log(3, stack->port, "%% GOT L2 Activate Info.\n"); + + if (stack->ptp && stack->l2link) { + cb_log(0, stack->port, "%% GOT L2 Activate Info. but we're activated already.. this l2 is faulty, blocking port\n"); + cb_event(EVENT_PORT_ALARM, &stack->bc[0], glob_mgr->user_data); + } + stack->l2link = 1; - + stack->l2upcnt=0; + free_msg(msg); return 0; } break; + case DL_RELEASE | INDICATION: case DL_RELEASE | CONFIRM: { - cb_log(4, stack->port, "%% GOT L2 DeActivate Info port:%d\n",stack->port); - stack->l2link = 0; - - /** Clean the L3 here **/ - if (cb_clearl3_true()) - clear_l3(stack); + if (stack->ptp) { + cb_log(3 , stack->port, "%% GOT L2 DeActivate Info.\n"); + + if (stack->l2upcnt>3) { + cb_log(0 , stack->port, "!!! Could not Get the L2 up after 3 Attemps!!!\n"); + } else { +#if 0 + if (stack->nt) misdn_lib_reinit_nt_stack(stack->port); +#endif + if (stack->l1link) { + misdn_lib_get_l2_up(stack); + stack->l2upcnt++; + } + } + + } else + cb_log(3, stack->port, "%% GOT L2 DeActivate Info.\n"); + stack->l2link = 0; free_msg(msg); return 0; } @@ -1685,8 +1995,6 @@ handle_event_nt(void *dat, void *arg) } } - - { /* Parse Events and fire_up to App. */ struct misdn_bchannel *bc; @@ -1698,21 +2006,75 @@ handle_event_nt(void *dat, void *arg) if (!bc) { - cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on port:%d\n", hh->dinfo, stack->port); + cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x).\n", hh->dinfo); memset (&dummybc,0,sizeof(dummybc)); dummybc.port=stack->port; dummybc.l3_id=hh->dinfo; + dummybc.nt=stack->nt; bc=&dummybc; } if (bc ) { isdn_msg_parse_event(msgs_g,msg,bc, 1); + + switch (event) { + case EVENT_SETUP: + if (bc->channel>0 && bc->channel<255) { + + if (stack->ptp) + set_chan_in_stack(stack, bc->channel); + else + cb_log(0,stack->port," --> PTMP but channel requested\n"); + + } else { + + bc->channel = find_free_chan_in_stack(stack, 0); + if (!bc->channel) { + cb_log(0, stack->port, " No free channel at the moment\n"); + + msg_t *dmsg; + + cb_log(0, stack->port, "Releaseing call %x (No free Chan for you..)\n", hh->dinfo); + dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1); + stack->nst.manager_l3(&stack->nst, dmsg); + free_msg(msg); + return 0; + } + + } +#if 0 + setup_bc(bc); +#endif + + break; + case EVENT_RELEASE: + case EVENT_RELEASE_COMPLETE: + if (bc->channel>0) + empty_chan_in_stack(stack, bc->channel); + int tmpcause=bc->cause; + empty_bc(bc); + bc->cause=tmpcause; + clean_up_bc(bc); + break; + + default: + break; + } if(!isdn_get_info(msgs_g,event,1)) { cb_log(4, stack->port, "Unknown Event Ind: prim %x dinfo %x\n",hh->prim, hh->dinfo); } else { + if (reject) { + switch(bc->cause){ + case 17: + cb_log(1, stack->port, "Siemens Busy reject..\n"); + + break; + default: + break; + } + } cb_event(event, bc, glob_mgr->user_data); } - } else { cb_log(4, stack->port, "No BC found with l3id: prim %x dinfo %x\n",hh->prim, hh->dinfo); @@ -1749,7 +2111,7 @@ int handle_timers(msg_t* msg) stack = stack->next) { itimer_t *it; - if (stack->mode != NT_MODE) continue; + if (!stack->nt) continue; it = stack->nst.tlist; /* find timer */ @@ -1780,129 +2142,221 @@ int handle_timers(msg_t* msg) +void misdn_lib_tone_generator_start(struct misdn_bchannel *bc) +{ + bc->generate_tone=1; +} + +void misdn_lib_tone_generator_stop(struct misdn_bchannel *bc) +{ + bc->generate_tone=0; +} + static int do_tone(struct misdn_bchannel *bc, int len) { - char buf[4096 + mISDN_HEADER_LEN]; - iframe_t *frm= (iframe_t*)buf; - int r; - struct misdn_stack *stack=get_stack_by_bc(bc); + bc->tone_cnt=len; + + if (bc->generate_tone) { + cb_event(EVENT_TONE_GENERATE, bc, glob_mgr->user_data); + + if ( !bc->nojitter ) { + misdn_tx_jitter(bc,len); + } + + return 1; + } - if (bc->tone == TONE_NONE) return 0; + return 0; +} - frm->prim = DL_DATA|REQUEST; - frm->dinfo = 0; - frm->addr = bc->addr | IF_DOWN; - - bc->tone_cnt+=len; - if (bc->tone_cnt < TONE_425_SIZE) return 1; - switch(bc->tone) { - case TONE_DIAL: - { - frm->len = TONE_425_SIZE; - memcpy(&buf[mISDN_HEADER_LEN], tone_425_flip,TONE_425_SIZE); - - r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_1SEC); - if (r<frm->len) { - perror("Error written less than told bytes :(\n"); +void misdn_tx_jitter(struct misdn_bchannel *bc, int len) +{ + char buf[4096 + mISDN_HEADER_LEN]; + char *data=&buf[mISDN_HEADER_LEN]; + iframe_t *txfrm= (iframe_t*)buf; + int jlen, r; + + jlen=cb_jb_empty(bc,data,len); + + if (jlen) { + flip_buf_bits( data, jlen); + + if (jlen < len) { + cb_log(7,bc->port,"Jitterbuffer Underrun.\n"); } - } - break; - case TONE_ALERTING: - bc->tone_cnt2++; - - if (bc->tone_cnt2 <= TONE_ALERT_CNT) { - frm->len = TONE_425_SIZE; - memcpy(&buf[mISDN_HEADER_LEN], tone_425_flip,TONE_425_SIZE); - r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_1SEC); - if (r<frm->len) { - perror("Error written less than told bytes :(\n"); - } - } else if (bc->tone_cnt2 <= (TONE_ALERT_SILENCE_CNT)) { - frm->len = TONE_SILENCE_SIZE; - memcpy(&buf[mISDN_HEADER_LEN], tone_silence_flip ,TONE_SILENCE_SIZE); - r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_1SEC); - } else { - bc->tone_cnt2=-1; + txfrm->prim = DL_DATA|REQUEST; + + txfrm->dinfo = 0; + + txfrm->addr = bc->addr|FLG_MSG_DOWN; /* | IF_DOWN; */ + + txfrm->len =jlen; + cb_log(9, bc->port, "Transmitting %d samples 2 misdn\n", txfrm->len); + + r=mISDN_write( glob_mgr->midev, buf, txfrm->len + mISDN_HEADER_LEN, 8000 ); + } else { +#define MISDN_GEN_SILENCE +#ifdef MISDN_GEN_SILENCE + int cnt=len/TONE_SILENCE_SIZE; + int rest=len%TONE_SILENCE_SIZE; + int i; + + for (i=0; i<cnt; i++) { + memcpy(data, tone_silence_flip, TONE_SILENCE_SIZE ); + data +=TONE_SILENCE_SIZE; } - break; - case TONE_BUSY: - bc->tone_cnt2++; - - if (bc->tone_cnt2 <= TONE_BUSY_CNT) { - frm->len = TONE_425_SIZE; - memcpy(&buf[mISDN_HEADER_LEN], tone_425_flip,TONE_425_SIZE); - r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_1SEC); - if (r<frm->len) { - perror("Error written less than told bytes :(\n"); - } - } else if (bc->tone_cnt2 <= (TONE_BUSY_SILENCE_CNT)) { - frm->len = TONE_SILENCE_SIZE; - memcpy(&buf[mISDN_HEADER_LEN], tone_silence_flip ,TONE_SILENCE_SIZE); - r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_1SEC); - } else { - bc->tone_cnt2=-1; + + if (rest) { + memcpy(data, tone_silence_flip, rest); } - break; - case TONE_FILE: - break; - case TONE_NONE: - return 0; + + txfrm->prim = DL_DATA|REQUEST; + + txfrm->dinfo = 0; + + txfrm->addr = bc->addr|FLG_MSG_DOWN; /* | IF_DOWN; */ + + txfrm->len =len; + cb_log(9, bc->port, "Transmitting %d samples 2 misdn\n", txfrm->len); + + r=mISDN_write( glob_mgr->midev, buf, txfrm->len + mISDN_HEADER_LEN, 8000 ); +#endif } - - bc->tone_cnt -= TONE_425_SIZE ; - return 1; } - - int handle_bchan(msg_t *msg) { iframe_t *frm= (iframe_t*)msg->data; - struct misdn_bchannel *bc; + + + struct misdn_bchannel *bc=find_bc_by_addr(frm->addr); - bc=find_bc_by_addr(frm->addr); + if (!bc) { + cb_log(1,0,"handle_bchan: BC not found for prim:%x with addr:%x dinfo:%x\n", frm->prim, frm->addr, frm->dinfo); + return 0 ; + } - if (!bc) return 0 ; - struct misdn_stack *stack=get_stack_by_bc(bc); - - if (!stack) return 0; + + if (!stack) { + cb_log(0, bc->port,"handle_bchan: STACK not found for prim:%x with addr:%x dinfo:%x\n", frm->prim, frm->addr, frm->dinfo); + return 0; + } switch (frm->prim) { + + case MGR_SETSTACK| CONFIRM: + cb_log(3, stack->port, "BCHAN: MGR_SETSTACK|CONFIRM pid:%d\n",bc->pid); + break; + + case MGR_SETSTACK| INDICATION: + cb_log(3, stack->port, "BCHAN: MGR_SETSTACK|IND pid:%d\n",bc->pid); + break; +#if 0 + AGAIN: + bc->addr = mISDN_get_layerid(stack->midev, bc->b_stid, bc->layer); + if (!bc->addr) { + + if (errno == EAGAIN) { + usleep(1000); + goto AGAIN; + } + + cb_log(0,stack->port,"$$$ Get Layer (%d) Id Error: %s\n",bc->layer,strerror(errno)); + + /* we kill the channel later, when we received some + data. */ + bc->addr= frm->addr; + } else if ( bc->addr < 0) { + cb_log(0, stack->port,"$$$ bc->addr <0 Error:%s\n",strerror(errno)); + bc->addr=0; + } + + cb_log(4, stack->port," --> Got Adr %x\n", bc->addr); + + free_msg(msg); + + + switch(bc->bc_state) { + case BCHAN_SETUP: + bc_state_change(bc,BCHAN_SETUPED); + break; + + case BCHAN_CLEAN_REQUEST: + default: + cb_log(0, stack->port," --> STATE WASN'T SETUP (but %s) in SETSTACK|IND pid:%d\n",bc_state2str(bc->bc_state), bc->pid); + clean_up_bc(bc); + } + return 1; +#endif + + case MGR_DELLAYER| INDICATION: + cb_log(3, stack->port, "BCHAN: MGR_DELLAYER|IND pid:%d\n",bc->pid); + break; + + case MGR_DELLAYER| CONFIRM: + cb_log(3, stack->port, "BCHAN: MGR_DELLAYER|CNF pid:%d\n",bc->pid); + + bc->pid=0; + bc->addr=0; + + free_msg(msg); + return 1; + case PH_ACTIVATE | INDICATION: case DL_ESTABLISH | INDICATION: - cb_log(4, stack->port, "BCHAN: ACT Ind\n"); + cb_log(3, stack->port, "BCHAN: ACT Ind pid:%d\n", bc->pid); + free_msg(msg); return 1; case PH_ACTIVATE | CONFIRM: case DL_ESTABLISH | CONFIRM: - cb_log(4, stack->port, "BCHAN: bchan ACT Confirm\n"); + + cb_log(3, stack->port, "BCHAN: bchan ACT Confirm pid:%d\n",bc->pid); free_msg(msg); - + return 1; + + case DL_ESTABLISH | REQUEST: + { + char buf[128]; + mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_ESTABLISH | CONFIRM, 0,0, NULL, TIMEOUT_1SEC); + } + free_msg(msg); + return 1; + + case DL_RELEASE|REQUEST: + { + char buf[128]; + mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_RELEASE| CONFIRM, 0,0, NULL, TIMEOUT_1SEC); + } + free_msg(msg); + return 1; case PH_DEACTIVATE | INDICATION: case DL_RELEASE | INDICATION: - cb_log (4, stack->port, "BCHAN: DeACT Ind\n"); + cb_log (3, stack->port, "BCHAN: DeACT Ind pid:%d\n",bc->pid); + free_msg(msg); return 1; case PH_DEACTIVATE | CONFIRM: case DL_RELEASE | CONFIRM: - cb_log(4, stack->port, "BCHAN: DeACT Conf\n"); + cb_log(3, stack->port, "BCHAN: DeACT Conf pid:%d\n",bc->pid); + free_msg(msg); return 1; case PH_CONTROL|INDICATION: { - unsigned long cont = *((unsigned long *)&frm->data.p); + unsigned int cont = *((unsigned int *)&frm->data.p); - cb_log(4, stack->port, "PH_CONTROL: port:%d channel:%d oad%d:%s dad%d:%s \n", stack->port, bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + cb_log(4, stack->port, "PH_CONTROL: channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); if ((cont&~DTMF_TONE_MASK) == DTMF_TONE_VAL) { int dtmf = cont & DTMF_TONE_MASK; @@ -1925,7 +2379,16 @@ int handle_bchan(msg_t *msg) } } break; - + + case PH_DATA|REQUEST: + case DL_DATA|REQUEST: + cb_log(0, stack->port, "DL_DATA REQUEST \n"); + do_tone(bc, 64); + + free_msg(msg); + return 1; + + case PH_DATA|INDICATION: case DL_DATA|INDICATION: { @@ -1935,44 +2398,63 @@ int handle_bchan(msg_t *msg) /** Anyway flip the bufbits **/ if ( misdn_cap_is_speech(bc->capability) ) flip_buf_bits(bc->bframe, bc->bframe_len); - + + + if (!bc->bframe_len) { + cb_log(2, stack->port, "DL_DATA INDICATION bc->addr:%x frm->addr:%x\n", bc->addr, frm->addr); + free_msg(msg); + return 1; + } + + if ( (bc->addr&STACK_ID_MASK) != (frm->addr&STACK_ID_MASK) ) { + cb_log(2, stack->port, "DL_DATA INDICATION bc->addr:%x frm->addr:%x\n", bc->addr, frm->addr); + free_msg(msg); + return 1; + } #if MISDN_DEBUG cb_log(0, stack->port, "DL_DATA INDICATION Len %d\n", frm->len); + #endif - if (bc->active && frm->len > 0) { - if ( !do_tone(bc, frm->len) ) { + if ( (bc->bc_state == BCHAN_ACTIVATED) && frm->len > 0) { + int t; + +#ifdef MISDN_B_DEBUG + cb_log(0,bc->port,"do_tone START\n"); +#endif + t=do_tone(bc,frm->len); + +#ifdef MISDN_B_DEBUG + cb_log(0,bc->port,"do_tone STOP (%d)\n",t); +#endif + if ( !t ) { if ( misdn_cap_is_speech(bc->capability)) { if ( !bc->nojitter ) { - char buf[4096 + mISDN_HEADER_LEN]; - iframe_t *txfrm= (iframe_t*)buf; - int len, r; - - len = ibuf_usedcount(bc->misdnbuf); - - if (len < frm->len) { - /** send nothing - * till we are synced - **/ - } else { - - txfrm->prim = DL_DATA|REQUEST; - txfrm->dinfo = 0; - txfrm->addr = bc->addr; /* | IF_DOWN; */ - txfrm->len = frm->len; - ibuf_memcpy_r(&buf[mISDN_HEADER_LEN], bc->misdnbuf,frm->len); - cb_log(9, stack->port, "Transmitting %d samples 2 misdn\n", txfrm->len); - - r=mISDN_write(stack->midev, buf, txfrm->len + mISDN_HEADER_LEN, 8000 ); - - } - +#ifdef MISDN_B_DEBUG + cb_log(0,bc->port,"tx_jitter START\n"); +#endif + misdn_tx_jitter(bc,frm->len); +#ifdef MISDN_B_DEBUG + cb_log(0,bc->port,"tx_jitter STOP\n"); +#endif } } + +#ifdef MISDN_B_DEBUG + cb_log(0,bc->port,"EVENT_B_DATA START\n"); +#endif + + int i=cb_event( EVENT_BCHAN_DATA, bc, glob_mgr->user_data); +#ifdef MISDN_B_DEBUG + cb_log(0,bc->port,"EVENT_B_DATA STOP\n"); +#endif - cb_event( EVENT_BCHAN_DATA, bc, glob_mgr->user_data); + if (i<0) { + cb_log(10,stack->port,"cb_event returned <0\n"); + /*clean_up_bc(bc);*/ + } } } free_msg(msg); @@ -1980,22 +2462,27 @@ int handle_bchan(msg_t *msg) } + case PH_CONTROL | CONFIRM: + cb_log(4, stack->port, "PH_CONTROL|CNF bc->addr:%x\n", frm->addr); + free_msg(msg); + return 1; + case PH_DATA | CONFIRM: case DL_DATA|CONFIRM: #if MISDN_DEBUG + cb_log(0, stack->port, "Data confirmed\n"); + #endif free_msg(msg); + return 1; - break; case DL_DATA|RESPONSE: #if MISDN_DEBUG cb_log(0, stack->port, "Data response\n"); + #endif break; - - case DL_DATA | REQUEST: - break; } return 0; @@ -2008,30 +2495,32 @@ int handle_frm_nt(msg_t *msg) iframe_t *frm= (iframe_t*)msg->data; struct misdn_stack *stack; int err=0; + + stack=find_stack_by_addr( frm->addr ); + + - stack=find_stack_by_addr((frm->addr & IF_ADDRMASK ) ); - - if (!stack || stack->mode != NT_MODE) { + if (!stack || !stack->nt) { return 0; } - + if ((err=stack->nst.l1_l2(&stack->nst,msg))) { if (nt_err_cnt > 0 ) { if (nt_err_cnt < 100) { nt_err_cnt++; - cb_log(0, stack->port, "NT Stack sends us error: %d port:%d\n", err,stack->port); + cb_log(0, stack->port, "NT Stack sends us error: %d \n", err); } else if (nt_err_cnt < 105){ - cb_log(0, stack->port, "NT Stack sends us error: %d port:%d over 100 times, so I'll stop this message\n", err,stack->port); + cb_log(0, stack->port, "NT Stack sends us error: %d over 100 times, so I'll stop this message\n", err); nt_err_cnt = - 1; } } free_msg(msg); return 1; - + } - + return 1; } @@ -2039,16 +2528,24 @@ int handle_frm_nt(msg_t *msg) int handle_frm(msg_t *msg) { iframe_t *frm = (iframe_t*) msg->data; - struct misdn_stack *stack=find_stack_by_addr(frm->addr & IF_ADDRMASK); - - if (!stack || stack->mode != TE_MODE) { + + struct misdn_stack *stack=find_stack_by_addr(frm->addr); + + if (!stack || stack->nt) { return 0; } + + cb_log(4,stack?stack->port:0,"handle_frm: frm->addr:%x frm->prim:%x\n",frm->addr,frm->prim); { struct misdn_bchannel *bc; + int ret=handle_cr(stack, frm); + + if (ret<0) { + cb_log(3,stack?stack->port:0,"handle_frm: handle_cr <0 prim:%x addr:%x\n", frm->prim, frm->addr); + } - if(handle_cr(frm)) { + if(ret) { free_msg(msg); return 1; } @@ -2060,7 +2557,7 @@ int handle_frm(msg_t *msg) enum event_response_e response=RESPONSE_OK; isdn_msg_parse_event(msgs_g,msg,bc, 0); - + /** Preprocess some Events **/ handle_event(bc, event, frm); /* shoot up event to App: */ @@ -2074,35 +2571,47 @@ int handle_frm(msg_t *msg) if (event == EVENT_SETUP) { switch (response) { case RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE: - cb_log(0, stack->port, "TOTALY IGNORING SETUP: port:%d\n", frm->addr&IF_CONTRMASK); + + cb_log(0, stack->port, "TOTALY IGNORING SETUP \n"); + break; case RESPONSE_IGNORE_SETUP: /* I think we should send CC_RELEASE_CR, but am not sure*/ - empty_chan_in_stack(stack, bc->channel); + + bc->out_cause=16; + misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); + if (bc->channel>0) + empty_chan_in_stack(stack, bc->channel); empty_bc(bc); - - cb_log(0, stack->port, "GOT IGNORE SETUP: port:%d\n", frm->addr&IF_CONTRMASK); + bc_state_change(bc,BCHAN_CLEANED); + + cb_log(0, stack->port, "GOT IGNORE SETUP\n"); + + break; case RESPONSE_OK: - cb_log(4, stack->port, "GOT SETUP OK: port:%d\n", frm->addr&IF_CONTRMASK); + cb_log(4, stack->port, "GOT SETUP OK\n"); + + break; default: break; } } - - cb_log(5, stack->port, "Freeing Msg on prim:%x port:%d\n",frm->prim, frm->addr&IF_CONTRMASK); + + cb_log(5, stack->port, "Freeing Msg on prim:%x \n",frm->prim); + + free_msg(msg); return 1; #endif } else { - cb_log(0, stack->port, "NO BC FOR STACK: port:%d\n", frm->addr&IF_CONTRMASK); + cb_log(0, stack->port, "NO BC FOR STACK\n"); } - } - cb_log(4, stack->port, "TE_FRM_HANDLER: Returning 0 on prim:%x port:%d\n",frm->prim, frm->addr&IF_CONTRMASK); - + + cb_log(4, stack->port, "TE_FRM_HANDLER: Returning 0 on prim:%x \n",frm->prim); return 0; } @@ -2110,21 +2619,24 @@ int handle_frm(msg_t *msg) int handle_l1(msg_t *msg) { iframe_t *frm = (iframe_t*) msg->data; - struct misdn_stack *stack = find_stack_by_port(frm->addr & IF_CONTRMASK); + struct misdn_stack *stack = find_stack_by_addr(frm->addr); int i ; if (!stack) return 0 ; - + switch (frm->prim) { case PH_ACTIVATE | CONFIRM: case PH_ACTIVATE | INDICATION: - cb_log (1, stack->port, "L1: PH L1Link Up! port:%d\n",stack->port); + cb_log (3, stack->port, "L1: PH L1Link Up!\n"); stack->l1link=1; - if (stack->mode==NT_MODE) { + if (stack->nt) { if (stack->nst.l1_l2(&stack->nst, msg)) free_msg(msg); + + if (stack->ptp) + misdn_lib_get_l2_up(stack); } else { free_msg(msg); } @@ -2137,30 +2649,37 @@ int handle_l1(msg_t *msg) } } + return 1; + + case PH_ACTIVATE | REQUEST: + free_msg(msg); + cb_log(3,stack->port,"L1: PH_ACTIVATE|REQUEST \n"); + return 1; + case PH_DEACTIVATE | REQUEST: + free_msg(msg); + cb_log(3,stack->port,"L1: PH_DEACTIVATE|REQUEST \n"); return 1; + case PH_DEACTIVATE | CONFIRM: case PH_DEACTIVATE | INDICATION: - cb_log (1, stack->port, "L1: PH L1Link Down! port:%d\n",stack->port); + cb_log (3, stack->port, "L1: PH L1Link Down! \n"); for (i=0; i<stack->b_num; i++) { if (global_state == MISDN_INITIALIZED) { cb_event(EVENT_CLEANUP, &stack->bc[i], glob_mgr->user_data); } - } - if (stack->mode==NT_MODE) { + if (stack->nt) { if (stack->nst.l1_l2(&stack->nst, msg)) free_msg(msg); - } else { free_msg(msg); } stack->l1link=0; stack->l2link=0; - return 1; } @@ -2170,39 +2689,30 @@ int handle_l1(msg_t *msg) int handle_l2(msg_t *msg) { iframe_t *frm = (iframe_t*) msg->data; - struct misdn_stack *stack = find_stack_by_addr(frm->addr & IF_ADDRMASK); - if (!stack) return 0 ; - + struct misdn_stack *stack = find_stack_by_addr(frm->addr); + + if (!stack) { + return 0 ; + } + switch(frm->prim) { -#ifdef DL_STATUS - case DL_STATUS | INDICATION: - case DL_STATUS | CONFIRM: - cb_log (3, stack->port, "L2: DL_STATUS! port:%d\n", stack->port); + case DL_ESTABLISH | REQUEST: + cb_log(1,stack->port,"DL_ESTABLISH|REQUEST \n"); + return 1; + case DL_RELEASE | REQUEST: + cb_log(1,stack->port,"DL_RELEASE|REQUEST \n"); + return 1; - switch (frm->dinfo) { - case SDL_ESTAB: - cb_log (4, stack->port, " --> SDL_ESTAB port:%d\n", stack->port); - stack->l1link=1; - goto dl_estab; - case SDL_REL: - cb_log (4, stack->port, " --> SDL_REL port:%d\n", stack->port); - stack->l1link=0; - misdn_lib_get_l2_up(stack); - goto dl_rel; - } - break; -#endif - - case DL_ESTABLISH | INDICATION: case DL_ESTABLISH | CONFIRM: -#ifdef DL_STATUS - dl_estab: -#endif { - cb_log (3, stack->port, "L2: L2Link Up! port:%d\n", stack->port); + cb_log (3, stack->port, "L2: L2Link Up! \n"); + if (stack->ptp && stack->l2link) { + cb_log (-1, stack->port, "L2: L2Link Up! but it's already UP.. must be faulty, blocking port\n"); + cb_event(EVENT_PORT_ALARM, &stack->bc[0], glob_mgr->user_data); + } stack->l2link=1; free_msg(msg); return 1; @@ -2211,11 +2721,8 @@ int handle_l2(msg_t *msg) case DL_RELEASE | INDICATION: case DL_RELEASE | CONFIRM: -#ifdef DL_STATUS - dl_rel: -#endif { - cb_log (3, stack->port, "L2: L2Link Down! port:%d\n", stack->port); + cb_log (3, stack->port, "L2: L2Link Down! \n"); stack->l2link=0; free_msg(msg); @@ -2226,16 +2733,84 @@ int handle_l2(msg_t *msg) return 0; } - int handle_mgmt(msg_t *msg) { iframe_t *frm = (iframe_t*) msg->data; - - if ( (frm->prim & 0x0f0000) == 0x0f0000) { - cb_log(5, 0, "$$$ MGMT FRAME: prim %x addr %x dinfo %x\n",frm->prim, frm->addr, frm->dinfo) ; + + if ( (frm->addr == 0) && (frm->prim == (MGR_DELLAYER|CONFIRM)) ) { + cb_log(2, 0, "MGMT: DELLAYER|CONFIRM Addr: 0 !\n") ; free_msg(msg); return 1; } + + struct misdn_stack * stack=find_stack_by_addr(frm->addr); + + if (!stack) { + if (frm->prim == (MGR_DELLAYER|CONFIRM)) { + cb_log(2, 0, "MGMT: DELLAYER|CONFIRM Addr: %x !\n", + frm->addr) ; + free_msg(msg); + return 1; + } + + return 0; + } + + switch(frm->prim) { + case MGR_SHORTSTATUS | INDICATION: + case MGR_SHORTSTATUS | CONFIRM: + cb_log(5, stack->port, "MGMT: Short status dinfo %x\n",frm->dinfo); + switch (frm->dinfo) { + case SSTATUS_L1_ACTIVATED: + cb_log(3, stack->port, "MGMT: SSTATUS: L1_ACTIVATED \n"); + stack->l1link=1; + break; + + case SSTATUS_L1_DEACTIVATED: + cb_log(3, stack->port, "MGMT: SSTATUS: L1_DEACTIVATED \n"); + /*reopen L1 if down*/ + if (stack->l1link==2) + stack->l1link--; + else + stack->l1link=0; + + clear_l3(stack); + + break; + + case SSTATUS_L2_ESTABLISHED: + cb_log(3, stack->port, "MGMT: SSTATUS: L2_ESTABLISH \n"); + stack->l2link=1; + if ( !stack->ptp && !stack->nt ) + stack->l1link=2; + break; + + case SSTATUS_L2_RELEASED: + cb_log(3, stack->port, "MGMT: SSTATUS: L2_RELEASED \n"); + stack->l2link=0; + break; + } + + free_msg(msg); + return 1; + + case MGR_SETSTACK | INDICATION: + cb_log(4, stack->port, "MGMT: SETSTACK|IND dinfo %x\n",frm->dinfo); + free_msg(msg); + return 1; + case MGR_DELLAYER | CONFIRM: + cb_log(4, stack->port, "MGMT: DELLAYER|CNF dinfo %x\n",frm->dinfo) ; + free_msg(msg); + return 1; + + } + + /* + if ( (frm->prim & 0x0f0000) == 0x0f0000) { + cb_log(5, 0, "$$$ MGMT FRAME: prim %x addr %x dinfo %x\n",frm->prim, frm->addr, frm->dinfo) ; + free_msg(msg); + return 1; + } */ return 0; } @@ -2245,33 +2820,51 @@ msg_t *fetch_msg(int midev) { msg_t *msg=alloc_msg(MAX_MSG_SIZE); int r; - fd_set rdfs; +/* fd_set rdfs; */ if (!msg) { cb_log(0, 0, "fetch_msg: alloc msg failed !!"); return NULL; } - + +#if 0 FD_ZERO(&rdfs); FD_SET(midev,&rdfs); mISDN_select(FD_SETSIZE, &rdfs, NULL, NULL, NULL); + //select(FD_SETSIZE, &rdfs, NULL, NULL, NULL); if (FD_ISSET(midev, &rdfs)) { - - r=mISDN_read(midev,msg->data,MAX_MSG_SIZE,0); +#endif + + AGAIN: + r=mISDN_read(midev,msg->data,MAX_MSG_SIZE, TIMEOUT_10SEC); msg->len=r; if (r==0) { free_msg(msg); /* danger, cauz usualy freeing in main_loop */ - printf ("Got empty Msg?\n"); + cb_log(6,0,"Got empty Msg..\n"); return NULL; } + if (r<0) { + if (errno == EAGAIN) { + /*we wait for mISDN here*/ + cb_log(4,0,"mISDN_read wants us to wait\n"); + usleep(5000); + goto AGAIN; + } + + cb_log(0,0,"mISDN_read returned :%d error:%s (%d)\n",r,strerror(errno),errno); + } + return msg; + +#if 0 } else { printf ("Select timeout\n"); } +#endif return NULL; } @@ -2282,9 +2875,7 @@ static void misdn_lib_isdn_event_catcher(void *arg) struct misdn_lib *mgr = arg; int zero_frm=0 , fff_frm=0 ; int midev= mgr->midev; - int port; - - //cb_log(5, 0, "In event_catcher thread\n"); + int port=0; while (1) { msg_t *msg = fetch_msg(midev); @@ -2294,7 +2885,6 @@ static void misdn_lib_isdn_event_catcher(void *arg) if (!msg) continue; frm = (iframe_t*) msg->data; - port = frm->addr&IF_CONTRMASK; /** When we make a call from NT2Ast we get this frames **/ if (frm->len == 0 && frm->addr == 0 && frm->dinfo == 0 && frm->prim == 0 ) { @@ -2397,41 +2987,92 @@ struct misdn_bchannel *manager_find_bc_holded(struct misdn_bchannel* bc) +void prepare_bc(struct misdn_bchannel*bc, int channel) +{ + bc->channel = channel; + bc->channel_preselected = channel?1:0; + bc->in_use = 1; + bc->need_disconnect=1; + bc->need_release=1; + bc->need_release_complete=1; + bc->cause=16; + + if (++mypid>5000) mypid=1; + bc->pid=mypid; + +#if 0 + bc->addr=0; + bc->b_stid=0; + bc->layer_id=0; +#endif +} + struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel) { struct misdn_stack *stack; int i; - if (channel < 0 || channel > MAX_BCHANS) + if (channel < 0 || channel > MAX_BCHANS) { + cb_log(0,port,"Requested channel out of bounds (%d)\n",channel); return NULL; + } for (stack=glob_mgr->stack_list; stack; stack=stack->next) { if (stack->port == port) { + if (stack->blocked) { + cb_log(0,port,"Port is blocked\n"); + return NULL; + } + if (channel > 0) { if (channel <= stack->b_num) { for (i = 0; i < stack->b_num; i++) { if (stack->bc[i].in_use && stack->bc[i].channel == channel) { + cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port); return NULL; } } - } else + } else { + cb_log(0,port,"Requested channel:%d is out of bounds on port:%d\n",channel, port); return NULL; + } } for (i = 0; i < stack->b_num; i++) { if (!stack->bc[i].in_use) { - stack->bc[i].channel = channel; - stack->bc[i].channel_preselected = channel?1:0; - stack->bc[i].in_use = 1; + prepare_bc(&stack->bc[i], channel); return &stack->bc[i]; } } + + cb_log(1,port,"There is no free channel on port (%d)\n",port); return NULL; } } + + cb_log(0,port,"Port is not configured (%d)\n",port); return NULL; } + +char *fac2str (enum facility_type type) { + struct arr_el { + enum facility_type p; + char *s ; + } arr[] = { + { FACILITY_NONE, "FAC_NONE" }, + { FACILITY_CALLDEFLECT, "FAC_CALLDEFLECT"}, + { FACILITY_CENTREX, "FAC_CENTREX"} + }; + + int i; + + for (i=0; i < sizeof(arr)/sizeof( struct arr_el) ; i ++) + if ( arr[i].p==type) return arr[i].s; + + return "FAC_UNKNOWN"; +} + void misdn_lib_log_ies(struct misdn_bchannel *bc) { if (!bc) return; @@ -2439,96 +3080,120 @@ void misdn_lib_log_ies(struct misdn_bchannel *bc) struct misdn_stack *stack=get_stack_by_bc(bc); if (!stack) return; - - cb_log(2, stack->port, " --> mode:%s cause:%d ocause:%d rad:%s\n", stack->mode==NT_MODE?"NT":"TE", bc->cause, bc->out_cause, bc->rad); + + cb_log(2, stack->port, " --> channel:%d mode:%s cause:%d ocause:%d rad:%s cad:%s\n", bc->channel, stack->nt?"NT":"TE", bc->cause, bc->out_cause, bc->rad, bc->cad); cb_log(2, stack->port, - " --> info_dad:%s onumplan:%c dnumplan:%c rnumplan:%c\n", + " --> info_dad:%s onumplan:%c dnumplan:%c rnumplan:%c cpnnumplan:%c\n", bc->info_dad, bc->onumplan>=0?'0'+bc->onumplan:' ', bc->dnumplan>=0?'0'+bc->dnumplan:' ', - bc->rnumplan>=0?'0'+bc->rnumplan:' ' + bc->rnumplan>=0?'0'+bc->rnumplan:' ', + bc->cpnnumplan>=0?'0'+bc->cpnnumplan:' ' ); - cb_log(2, stack->port, " --> channel:%d caps:%s pi:%x keypad:%s\n", bc->channel, bearer2str(bc->capability),bc->progress_indicator, bc->keypad); - - cb_log(3, stack->port, " --> urate:%d rate:%d mode:%d user1:%d\n", bc->urate, bc->rate, bc->mode,bc->user1); + cb_log(3, stack->port, " --> caps:%s pi:%x keypad:%s sending_complete:%d\n", bearer2str(bc->capability),bc->progress_indicator, bc->keypad, bc->sending_complete); + cb_log(4, stack->port, " --> screen:%d --> pres:%d\n", + bc->screen, bc->pres); - cb_log(3, stack->port, " --> pid:%d addr:%x l3id:%x\n", bc->pid, bc->addr, bc->l3_id); + cb_log(4, stack->port, " --> addr:%x l3id:%x b_stid:%x layer_id:%x\n", bc->addr, bc->l3_id, bc->b_stid, bc->layer_id); + + cb_log(4, stack->port, " --> facility:%s out_facility:%s\n",fac2str(bc->fac_type),fac2str(bc->out_fac_type)); - cb_log(4, stack->port, " --> bc:%x h:%d sh:%d\n", bc, bc->holded, bc->stack_holder); + cb_log(5, stack->port, " --> urate:%d rate:%d mode:%d user1:%d\n", bc->urate, bc->rate, bc->mode,bc->user1); + + cb_log(5, stack->port, " --> bc:%x h:%d sh:%d\n", bc, bc->holded, bc->stack_holder); } int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) { msg_t *msg; int err = -1 ; + int ret=0; if (!bc) goto ERR; struct misdn_stack *stack=get_stack_by_bc(bc); - if ( stack->mode == NT_MODE && !stack->l1link) { + if (!stack) { + cb_log(0,bc->port,"SENDEVENT: no Stack for event:%s oad:%s dad:%s \n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad); + return -1; + } + + cb_log(6,stack->port,"SENDEVENT: stack->nt:%d stack->uperid:%x\n",stack->nt, stack->upper_id); + + if ( stack->nt && !stack->l1link) { /** Queue Event **/ bc->evq=event; cb_log(1, stack->port, "Queueing Event %s because L1 is down (btw. Activating L1)\n", isdn_get_info(msgs_g, event, 0)); - { /* Pull Up L1 */ - iframe_t act; - act.prim = PH_ACTIVATE | REQUEST; - act.addr = (stack->upper_id & IF_ADDRMASK) | IF_DOWN ; - act.dinfo = 0; - act.len = 0; - mISDN_write(glob_mgr->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC); - } - + misdn_lib_get_l1_up(stack); return 0; } - cb_log(1, stack->port, "I SEND:%s oad:%s dad:%s port:%d\n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad, stack->port); + cb_log(1, stack->port, "I SEND:%s oad:%s dad:%s pid:%d\n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad, bc->pid); + cb_log(1, stack->port, " --> bc_state:%s\n",bc_state2str(bc->bc_state)); misdn_lib_log_ies(bc); switch (event) { case EVENT_SETUP: if (create_process(glob_mgr->midev, bc)<0) { cb_log(0, stack->port, " No free channel at the moment @ send_event\n"); + err=-ENOCHAN; goto ERR; } +#if 0 + if (stack->nt) { + ret=setup_bc(bc); + if (ret == -EINVAL) { + cb_log(0,bc->port,"send_event: setup_bc failed\n"); + } + } +#endif break; - case EVENT_CONNECT: case EVENT_PROGRESS: case EVENT_ALERTING: case EVENT_PROCEEDING: case EVENT_SETUP_ACKNOWLEDGE: + if (!bc->nt && !stack->ptp) break; + + case EVENT_CONNECT: case EVENT_RETRIEVE_ACKNOWLEDGE: + + bc->holded=0; - if (stack->mode == NT_MODE) { + if (stack->nt) { if (bc->channel <=0 ) { /* else we have the channel already */ bc->channel = find_free_chan_in_stack(stack, 0); if (!bc->channel) { cb_log(0, stack->port, " No free channel at the moment\n"); + err=-ENOCHAN; goto ERR; } } /* Its that i generate channels */ } + + ret=setup_bc(bc); + if (ret == -EINVAL) { + cb_log(0,bc->port,"send_event: setup_bc failed\n"); + } + + cb_log(0,bc->port,"After SETUP BC\n"); + - setup_bc(bc); - - - if ( event == EVENT_CONNECT ) { - if ( *bc->crypt_key ) { - cb_log(4, stack->port, " --> ENABLING BLOWFISH port:%d channel:%d oad%d:%s dad%d:%s \n", stack->port, bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + if (misdn_cap_is_speech(bc->capability)) { + if ((event==EVENT_CONNECT)||(event==EVENT_RETRIEVE_ACKNOWLEDGE)) { + if ( *bc->crypt_key ) { + cb_log(4, stack->port, " --> ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); + + manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); + } - manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); - } - - if ( misdn_cap_is_speech(bc->capability)) { if (!bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0); - - if (bc->ec_enable) manager_ec_enable(bc); + manager_ec_enable(bc); if (bc->txgain != 0) { cb_log(4, stack->port, "--> Changing txgain to %d\n", bc->txgain); @@ -2541,50 +3206,78 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) } } } - - if (event == EVENT_RETRIEVE_ACKNOWLEDGE) { - manager_bchannel_activate(bc); - } - break; - + case EVENT_HOLD_ACKNOWLEDGE: { struct misdn_bchannel *holded_bc=malloc(sizeof(struct misdn_bchannel)); - memcpy(holded_bc,bc,sizeof(struct misdn_bchannel)); - holded_bc->holded=1; stack_holder_add(stack,holded_bc); - if (stack->mode == NT_MODE) { - empty_chan_in_stack(stack,bc->channel); + if (stack->nt) { + if (bc->bc_state == BCHAN_BRIDGED) { + misdn_split_conf(bc,bc->conf_id); + misdn_split_conf(bc->holded_bc,bc->holded_bc->conf_id); + } + + if (bc->channel>0) + empty_chan_in_stack(stack,bc->channel); empty_bc(bc); clean_up_bc(bc); } /** we set it up later at RETRIEVE_ACK again.**/ - holded_bc->upset=0; - holded_bc->active=0; + /*holded_bc->upset=0; + holded_bc->active=0;*/ + bc_state_change(holded_bc,BCHAN_CLEANED); - cb_event( EVENT_NEW_BC, holded_bc, glob_mgr->user_data); + cb_event( EVENT_NEW_BC, bc, holded_bc); } break; - + + /* finishing the channel eh ? */ + case EVENT_DISCONNECT: + if (!bc->need_disconnect) { + cb_log(0,bc->port," --> we have already send Disconnect\n"); + return -1; + } + + bc->need_disconnect=0; + break; case EVENT_RELEASE: + if (!bc->need_release) { + cb_log(0,bc->port," --> we have already send Release\n"); + return -1; + } + bc->need_disconnect=0; + bc->need_release=0; break; - case EVENT_RELEASE_COMPLETE: - empty_chan_in_stack(stack,bc->channel); - empty_bc(bc); - clean_up_bc(bc); + if (!bc->need_release_complete) { + cb_log(0,bc->port," --> we have already send Release_complete\n"); + return -1; + } + bc->need_disconnect=0; + bc->need_release=0; + bc->need_release_complete=0; break; case EVENT_CONNECT_ACKNOWLEDGE: + + if ( bc->nt || misdn_cap_is_speech(bc->capability)) { + int ret=setup_bc(bc); + if (ret == -EINVAL){ + cb_log(0,bc->port,"send_event: setup_bc failed\n"); + + } + } + if (misdn_cap_is_speech(bc->capability)) { if ( !bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0); - if (bc->ec_enable) manager_ec_enable(bc); + manager_ec_enable(bc); + if ( bc->txgain != 0 ) { cb_log(4, stack->port, "--> Changing txgain to %d\n", bc->txgain); manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain); @@ -2601,7 +3294,7 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) } /* Later we should think about sending bchannel data directly to misdn. */ - msg = isdn_msg_build_event(msgs_g, bc, event, stack->mode==NT_MODE?1:0); + msg = isdn_msg_build_event(msgs_g, bc, event, stack->nt); msg_queue_tail(&stack->downqueue, msg); sem_post(&glob_mgr->new_msg); @@ -2612,40 +3305,151 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ) } +int handle_err(msg_t *msg) +{ + iframe_t *frm = (iframe_t*) msg->data; + + + if (!frm->addr) { + static int cnt=0; + if (!cnt) + cb_log(0,0,"mISDN Msg without Address pr:%x dinfo:%x\n",frm->prim,frm->dinfo); + cnt++; + if (cnt>100) { + cb_log(0,0,"mISDN Msg without Address pr:%x dinfo:%x (already more than 100 of them)\n",frm->prim,frm->dinfo); + cnt=0; + } + + free_msg(msg); + return 1; + + } + + switch (frm->prim) { + case MGR_SETSTACK|INDICATION: + return handle_bchan(msg); + break; + + case MGR_SETSTACK|CONFIRM: + case MGR_CLEARSTACK|CONFIRM: + free_msg(msg) ; + return 1; + break; + + case DL_DATA|CONFIRM: + cb_log(4,0,"DL_DATA|CONFIRM\n"); + free_msg(msg); + return 1; + + case PH_CONTROL|CONFIRM: + cb_log(4,0,"PH_CONTROL|CONFIRM\n"); + free_msg(msg); + return 1; + + case DL_DATA|INDICATION: + { + int port=(frm->addr&MASTER_ID_MASK) >> 8; + int channel=(frm->addr&CHILD_ID_MASK) >> 16; + + /*we flush the read buffer here*/ + + cb_log(9,0,"BCHAN DATA without BC: addr:%x port:%d channel:%d\n",frm->addr, port,channel); + + free_msg(msg) ; + return 1; + + + struct misdn_bchannel *bc=find_bc_by_channel( port , channel); + + if (!bc) { + struct misdn_stack *stack=find_stack_by_port( port ); + + if (!stack) { + cb_log(0,0," --> stack not found\n"); + free_msg(msg); + return 1; + } + + cb_log(0,0," --> bc not found by channel\n"); + if (stack->l2link) + misdn_lib_get_l2_down(stack); + + if (stack->l1link) + misdn_lib_get_l1_down(stack); + + free_msg(msg); + return 1; + } + + cb_log(3,port," --> BC in state:%s\n", bc_state2str(bc->bc_state)); + } + } + + return 0; +} + + +int queue_l2l3(msg_t *msg) { + iframe_t *frm= (iframe_t*)msg->data; + struct misdn_stack *stack; + stack=find_stack_by_addr( frm->addr ); + + + if (!stack) { + return 0; + } + + msg_queue_tail(&stack->upqueue, msg); + sem_post(&glob_mgr->new_msg); + return 1; +} int manager_isdn_handler(iframe_t *frm ,msg_t *msg) { if (frm->dinfo==(signed long)0xffffffff && frm->prim==(PH_DATA|CONFIRM)) { - printf("SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n"); + cb_log(0,0,"SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n"); } + if ( ((frm->addr | ISDN_PID_BCHANNEL_BIT )>> 28 ) == 0x5) { + if (handle_bchan(msg)) { + return 0 ; + } + } + +#ifdef RECV_FRM_SYSLOG_DEBUG + syslog(LOG_NOTICE,"mISDN recv: P(%02d): ADDR:%x PRIM:%x DINFO:%x\n",stack->port, frm->addr, frm->prim, frm->dinfo); +#endif + if (handle_timers(msg)) return 0 ; - - if (handle_mgmt(msg)) - return 0 ; + + if (handle_mgmt(msg)) + return 0 ; + if (handle_l2(msg)) return 0 ; /* Its important to handle l1 AFTER l2 */ if (handle_l1(msg)) return 0 ; + + if (handle_frm_nt(msg)) { + return 0; + } - if (handle_bchan(msg)) - return 0 ; + if (handle_frm(msg)) { + return 0; + } - /** Handle L2/3 Signalling after bchans **/ - if (handle_frm_nt(msg)) - return 0 ; - - if (handle_frm(msg)) + if (handle_err(msg)) { return 0 ; + } - cb_log(0, frm->addr&IF_CONTRMASK, "Unhandled Message: prim %x len %d from addr %x, dinfo %x on port: %d\n",frm->prim, frm->len, frm->addr, frm->dinfo, frm->addr&IF_CONTRMASK); - + cb_log(0, 0, "Unhandled Message: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo); free_msg(msg); + return 0; } @@ -2664,12 +3468,14 @@ int misdn_lib_get_port_info(int port) } frm=(iframe_t*)msg->data; if (!stack ) { - cb_log(0, port, "There is no Stack on Port:%d\n",port); + cb_log(0, port, "There is no Stack for this port.\n"); return -1; } /* activate bchannel */ frm->prim = CC_STATUS_ENQUIRY | REQUEST; - frm->addr = stack->upper_id; + + frm->addr = stack->upper_id| FLG_MSG_DOWN; + frm->dinfo = 0; frm->len = 0; @@ -2680,80 +3486,65 @@ int misdn_lib_get_port_info(int port) return 0; } + +int queue_cleanup_bc(struct misdn_bchannel *bc) +{ + msg_t *msg=alloc_msg(MAX_MSG_SIZE); + iframe_t *frm; + if (!msg) { + cb_log(0, bc->port, "misgn_lib_get_port: alloc_msg failed!\n"); + return -1; + } + frm=(iframe_t*)msg->data; + + /* activate bchannel */ + frm->prim = MGR_CLEARSTACK| REQUEST; + + frm->addr = bc->l3_id; + + frm->dinfo = bc->port; + frm->len = 0; + + msg_queue_tail(&glob_mgr->activatequeue, msg); + sem_post(&glob_mgr->new_msg); + + return 0; + +} + int misdn_lib_port_restart(int port) { struct misdn_stack *stack=find_stack_by_port(port); - cb_log(0, port, "Restarting Port:%d\n",port); + cb_log(0, port, "Restarting this port.\n"); if (stack) { cb_log(0, port, "Stack:%p\n",stack); - - + clear_l3(stack); - { msg_t *msg=alloc_msg(MAX_MSG_SIZE); iframe_t *frm; if (!msg) { - cb_log(0, port, "port_restart: alloc_msg fialed\n"); + cb_log(0, port, "port_restart: alloc_msg failed\n"); return -1; } frm=(iframe_t*)msg->data; /* we must activate if we are deactivated */ /* activate bchannel */ - frm->prim = DL_RELEASE | REQUEST; - - frm->addr = stack->upper_id ; + frm->addr = stack->upper_id | FLG_MSG_DOWN; + frm->dinfo = 0; frm->len = 0; msg_queue_tail(&glob_mgr->activatequeue, msg); sem_post(&glob_mgr->new_msg); } - return 0; - - stack_te_destroy(stack); - - { - struct misdn_stack *tmpstack; - struct misdn_stack *newstack=stack_te_init(stack->midev ,port, stack->ptp); - - - if (stack == glob_mgr->stack_list) { - struct misdn_stack *n=glob_mgr->stack_list->next; - glob_mgr->stack_list = newstack ; - glob_mgr->stack_list->next = n; - } else { - for (tmpstack=glob_mgr->stack_list; - tmpstack->next; - tmpstack=tmpstack->next) - if (tmpstack->next == stack) break; - if (!tmpstack->next) { - cb_log(0, port, "Stack to restart not found\n"); - return 0; - } else { - struct misdn_stack *n=tmpstack->next->next; - tmpstack->next=newstack; - newstack->next=n; - } - } - - { - int i; - for(i=0;i<newstack->b_num; i++) { - int r; - if ((r=init_bc(newstack, &newstack->bc[i], newstack->midev,port,i, "", 1))<0) { - cb_log(0, port, "Got Err @ init_bc :%d\n",r); - return 0; - } - } - } - - free(stack); - } + if (stack->nt) + misdn_lib_reinit_nt_stack(stack->port); + } return 0; @@ -2782,6 +3573,27 @@ void manager_event_handler(void *arg) iframe_t *frm = (iframe_t*) msg->data ; switch ( frm->prim) { + + case MGR_CLEARSTACK | REQUEST: + /*a queued bchannel cleanup*/ + { + struct misdn_stack *stack=find_stack_by_port(frm->dinfo); + if (!stack) { + cb_log(0,0,"no stack found with port [%d]!! so we cannot cleanup the bc\n",frm->dinfo); + free_msg(msg); + break; + } + + struct misdn_bchannel *bc=find_bc_by_l3id(stack,frm->addr); + if (bc) { + cb_log(1,bc->port,"CLEARSTACK queued, cleaning up\n"); + clean_up_bc(bc); + } else { + cb_log(0,stack->port,"bc could not be cleaned correctly !! addr [%x]\n",frm->addr); + } + } + free_msg(msg); + break; case MGR_SETSTACK | REQUEST : break; default: @@ -2793,20 +3605,32 @@ void manager_event_handler(void *arg) for (stack=glob_mgr->stack_list; stack; stack=stack->next ) { + + while ( (msg=msg_dequeue(&stack->upqueue)) ) { + /** Handle L2/3 Signalling after bchans **/ + if (!handle_frm_nt(msg)) { + /* Maybe it's TE */ + if (!handle_frm(msg)) { + /* wow none! */ + cb_log(0,stack->port,"Wow we've got a strange issue while dequeueing a Frame\n"); + } + } + } + + /* Here we should check if we really want to + send all the messages we've queued, lets + assume we've queued a Disconnect, but + received it already from the other side!*/ + while ( (msg=msg_dequeue(&stack->downqueue)) ) { - - if (stack->mode == NT_MODE ){ - + if (stack->nt ) { if (stack->nst.manager_l3(&stack->nst, msg)) cb_log(0, stack->port, "Error@ Sending Message in NT-Stack.\n"); } else { - if (msg) { - iframe_t *frm = (iframe_t *)msg->data; - struct misdn_bchannel *bc = find_bc_by_l3id(stack, frm->dinfo); - - if (bc) send_msg(glob_mgr->midev, bc, msg); - } + iframe_t *frm = (iframe_t *)msg->data; + struct misdn_bchannel *bc = find_bc_by_l3id(stack, frm->dinfo); + if (bc) send_msg(glob_mgr->midev, bc, msg); } } } @@ -2829,6 +3653,27 @@ int misdn_lib_maxports_get() { /** BE AWARE WE HAVE NO CB_LOG HERE! **/ return max; } + +void misdn_lib_nt_debug_init( int flags, char *file ) +{ + int static init=0; + char *f; + + if (!flags) + f=NULL; + else + f=file; + + if (!init) { + debug_init( flags , f, f, f); + init=1; + } else { + debug_close(); + debug_init( flags , f, f, f); + } +} + + int misdn_lib_init(char *portlist, struct misdn_lib_iface *iface, void *user_data) { struct misdn_lib *mgr=calloc(1, sizeof(struct misdn_lib)); @@ -2839,12 +3684,13 @@ int misdn_lib_init(char *portlist, struct misdn_lib_iface *iface, void *user_dat cb_log = iface->cb_log; cb_event = iface->cb_event; - cb_clearl3_true = iface->cb_clearl3_true; + cb_jb_empty = iface->cb_jb_empty; glob_mgr = mgr; msg_init(); - debug_init(0 , NULL, NULL, NULL); + + misdn_lib_nt_debug_init(0,NULL); if (!portlist || (*portlist == 0) ) return 1; @@ -2883,12 +3729,10 @@ int misdn_lib_init(char *portlist, struct misdn_lib_iface *iface, void *user_dat ptp=1; if (port > port_count) { - cb_log(0, port, "Couldn't Initialize Port:%d since we have only %d ports\n",port, port_count); + cb_log(0, port, "Couldn't Initialize this port since we have only %d ports\n", port_count); exit(1); } - stack=stack_te_init(midev, port, ptp); - - + stack=stack_init(midev, port, ptp); if (!stack) { perror("init_stack"); @@ -2937,22 +3781,20 @@ int misdn_lib_init(char *portlist, struct misdn_lib_iface *iface, void *user_dat if (sem_init(&handler_started, 1, 0)<0) sem_init(&handler_started, 0, 0); - cb_log(4, 0, "Starting Event Handler\n"); + cb_log(8, 0, "Starting Event Handler\n"); pthread_create( &mgr->event_handler_thread, NULL,(void*)manager_event_handler, mgr); sem_wait(&handler_started) ; - cb_log(4, 0, "Starting Event Catcher\n"); + cb_log(8, 0, "Starting Event Catcher\n"); pthread_create( &mgr->event_thread, NULL, (void*)misdn_lib_isdn_event_catcher, mgr); - cb_log(4, 0, "Event Catcher started\n"); + cb_log(8, 0, "Event Catcher started\n"); global_state= MISDN_INITIALIZED; return (mgr == NULL); } - - void misdn_lib_destroy() { struct misdn_stack *help; @@ -2961,14 +3803,11 @@ void misdn_lib_destroy() for ( help=glob_mgr->stack_list; help; help=help->next ) { for(i=0;i<help->b_num; i++) { char buf[1024]; - mISDN_write_frame(help->midev, buf, help->bc[i].addr, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC); help->bc[i].addr = 0; } - - - cb_log (1, help->port, "Destroying port:%d\n", help->port); - stack_te_destroy(help); + cb_log (1, help->port, "Destroying this port.\n"); + stack_destroy(help); } if (global_state == MISDN_INITIALIZED) { @@ -2978,7 +3817,6 @@ void misdn_lib_destroy() pthread_join(glob_mgr->event_handler_thread, NULL); } - cb_log(4, 0, "Killing Main Thread\n"); if ( pthread_cancel(glob_mgr->event_thread) == 0 ) { cb_log(4, 0, "Joining Main Thread\n"); @@ -2990,48 +3828,42 @@ void misdn_lib_destroy() te_lib_destroy(glob_mgr->midev); } - char *manager_isdn_get_info(enum event_e event) { return isdn_get_info(msgs_g , event, 0); } - - - void manager_bchannel_activate(struct misdn_bchannel *bc) { - msg_t *msg=alloc_msg(MAX_MSG_SIZE); - iframe_t *frm; + char buf[128]; + iframe_t *ifrm; + int ret; struct misdn_stack *stack=get_stack_by_bc(bc); - - if (!msg) { - cb_log(0, stack->port, "bchannel_activate: alloc_msg failed !"); + + if (!stack) { + cb_log(0, bc->port, "bchannel_activate: Stack not found !"); return ; } - frm=(iframe_t*)msg->data; /* we must activate if we are deactivated */ - clear_ibuffer(bc->misdnbuf); clear_ibuffer(bc->astbuf); - - if (bc->active) return; - cb_log(5, stack->port, "$$$ Bchan Activated addr %x\n", bc->addr); - - /* activate bchannel */ - frm->prim = DL_ESTABLISH | REQUEST; - frm->addr = bc->addr ; - frm->dinfo = 0; - frm->len = 0; - msg_queue_tail(&glob_mgr->activatequeue, msg); - sem_post(&glob_mgr->new_msg); + mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_DOWN, DL_ESTABLISH | REQUEST, 0,0, NULL, TIMEOUT_1SEC); - bc->active=1; - + ret=mISDN_read(stack->midev,buf,128,TIMEOUT_10SEC); + + ifrm=(iframe_t*)buf; + + if (ret>0) { + if (ifrm->prim== (DL_ESTABLISH|CONFIRM)) { + cb_log(2,stack->port,"bchan: DL_ESTABLISH|CNF\n"); + } + } + + return ; } @@ -3039,96 +3871,106 @@ void manager_bchannel_activate(struct misdn_bchannel *bc) void manager_bchannel_deactivate(struct misdn_bchannel * bc) { - iframe_t dact; struct misdn_stack *stack=get_stack_by_bc(bc); - if (!bc->active) return; - - cb_log(5, stack->port, "$$$ Bchan deActivated addr %x\n", bc->addr); - - bc->tone=TONE_NONE; + + switch (bc->bc_state) { + case BCHAN_ACTIVATED: + break; + case BCHAN_BRIDGED: + misdn_split_conf(bc,bc->conf_id); + break; + default: + cb_log( 4, bc->port,"bchan_deactivate: called but not activated\n"); + return ; + + } + + cb_log(5, stack->port, "$$$ Bchan deActivated addr %x\n", bc->addr); + + bc->generate_tone=0; + + iframe_t dact; dact.prim = DL_RELEASE | REQUEST; - dact.addr = bc->addr; + dact.addr = bc->addr | FLG_MSG_DOWN; dact.dinfo = 0; dact.len = 0; - - mISDN_write(stack->midev, &dact, mISDN_HEADER_LEN+dact.len, TIMEOUT_1SEC); - clear_ibuffer(bc->misdnbuf); + char buf[128]; + mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_DOWN, DL_RELEASE|REQUEST,0,0,NULL, TIMEOUT_1SEC); + + mISDN_read(stack->midev, buf, 128, TIMEOUT_1SEC); + clear_ibuffer(bc->astbuf); - bc->active=0; + + bc_state_change(bc,BCHAN_RELEASE); return; } -int manager_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len) +int misdn_lib_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len) { - struct misdn_stack *stack=get_stack_by_bc(bc); - if (!bc->active) return -1; - if ( misdn_cap_is_speech(bc->capability) ) - flip_buf_bits(data,len); + switch (bc->bc_state) { + case BCHAN_ACTIVATED: + case BCHAN_BRIDGED: + break; + default: + cb_log(3, bc->port, "BC not yet activated (state:%s)\n",bc_state2str(bc->bc_state)); + return -1; + } - if ( !bc->nojitter && misdn_cap_is_speech(bc->capability) ) { - if (len > ibuf_freecount(bc->misdnbuf)) { - len=ibuf_freecount(bc->misdnbuf); - } - ibuf_memcpy_w(bc->misdnbuf, (unsigned char*)data, len); - } else { - char buf[4096 + mISDN_HEADER_LEN]; - iframe_t *frm= (iframe_t*)buf; - int r; - - frm->prim = DL_DATA|REQUEST; - frm->dinfo = 0; - frm->addr = bc->addr | IF_DOWN; - frm->len = len; - memcpy(&buf[mISDN_HEADER_LEN], data,len); - - - - if ( misdn_cap_is_speech(bc->capability)) - cb_log(4, stack->port, "Writing %d bytes\n",len); + char buf[4096 + mISDN_HEADER_LEN]; + iframe_t *frm= (iframe_t*)buf; + int r; + + frm->prim = DL_DATA|REQUEST; + frm->dinfo = 0; + frm->addr = bc->addr | FLG_MSG_DOWN ; + + frm->len = len; + memcpy(&buf[mISDN_HEADER_LEN], data,len); - cb_log(9, stack->port, "Wrinting %d bytes 2 mISDN\n",len); - r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_INFINIT); + if ( misdn_cap_is_speech(bc->capability) ) + flip_buf_bits( &buf[mISDN_HEADER_LEN], len); + else + cb_log(6, stack->port, "Writing %d data bytes\n",len); + + cb_log(9, stack->port, "Writing %d bytes 2 mISDN\n",len); + r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_INFINIT); +#ifdef ACK_HDLC + if (bc->hdlc && bc->ack_hdlc) { + cb_log(4,stack->port,"Awaiting Acknowledge [%d]\n",len); + sem_wait((sem_t*)bc->ack_hdlc); + cb_log(4,stack->port,"Acknowledged\n"); } - +#endif return 0; } - -void manager_send_tone (struct misdn_bchannel *bc, enum tone_e tone) -{ - if (tone != TONE_NONE) manager_bchannel_activate(bc); - bc->tone=tone; - bc->tone_cnt2=-1; - bc->tone_cnt=0; -} - - - /* * send control information to the channel (dsp-module) */ void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2) { - unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+sizeof(int)]; + unsigned char buffer[mISDN_HEADER_LEN+ 2*sizeof(int)]; iframe_t *ctrl = (iframe_t *)buffer; /* preload data */ - unsigned long *d = (unsigned long *)&ctrl->data.p; - struct misdn_stack *stack=get_stack_by_bc(bc); + unsigned int *d = (unsigned int*)&ctrl->data.p; + /*struct misdn_stack *stack=get_stack_by_bc(bc);*/ + + cb_log(4,bc->port,"ph_control: c1:%x c2:%x\n",c1,c2); ctrl->prim = PH_CONTROL | REQUEST; - ctrl->addr = bc->addr; + ctrl->addr = bc->addr | FLG_MSG_DOWN; ctrl->dinfo = 0; - ctrl->len = sizeof(unsigned long)*2; + ctrl->len = sizeof(unsigned int)*2; *d++ = c1; *d++ = c2; - mISDN_write(stack->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC); + mISDN_write(glob_mgr->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC); } /* @@ -3138,16 +3980,16 @@ void manager_ph_control_block(struct misdn_bchannel *bc, int c1, void *c2, int c { unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+c2_len]; iframe_t *ctrl = (iframe_t *)buffer; - unsigned long *d = (unsigned long *)&ctrl->data.p; - struct misdn_stack *stack=get_stack_by_bc(bc); + unsigned int *d = (unsigned int *)&ctrl->data.p; + /*struct misdn_stack *stack=get_stack_by_bc(bc);*/ ctrl->prim = PH_CONTROL | REQUEST; - ctrl->addr = bc->addr; + ctrl->addr = bc->addr | FLG_MSG_DOWN; ctrl->dinfo = 0; - ctrl->len = sizeof(unsigned long) + c2_len; + ctrl->len = sizeof(unsigned int) + c2_len; *d++ = c1; memcpy(d, c2, c2_len); - mISDN_write(stack->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC); + mISDN_write(glob_mgr->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC); } @@ -3157,10 +3999,8 @@ void manager_clean_bc(struct misdn_bchannel *bc ) { struct misdn_stack *stack=get_stack_by_bc(bc); - if (bc->state == STATE_CONNECTED) - misdn_lib_send_event(bc,EVENT_DISCONNECT); - - empty_chan_in_stack(stack, bc->channel); + if (bc->channel>0) + empty_chan_in_stack(stack, bc->channel); empty_bc(bc); misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); @@ -3188,6 +4028,7 @@ void stack_holder_add(struct misdn_stack *stack, struct misdn_bchannel *holder) help=help->next) { if (!help->next) { help->next=holder; + break; } } @@ -3199,6 +4040,8 @@ void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holde if (!holder->stack_holder) return; + holder->stack_holder=0; + cb_log(4,stack->port, "*HOLDER: remove %x\n",holder->l3_id); if (!stack || ! stack->holding) return; @@ -3241,35 +4084,78 @@ struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned lon +void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone) +{ + + switch(tone) { + case TONE_DIAL: + manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_DIALTONE); + break; + + case TONE_ALERTING: + manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_RINGING); + break; + + case TONE_HANGUP: + manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_HANGUP); + break; + + case TONE_NONE: + default: + manager_ph_control(bc, TONE_PATT_OFF, TONE_GERMAN_HANGUP); + } + + char buf[mISDN_HEADER_LEN+128]; + iframe_t *frm=(iframe_t*)buf; + memset(buf,0,mISDN_HEADER_LEN+128); + + frm->prim=DL_DATA|REQUEST; + frm->addr=bc->addr|FLG_MSG_DOWN; + frm->dinfo=0; + frm->len=128; + + mISDN_write(glob_mgr->midev, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC); +} + + void manager_ec_enable(struct misdn_bchannel *bc) { int ec_arr[2]; struct misdn_stack *stack=get_stack_by_bc(bc); - cb_log(1, stack?stack->port:0,"Sending Control ECHOCAN_ON taps:%d training:%d\n",bc->ec_deftaps, bc->ec_training); - - switch (bc->ec_deftaps) { - case 4: - case 8: - case 16: - case 32: - case 64: - case 128: - case 256: - case 512: - case 1024: - cb_log(4, stack->port, "Taps is %d\n",bc->ec_deftaps); - break; - default: - cb_log(0, stack->port, "Taps should be power of 2\n"); - bc->ec_deftaps=128; + cb_log(1, stack?stack->port:0,"ec_enable\n"); + + if (!misdn_cap_is_speech(bc->capability)) { + cb_log(1, stack?stack->port:0, " --> no speech? cannot enable EC\n"); + return; } - ec_arr[0]=bc->ec_deftaps; - ec_arr[1]=bc->ec_training; + if (bc->ec_enable) { + cb_log(1, stack?stack->port:0,"Sending Control ECHOCAN_ON taps:%d training:%d\n",bc->ec_deftaps, bc->ec_training); + + switch (bc->ec_deftaps) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + cb_log(4, stack->port, "Taps is %d\n",bc->ec_deftaps); + break; + default: + cb_log(0, stack->port, "Taps should be power of 2\n"); + bc->ec_deftaps=128; + } - manager_ph_control_block(bc, ECHOCAN_ON, ec_arr, sizeof(ec_arr)); + ec_arr[0]=bc->ec_deftaps; + ec_arr[1]=0; + + manager_ph_control_block(bc, ECHOCAN_ON, ec_arr, sizeof(ec_arr)); + } } @@ -3278,8 +4164,17 @@ void manager_ec_disable(struct misdn_bchannel *bc) { struct misdn_stack *stack=get_stack_by_bc(bc); - cb_log(1, stack?stack->port:0, "Sending Control ECHOCAN_OFF\n"); - manager_ph_control(bc, ECHOCAN_OFF, 0); + cb_log(1, stack?stack->port:0,"ec_disable\n"); + + if (!misdn_cap_is_speech(bc->capability)) { + cb_log(1, stack?stack->port:0, " --> no speech? cannot disable EC\n"); + return; + } + + if ( bc->ec_enable) { + cb_log(1, stack?stack->port:0, "Sending Control ECHOCAN_OFF\n"); + manager_ph_control(bc, ECHOCAN_OFF, 0); + } } struct misdn_stack* get_misdn_stack() { @@ -3288,21 +4183,127 @@ struct misdn_stack* get_misdn_stack() { +void misdn_join_conf(struct misdn_bchannel *bc, int conf_id) +{ + bc_state_change(bc,BCHAN_BRIDGED); + manager_ph_control(bc, CMX_RECEIVE_OFF, 0); + manager_ph_control(bc, CMX_CONF_JOIN, conf_id); + + cb_log(1,bc->port, "Joining bc:%x in conf:%d\n",bc->addr,conf_id); + + char data[16]; + int len=15; + + memset(data,0,15); + + misdn_lib_tx2misdn_frm(bc, data, len); + +} + + +void misdn_split_conf(struct misdn_bchannel *bc, int conf_id) +{ + bc_state_change(bc,BCHAN_ACTIVATED); + manager_ph_control(bc, CMX_RECEIVE_ON, 0); + manager_ph_control(bc, CMX_CONF_SPLIT, conf_id); + + cb_log(1,bc->port, "Splitting bc:%x in conf:%d\n",bc->addr,conf_id); +} + void misdn_lib_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2) { - manager_ph_control(bc1, CMX_RECEIVE_OFF, 0); - manager_ph_control(bc2, CMX_RECEIVE_OFF, 0); + int conf_id=bc1->pid +1; + + cb_log(1, bc1->port, "I Send: BRIDGE from:%d to:%d\n",bc1->port,bc2->port); + + struct misdn_bchannel *bc_list[]={ + bc1,bc2,NULL + }; + struct misdn_bchannel **bc; + + for (bc=bc_list; *bc; *bc++) { + (*bc)->conf_id=conf_id; + cb_log(1, (*bc)->port, " --> bc_addr:%x\n",(*bc)->addr); - manager_ph_control(bc1, CMX_CONF_JOIN, (bc1->pid<<1) +1); - manager_ph_control(bc2, CMX_CONF_JOIN, (bc1->pid<<1) +1); + switch((*bc)->bc_state) { + case BCHAN_ACTIVATED: + misdn_join_conf(*bc,conf_id); + break; + default: + bc_next_state_change(*bc,BCHAN_BRIDGED); + break; + } + } } void misdn_lib_split_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2) { + + struct misdn_bchannel *bc_list[]={ + bc1,bc2,NULL + }; + struct misdn_bchannel **bc; + + for (bc=bc_list; *bc; *bc++) { + if ( (*bc)->bc_state == BCHAN_BRIDGED){ + misdn_split_conf( *bc, (*bc)->conf_id); + } else { + cb_log( 2, (*bc)->port, "BC not bridged (state:%s) so not splitting it\n",bc_state2str((*bc)->bc_state)); + } + } + +} + + + +void misdn_lib_echo(struct misdn_bchannel *bc, int onoff) +{ + cb_log(1,bc->port, " --> ECHO %s\n", onoff?"ON":"OFF"); + manager_ph_control(bc, onoff?CMX_ECHO_ON:CMX_ECHO_OFF, 0); +} + + + +void misdn_lib_reinit_nt_stack(int port) +{ + struct misdn_stack *stack=find_stack_by_port(port); - manager_ph_control(bc1, CMX_RECEIVE_ON, 0) ; - manager_ph_control(bc2, CMX_RECEIVE_ON, 0); + if (stack) { + stack->l2link=0; + stack->blocked=0; - manager_ph_control(bc1, CMX_CONF_SPLIT, (bc1->pid<<1) +1); - manager_ph_control(bc2, CMX_CONF_SPLIT, (bc1->pid<<1) +1); + cleanup_Isdnl3(&stack->nst); + cleanup_Isdnl2(&stack->nst); + + + memset(&stack->nst, 0, sizeof(net_stack_t)); + memset(&stack->mgr, 0, sizeof(manager_t)); + + stack->mgr.nst = &stack->nst; + stack->nst.manager = &stack->mgr; + + stack->nst.l3_manager = handle_event_nt; + stack->nst.device = glob_mgr->midev; + stack->nst.cardnr = port; + stack->nst.d_stid = stack->d_stid; + + stack->nst.feature = FEATURE_NET_HOLD; + if (stack->ptp) + stack->nst.feature |= FEATURE_NET_PTP; + if (stack->pri) + stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID; + + stack->nst.l1_id = stack->lower_id; + stack->nst.l2_id = stack->upper_id; + + msg_queue_init(&stack->nst.down_queue); + Isdnl2Init(&stack->nst); + Isdnl3Init(&stack->nst); + + if (!stack->ptp) + misdn_lib_get_l1_up(stack); + misdn_lib_get_l2_up(stack); + } } + + diff --git a/channels/misdn/isdn_lib.h b/channels/misdn/isdn_lib.h index 28a4fe7b6..f79bc2ad0 100644 --- a/channels/misdn/isdn_lib.h +++ b/channels/misdn/isdn_lib.h @@ -14,36 +14,74 @@ #ifndef TE_LIB #define TE_LIB + /** For initialization usage **/ /* typedef int ie_nothing_t ;*/ /** end of init usage **/ +#ifdef WITH_BEROEC +typedef int beroec_t; -#define MAX_BCHANS 30 -enum bc_state_e { - STATE_NOTHING=0, - STATE_NULL, - STATE_CALL_INIT, - STATE_CONNECTED, - STATE_HOLD_ACKNOWLEDGE +enum beroec_type { + BEROEC_FULLBAND=0, + BEROEC_SUBBAND, + BEROEC_FASTSUBBAND }; +void beroec_init(void); +void beroec_exit(void); +beroec_t *beroec_new(int tail, enum beroec_type type, int anti_howl, + int tonedisable, int zerocoeff, int adapt, int nlp); + +void beroec_destroy(beroec_t *ec); +int beroec_cancel_alaw_chunk(beroec_t *ec, + char *send, + char *receive , + int len); + +int beroec_version(void); +#endif + + enum tone_e { TONE_NONE=0, TONE_DIAL, TONE_ALERTING, + TONE_FAR_ALERTING, TONE_BUSY, + TONE_HANGUP, + TONE_CUSTOM, TONE_FILE }; + + +#define MAX_BCHANS 30 + +enum bchannel_state { + BCHAN_CLEANED=0, + BCHAN_EMPTY, + BCHAN_SETUP, + BCHAN_SETUPED, + BCHAN_ACTIVE, + BCHAN_ACTIVATED, + BCHAN_BRIDGE, + BCHAN_BRIDGED, + BCHAN_RELEASE, + BCHAN_RELEASED, + BCHAN_CLEAN, + BCHAN_CLEAN_REQUEST, + BCHAN_ERROR +}; + + enum misdn_err_e { ENOCHAN=1 }; - enum mISDN_NUMBER_PLAN { NUMPLAN_UNINITIALIZED=-1, NUMPLAN_INTERNATIONAL=0x1, @@ -61,10 +99,11 @@ enum event_response_e { }; - enum event_e { EVENT_NOTHING, + EVENT_TONE_GENERATE, EVENT_BCHAN_DATA, + EVENT_BCHAN_ACTIVATED, EVENT_CLEANUP, EVENT_PROCEEDING, EVENT_PROGRESS, @@ -99,6 +138,7 @@ enum event_e { EVENT_DTMF_TONE, EVENT_NEW_L3ID, EVENT_NEW_BC, + EVENT_PORT_ALARM, EVENT_UNKNOWN }; @@ -144,9 +184,19 @@ enum layer_e { UNKNOWN }; + + +/** FACILITY STUFF **/ + enum facility_type { FACILITY_NONE, - FACILITY_CALLDEFLECT + FACILITY_CALLDEFLECT=0x91, + FACILITY_CENTREX=0x88 +}; + +union facility { + char calldeflect_nr[15]; + char cnip[256]; }; @@ -161,13 +211,21 @@ struct misdn_bchannel { /* int b_addr; */ int layer_id; - + void *ack_hdlc; + + int layer; + /*state stuff*/ + int need_disconnect; + int need_release; + int need_release_complete; + /** var stuff**/ int l3_id; int pid; int ces; - + + int restart_channel; int channel; int channel_preselected; @@ -180,8 +238,8 @@ struct misdn_bchannel { void *astbuf; + void *misdnbuf; - int te_choose_channel; int early_bconnect; @@ -190,6 +248,13 @@ struct misdn_bchannel { int dtmf; int send_dtmf; + /* get setup ack */ + int need_more_infos; + + /* may there be more infos ?*/ + int sending_complete; + + /* wether we should use jollys dsp or not */ int nodsp; @@ -199,13 +264,17 @@ struct misdn_bchannel { enum mISDN_NUMBER_PLAN dnumplan; enum mISDN_NUMBER_PLAN rnumplan; enum mISDN_NUMBER_PLAN onumplan; + enum mISDN_NUMBER_PLAN cpnnumplan; int progress_coding; int progress_location; int progress_indicator; - enum facility_type facility; - char facility_calldeflect_nr[15]; + enum facility_type fac_type; + union facility fac; + + enum facility_type out_fac_type; + union facility out_fac; enum event_e evq; @@ -226,14 +295,18 @@ struct misdn_bchannel { int active; int upset; - enum tone_e tone; + int generate_tone; int tone_cnt; - int tone_cnt2; - - enum bc_state_e state; + + enum bchannel_state bc_state; + enum bchannel_state next_bc_state; + int conf_id; + int holded; int stack_holder; + + struct misdn_bchannel *holded_bc; int pres; int screen; @@ -246,7 +319,7 @@ struct misdn_bchannel { int user1; int urate; - int async; + int hdlc; /* V110 */ unsigned char display[84]; @@ -254,16 +327,17 @@ struct misdn_bchannel { unsigned char oad[32]; unsigned char rad[32]; unsigned char dad[32]; + unsigned char cad[32]; unsigned char orig_dad[32]; unsigned char keypad[32]; - + unsigned char info_dad[64]; unsigned char infos_pending[64]; - unsigned char info_keypad[32]; - unsigned char clisub[24]; - unsigned char cldsub[24]; - unsigned char fac[132]; - unsigned char uu[256]; + +/* unsigned char info_keypad[32]; */ +/* unsigned char clisub[24]; */ +/* unsigned char cldsub[24]; */ +/* unsigned char uu[256]; */ int cause; int out_cause; @@ -276,6 +350,16 @@ struct misdn_bchannel { int ec_deftaps; int ec_whenbridged; int ec_training; + +#ifdef WITH_BEROEC + beroec_t *ec; + int bnec_tail; + int bnec_ah; + int bnec_nlp; + int bnec_td; + int bnec_adapt; + int bnec_zero; +#endif int orig; @@ -288,17 +372,19 @@ struct misdn_bchannel { enum event_response_e (*cb_event) (enum event_e event, struct misdn_bchannel *bc, void *user_data); void (*cb_log) (int level, int port, char *tmpl, ...); -int (*cb_clearl3_true)(void); +int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len); struct misdn_lib_iface { enum event_response_e (*cb_event)(enum event_e event, struct misdn_bchannel *bc, void *user_data); void (*cb_log)(int level, int port, char *tmpl, ...); - int (*cb_clearl3_true)(void); + int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len); }; /***** USER IFACE **********/ +void misdn_lib_nt_debug_init( int flags, char *file ); + int misdn_lib_init(char *portlist, struct misdn_lib_iface* iface, void *user_data); int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event ); void misdn_lib_destroy(void); @@ -313,8 +399,8 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel); void manager_bchannel_activate(struct misdn_bchannel *bc); void manager_bchannel_deactivate(struct misdn_bchannel * bc); -int manager_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len); -void manager_send_tone (struct misdn_bchannel *bc, enum tone_e tone); + +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); @@ -322,7 +408,13 @@ void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2); int misdn_lib_port_restart(int port); int misdn_lib_get_port_info(int port); -int misdn_lib_port_up(int port); +int misdn_lib_is_port_blocked(int port); +int misdn_lib_port_block(int port); +int misdn_lib_port_unblock(int port); + +int misdn_lib_port_up(int port, int notcheck); + +int misdn_lib_get_port_down(int port); int misdn_lib_get_port_up (int port) ; @@ -339,24 +431,26 @@ int misdn_lib_send_facility(struct misdn_bchannel *bc, enum facility_type fac, v void manager_ec_enable(struct misdn_bchannel *bc); void manager_ec_disable(struct misdn_bchannel *bc); +void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone); + void get_show_stack_details(int port, char *buf); -/** Ibuf interface **/ -int misdn_ibuf_usedcount(void *buf); -int misdn_ibuf_freecount(void *buf); -void misdn_ibuf_memcpy_r(char *to, void *from, int len); -void misdn_ibuf_memcpy_w(void *buf, char *from, int len); +void misdn_lib_tone_generator_start(struct misdn_bchannel *bc); +void misdn_lib_tone_generator_stop(struct misdn_bchannel *bc); -/** Ibuf interface End **/ void misdn_lib_setup_bc(struct misdn_bchannel *bc); void misdn_lib_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2); void misdn_lib_split_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2); +void misdn_lib_echo(struct misdn_bchannel *bc, int onoff); int misdn_lib_is_ptp(int port); +int misdn_lib_get_maxchans(int port); + +void misdn_lib_reinit_nt_stack(int port); #define PRI_TRANS_CAP_SPEECH 0x0 #define PRI_TRANS_CAP_DIGITAL 0x08 @@ -364,4 +458,11 @@ int misdn_lib_is_ptp(int port); #define PRI_TRANS_CAP_3_1K_AUDIO 0x10 #define PRI_TRANS_CAP_7K_AUDIO 0x11 + + +char *bc_state2str(enum bchannel_state state); +void bc_state_change(struct misdn_bchannel *bc, enum bchannel_state state); + + + #endif diff --git a/channels/misdn/isdn_lib_intern.h b/channels/misdn/isdn_lib_intern.h index 0305a2dad..ff63339bc 100644 --- a/channels/misdn/isdn_lib_intern.h +++ b/channels/misdn/isdn_lib_intern.h @@ -1,5 +1,5 @@ #ifndef ISDN_LIB_INTERN -#define ISDN_LIB_INTER +#define ISDN_LIB_INTERN #include <mISDNuser/mISDNlib.h> @@ -11,17 +11,13 @@ #include "isdn_lib.h" - - +#define QI_ELEMENT(a) a.off #ifndef mISDNUSER_HEAD_SIZE -#ifdef MISDNUSER_JOLLY #define mISDNUSER_HEAD_SIZE (sizeof(mISDNuser_head_t)) -#else -#define mISDNUSER_HEAD_SIZE (sizeof(mISDN_head_t)) -#endif +/*#define mISDNUSER_HEAD_SIZE (sizeof(mISDN_head_t))*/ #endif @@ -37,8 +33,6 @@ struct isdn_msg { void (*msg_parser)(struct isdn_msg *msgs, msg_t *msg, struct misdn_bchannel *bc, int nt); msg_t *(*msg_builder)(struct isdn_msg *msgs, struct misdn_bchannel *bc, int nt); - void (*msg_printer)(struct isdn_msg *msgs); - char *info; } ; @@ -60,9 +54,16 @@ struct misdn_stack { int b_stids[MAX_BCHANS + 1]; int ptp; + + int l2upcnt; + + int l2_id; int lower_id; int upper_id; + + int blocked; + int l2link; time_t l2establish; @@ -70,7 +71,7 @@ struct misdn_stack { int l1link; int midev; - enum mode_e {NT_MODE, TE_MODE} mode; + int nt; int pri; @@ -78,6 +79,7 @@ struct misdn_stack { int procids[0x100+1]; msg_queue_t downqueue; + msg_queue_t upqueue; int busy; int port; @@ -96,4 +98,6 @@ struct misdn_stack { struct misdn_stack* get_stack_by_bc(struct misdn_bchannel *bc); + + #endif diff --git a/channels/misdn/isdn_msg_parser.c b/channels/misdn/isdn_msg_parser.c index 9b59f8685..d23031ecb 100644 --- a/channels/misdn/isdn_msg_parser.c +++ b/channels/misdn/isdn_msg_parser.c @@ -12,30 +12,57 @@ */ +#include "isdn_lib_intern.h" + + #include "isdn_lib.h" + #include "ie.c" +#include "fac.h" + + +void set_channel(struct misdn_bchannel *bc, int channel) { + + cb_log(3,bc->port,"set_channel: bc->channel:%d channel:%d\n", bc->channel, channel); + + + if (channel==0xff) { + /* any channel */ + channel=-1; + } + + /* ALERT: is that everytime true ? */ + if (channel > 0 && bc->nt ) { + + if (bc->channel && ( bc->channel != 0xff) ) { + cb_log(0,bc->port,"We already have a channel (%d)\n", bc->channel); + } else { + bc->channel = channel; + } + } + + if (channel > 0 && !bc->nt ) + bc->channel = channel; +} void parse_proceeding (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; CALL_PROCEEDING_t *proceeding=(CALL_PROCEEDING_t*)((unsigned long)msg->data+ HEADER_LEN); - struct misdn_stack *stack=get_stack_by_bc(bc); + //struct misdn_stack *stack=get_stack_by_bc(bc); { int exclusive, channel; dec_ie_channel_id(proceeding->CHANNEL_ID, (Q931_info_t *)proceeding, &exclusive, &channel, nt,bc); + + set_channel(bc,channel); - if (channel==0xff) /* any channel */ - channel=-1; - - /* ALERT: is that everytime true ? */ - if (channel > 0 && stack->mode == NT_MODE) - bc->channel = channel; } dec_ie_progress(proceeding->PROGRESS, (Q931_info_t *)proceeding, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc); + #if DEBUG printf("Parsing PROCEEDING Msg\n"); #endif @@ -59,9 +86,6 @@ msg_t *build_proceeding (struct isdn_msg msgs[], struct misdn_bchannel *bc, int #endif return msg; } -void print_proceeding (struct isdn_msg msgs[]) -{ -} void parse_alerting (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -94,9 +118,6 @@ msg_t *build_alerting (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt #endif return msg; } -void print_alerting (struct isdn_msg msgs[]) -{ -} void parse_progress (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) @@ -125,10 +146,6 @@ msg_t *build_progress (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt #endif return msg; } -void print_progress (struct isdn_msg msgs[]) -{ -} - void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -142,87 +159,76 @@ void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, { int type,plan,present, screen; char id[32]; - dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, (unsigned char *)id, sizeof(id), nt,bc); + dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, (unsigned char *)id, sizeof(id)-1, nt,bc); bc->onumplan=type; strcpy(bc->oad, id); switch (present) { case 0: -// cb_log(3, bc->stack->port, " --> Pres:0\n"); bc->pres=0; /* screened */ break; case 1: -// cb_log(3, bc->stack->port, " --> Pres:1\n"); bc->pres=1; /* not screened */ break; default: -// cb_log(3, bc->stack->port, " --> Pres:%d\n",present); bc->pres=0; } switch (screen) { case 0: -// cb_log(4, bc->stack->port, " --> Screen:0\n"); break; default: -// cb_log(4, bc->stack->port, " --> Screen:%d\n",screen); ; } } { int type, plan; char number[32]; - dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)setup, &type, &plan, (unsigned char *)number, sizeof(number), nt,bc); + dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)setup, &type, &plan, (unsigned char *)number, sizeof(number)-1, nt,bc); strcpy(bc->dad, number); bc->dnumplan=type; } { char keypad[32]; - dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, (unsigned char *)keypad, sizeof(keypad), nt,bc); + dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, (unsigned char *)keypad, sizeof(keypad)-1, nt,bc); strcpy(bc->keypad, keypad); } { - int sending_complete; - dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &sending_complete, nt,bc); + dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &bc->sending_complete, nt,bc); + } { int type, plan, present, screen, reason; char id[32]; - dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)setup, &type, &plan, &present, &screen, &reason, (unsigned char *)id, sizeof(id), nt,bc); + dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)setup, &type, &plan, &present, &screen, &reason, (unsigned char *)id, sizeof(id)-1, nt,bc); strcpy(bc->rad, id); bc->rnumplan=type; -// cb_log(3, bc->stack->port, " --> Redirecting number (REDIR_NR): '%s'\n", id); } { int coding, capability, mode, rate, multi, user, async, urate, stopbits, dbits, parity; dec_ie_bearer(setup->BEARER, (Q931_info_t *)setup, &coding, &capability, &mode, &rate, &multi, &user, &async, &urate, &stopbits, &dbits, &parity, nt,bc); switch (capability) { case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; -// cb_log(2, bc->stack->port, " --> cap -1 -> digital\n"); break; case 0: bc->capability=INFO_CAPABILITY_SPEECH; -// cb_log(2, bc->stack->port, " --> cap speech\n"); + break; + case 18: bc->capability=INFO_CAPABILITY_VIDEO; break; case 8: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; bc->user1 = user; - bc->async = async; bc->urate = urate; bc->rate = rate; bc->mode = mode; - -// cb_log(2, bc->stack->port, " --> cap unres Digital (user l1 %d, async %d, user rate %d\n", user, async, urate); break; case 9: bc->capability=INFO_CAPABILITY_DIGITAL_RESTRICTED; -// cb_log(2, bc->stack->port, " --> cap res Digital\n"); break; default: -// cb_log(2, bc->stack->port, " --> cap Else\n"); break; } - + switch(user) { case 2: bc->law=INFO_CODEC_ULAW; @@ -240,11 +246,8 @@ void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, { int exclusive, channel; dec_ie_channel_id(setup->CHANNEL_ID, (Q931_info_t *)setup, &exclusive, &channel, nt,bc); - if (channel==0xff) /* any channel */ - channel=-1; - - if (channel > 0) - bc->channel = channel; + + set_channel(bc,channel); } dec_ie_progress(setup->PROGRESS, (Q931_info_t *)setup, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc); @@ -260,12 +263,12 @@ msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) setup=(SETUP_t*)((msg->data+HEADER_LEN)); -// cb_log(2, bc->stack->port, " --> oad %s dad %s channel %d\n",bc->oad, bc->dad,bc->channel); if (bc->channel == 0 || bc->channel == ANY_CHANNEL || bc->channel==-1) enc_ie_channel_id(&setup->CHANNEL_ID, msg, 0, bc->channel, nt,bc); - else + else enc_ie_channel_id(&setup->CHANNEL_ID, msg, 1, bc->channel, nt,bc); - + + { int type=bc->onumplan,plan=1,present=bc->pres,screen=bc->screen; enc_ie_calling_pn(&setup->CALLING_PN, msg, type, plan, present, @@ -276,6 +279,13 @@ msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) if (bc->dad[0]) enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, nt,bc); } + + { + if (bc->rad[0]) + enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, nt,bc); + } + + if (*bc->display) { enc_ie_display(&setup->DISPLAY, msg, bc->display, nt,bc); @@ -299,6 +309,8 @@ msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) break; case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: capability = 8; user=-1; + mode=bc->mode; + rate=bc->rate; break; case INFO_CAPABILITY_DIGITAL_RESTRICTED: capability = 9; user=-1; @@ -318,19 +330,23 @@ msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) return msg; } -void print_setup (struct isdn_msg msgs[]) -{ -} - void parse_connect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; CONNECT_t *connect=(CONNECT_t*)((unsigned long)(msg->data+HEADER_LEN)); + int plan,pres,screen; + bc->ces = connect->ces; bc->ces = connect->ces; dec_ie_progress(connect->PROGRESS, (Q931_info_t *)connect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc); + + dec_ie_connected_pn(connect->CONNECT_PN,(Q931_info_t *)connect, &bc->cpnnumplan, &plan, &pres, &screen, bc->cad, 31, nt, bc); + + /* + cb_log(1,bc->port,"CONNETED PN: %s cpn_dialplan:%d\n", connected_pn, type); + */ #if DEBUG printf("Parsing CONNECT Msg\n"); @@ -341,7 +357,9 @@ msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; CONNECT_t *connect; msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | REQUEST, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_t) ,nt); - + + cb_log(6,bc->port,"BUILD_CONNECT: bc:%p bc->l3id:%d, nt:%d\n",bc,bc->l3_id,nt); + connect=(CONNECT_t*)((msg->data+HEADER_LEN)); if (nt) { @@ -351,8 +369,8 @@ msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) } { - int type=0, plan=1, present=2, screen=0; - enc_ie_connected_pn(&connect->CONNECT_PN, msg, type,plan, present, screen, (unsigned char*) bc->dad , nt , bc); + int type=bc->cpnnumplan, plan=1, present=2, screen=0; + enc_ie_connected_pn(&connect->CONNECT_PN, msg, type,plan, present, screen, (unsigned char*) bc->cad, nt , bc); } #if DEBUG @@ -360,10 +378,6 @@ msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_connect (struct isdn_msg msgs[]) -{ -} - void parse_setup_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -374,11 +388,8 @@ void parse_setup_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_b int exclusive, channel; dec_ie_channel_id(setup_acknowledge->CHANNEL_ID, (Q931_info_t *)setup_acknowledge, &exclusive, &channel, nt,bc); - if (channel==0xff) /* any channel */ - channel=-1; - if (channel > 0) - bc->channel = channel; + set_channel(bc, channel); } dec_ie_progress(setup_acknowledge->PROGRESS, (Q931_info_t *)setup_acknowledge, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc); @@ -407,10 +418,6 @@ msg_t *build_setup_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *b return msg; } -void print_setup_acknowledge (struct isdn_msg msgs[]) -{ -} - void parse_connect_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { #if DEBUG @@ -434,10 +441,6 @@ msg_t *build_connect_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel #endif return msg; } -void print_connect_acknowledge (struct isdn_msg msgs[]) -{ -} - void parse_user_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -460,10 +463,6 @@ msg_t *build_user_information (struct isdn_msg msgs[], struct misdn_bchannel *bc #endif return msg; } -void print_user_information (struct isdn_msg msgs[]) -{ -} - void parse_suspend_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -486,10 +485,6 @@ msg_t *build_suspend_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, #endif return msg; } -void print_suspend_reject (struct isdn_msg msgs[]) -{ -} - void parse_resume_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -512,10 +507,6 @@ msg_t *build_resume_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, i #endif return msg; } -void print_resume_reject (struct isdn_msg msgs[]) -{ -} - void parse_hold (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -538,10 +529,6 @@ msg_t *build_hold (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_hold (struct isdn_msg msgs[]) -{ -} - void parse_suspend (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -564,10 +551,6 @@ msg_t *build_suspend (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_suspend (struct isdn_msg msgs[]) -{ -} - void parse_resume (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -590,10 +573,6 @@ msg_t *build_resume (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_resume (struct isdn_msg msgs[]) -{ -} - void parse_hold_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -616,10 +595,6 @@ msg_t *build_hold_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc #endif return msg; } -void print_hold_acknowledge (struct isdn_msg msgs[]) -{ -} - void parse_suspend_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -642,10 +617,6 @@ msg_t *build_suspend_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel #endif return msg; } -void print_suspend_acknowledge (struct isdn_msg msgs[]) -{ -} - void parse_resume_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -668,10 +639,6 @@ msg_t *build_resume_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel * #endif return msg; } -void print_resume_acknowledge (struct isdn_msg msgs[]) -{ -} - void parse_hold_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -694,10 +661,6 @@ msg_t *build_hold_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int #endif return msg; } -void print_hold_reject (struct isdn_msg msgs[]) -{ -} - void parse_retrieve (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -720,10 +683,6 @@ msg_t *build_retrieve (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt #endif return msg; } -void print_retrieve (struct isdn_msg msgs[]) -{ -} - void parse_retrieve_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -747,10 +706,6 @@ msg_t *build_retrieve_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel #endif return msg; } -void print_retrieve_acknowledge (struct isdn_msg msgs[]) -{ -} - void parse_retrieve_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -773,10 +728,6 @@ msg_t *build_retrieve_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, #endif return msg; } -void print_retrieve_reject (struct isdn_msg msgs[]) -{ -} - void parse_disconnect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -809,10 +760,6 @@ msg_t *build_disconnect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int #endif return msg; } -void print_disconnect (struct isdn_msg msgs[]) -{ -} - void parse_restart (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -827,10 +774,10 @@ void parse_restart (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *b { int exclusive, channel; - dec_ie_channel_id(restart->CHANNEL_ID, (Q931_info_t *)restart, &exclusive, &channel, nt,bc); + dec_ie_channel_id(restart->CHANNEL_ID, (Q931_info_t *)restart, &exclusive, &bc->restart_channel, nt,bc); if (channel==0xff) /* any channel */ channel=-1; - cb_log(0, stack->port, "CC_RESTART Request on channel:%d on port:%d\n",stack->port); + cb_log(3, stack->port, "CC_RESTART Request on channel:%d on this port.\n"); } @@ -848,10 +795,6 @@ msg_t *build_restart (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_restart (struct isdn_msg msgs[]) -{ -} - void parse_release (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -874,18 +817,14 @@ msg_t *build_release (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) release=(RELEASE_t*)((msg->data+HEADER_LEN)); - - enc_ie_cause(&release->CAUSE, msg, nt?1:0, bc->out_cause, nt,bc); + if (bc->out_cause>= 0) + enc_ie_cause(&release->CAUSE, msg, nt?1:0, bc->out_cause, nt,bc); #if DEBUG printf("Building RELEASE Msg\n"); #endif return msg; } -void print_release (struct isdn_msg msgs[]) -{ -} - void parse_release_complete (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -895,35 +834,30 @@ void parse_release_complete (struct isdn_msg msgs[], msg_t *msg, struct misdn_bc iframe_t *frm = (iframe_t*) msg->data; struct misdn_stack *stack=get_stack_by_bc(bc); - -#ifdef MISDNUSER_JOLLY mISDNuser_head_t *hh; hh=(mISDNuser_head_t*)msg->data; -#else - mISDN_head_t *hh; - hh=(mISDN_head_t*)msg->data; -#endif - + + /*hh=(mISDN_head_t*)msg->data; + mISDN_head_t *hh;*/ + if (nt) { if (hh->prim == (CC_RELEASE_COMPLETE|CONFIRM)) { - cb_log(0, stack->port, "CC_RELEASE_COMPLETE|CONFIRM [NT] port:%d\n",stack->port); + cb_log(0, stack->port, "CC_RELEASE_COMPLETE|CONFIRM [NT] \n"); return; } } else { if (frm->prim == (CC_RELEASE_COMPLETE|CONFIRM)) { - cb_log(0, stack->port, "CC_RELEASE_COMPLETE|CONFIRM [TE] port:%d\n",stack->port); + cb_log(0, stack->port, "CC_RELEASE_COMPLETE|CONFIRM [TE] \n"); return; } } dec_ie_cause(release_complete->CAUSE, (Q931_info_t *)(release_complete), &location, &bc->cause, nt,bc); - #if DEBUG printf("Parsing RELEASE_COMPLETE Msg\n"); #endif - - } + msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -939,31 +873,26 @@ msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc #endif return msg; } -void print_release_complete (struct isdn_msg msgs[]) -{ -} - void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { +//#define FACILITY_DECODE +#ifdef FACILITY_DECODE 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); - #if DEBUG printf("Parsing FACILITY Msg\n"); #endif { - char fac[128]; - int facility_len; - - dec_ie_facility(facility->FACILITY, qi, fac, &facility_len, nt, bc); + fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc); } - - +#endif + } + msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -977,17 +906,9 @@ msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt printf("Sending %s as Display\n", bc->display); enc_ie_display(&facility->DISPLAY, msg, bc->display, nt,bc); } - - switch ( bc->facility ) { - case FACILITY_CALLDEFLECT: - enc_facility_calldeflect(&facility->FACILITY, msg, bc->facility_calldeflect_nr, nt, bc); - - break; - case FACILITY_NONE: - break; - } + fac_enc(&facility->FACILITY, msg, bc->out_fac_type, bc->out_fac, bc); } @@ -996,19 +917,14 @@ msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt #endif return msg; } -void print_facility (struct isdn_msg msgs[]) -{ -} - void parse_notify (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { #if DEBUG printf("Parsing NOTIFY Msg\n"); #endif - - } + msg_t *build_notify (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -1022,19 +938,14 @@ msg_t *build_notify (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_notify (struct isdn_msg msgs[]) -{ -} - void parse_status_enquiry (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { #if DEBUG printf("Parsing STATUS_ENQUIRY Msg\n"); #endif - - } + msg_t *build_status_enquiry (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -1048,32 +959,25 @@ msg_t *build_status_enquiry (struct isdn_msg msgs[], struct misdn_bchannel *bc, #endif return msg; } -void print_status_enquiry (struct isdn_msg msgs[]) -{ -} - void parse_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; INFORMATION_t *information=(INFORMATION_t*)((unsigned long)(msg->data+HEADER_LEN)); - { int type, plan; char number[32]; char keypad[32]; - dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *)information, &type, &plan, (unsigned char *)number, sizeof(number), nt,bc); - dec_ie_keypad(information->KEYPAD, (Q931_info_t *)information, (unsigned char *)keypad, sizeof(keypad), nt,bc); + dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *)information, &type, &plan, (unsigned char *)number, sizeof(number)-1, nt, bc); + dec_ie_keypad(information->KEYPAD, (Q931_info_t *)information, (unsigned char *)keypad, sizeof(keypad)-1, nt, bc); strcpy(bc->info_dad, number); strcpy(bc->keypad,keypad); - } #if DEBUG printf("Parsing INFORMATION Msg\n"); #endif - - } + msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -1098,10 +1002,6 @@ msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int #endif return msg; } -void print_information (struct isdn_msg msgs[]) -{ -} - void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { @@ -1115,9 +1015,8 @@ void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc #if DEBUG printf("Parsing STATUS Msg\n"); #endif - - } + msg_t *build_status (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -1131,19 +1030,14 @@ msg_t *build_status (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_status (struct isdn_msg msgs[]) -{ -} - void parse_timeout (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { #if DEBUG printf("Parsing STATUS Msg\n"); -#endif - - +#endif } + msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) { int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; @@ -1157,9 +1051,6 @@ msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) #endif return msg; } -void print_timeout (struct isdn_msg msgs[]) -{ -} /************************************/ @@ -1171,96 +1062,96 @@ void print_timeout (struct isdn_msg msgs[]) struct isdn_msg msgs_g[] = { {CC_PROCEEDING,L3,EVENT_PROCEEDING, - parse_proceeding,build_proceeding,print_proceeding, + parse_proceeding,build_proceeding, "PROCEEDING"}, {CC_ALERTING,L3,EVENT_ALERTING, - parse_alerting,build_alerting,print_alerting, + parse_alerting,build_alerting, "ALERTING"}, {CC_PROGRESS,L3,EVENT_PROGRESS, - parse_progress,build_progress,print_progress, + parse_progress,build_progress, "PROGRESS"}, {CC_SETUP,L3,EVENT_SETUP, - parse_setup,build_setup,print_setup, + parse_setup,build_setup, "SETUP"}, {CC_CONNECT,L3,EVENT_CONNECT, - parse_connect,build_connect,print_connect, + parse_connect,build_connect, "CONNECT"}, {CC_SETUP_ACKNOWLEDGE,L3,EVENT_SETUP_ACKNOWLEDGE, - parse_setup_acknowledge,build_setup_acknowledge,print_setup_acknowledge, + parse_setup_acknowledge,build_setup_acknowledge, "SETUP_ACKNOWLEDGE"}, {CC_CONNECT_ACKNOWLEDGE ,L3,EVENT_CONNECT_ACKNOWLEDGE , - parse_connect_acknowledge ,build_connect_acknowledge ,print_connect_acknowledge , + parse_connect_acknowledge ,build_connect_acknowledge, "CONNECT_ACKNOWLEDGE "}, {CC_USER_INFORMATION,L3,EVENT_USER_INFORMATION, - parse_user_information,build_user_information,print_user_information, + parse_user_information,build_user_information, "USER_INFORMATION"}, {CC_SUSPEND_REJECT,L3,EVENT_SUSPEND_REJECT, - parse_suspend_reject,build_suspend_reject,print_suspend_reject, + parse_suspend_reject,build_suspend_reject, "SUSPEND_REJECT"}, {CC_RESUME_REJECT,L3,EVENT_RESUME_REJECT, - parse_resume_reject,build_resume_reject,print_resume_reject, + parse_resume_reject,build_resume_reject, "RESUME_REJECT"}, {CC_HOLD,L3,EVENT_HOLD, - parse_hold,build_hold,print_hold, + parse_hold,build_hold, "HOLD"}, {CC_SUSPEND,L3,EVENT_SUSPEND, - parse_suspend,build_suspend,print_suspend, + parse_suspend,build_suspend, "SUSPEND"}, {CC_RESUME,L3,EVENT_RESUME, - parse_resume,build_resume,print_resume, + parse_resume,build_resume, "RESUME"}, {CC_HOLD_ACKNOWLEDGE,L3,EVENT_HOLD_ACKNOWLEDGE, - parse_hold_acknowledge,build_hold_acknowledge,print_hold_acknowledge, + parse_hold_acknowledge,build_hold_acknowledge, "HOLD_ACKNOWLEDGE"}, {CC_SUSPEND_ACKNOWLEDGE,L3,EVENT_SUSPEND_ACKNOWLEDGE, - parse_suspend_acknowledge,build_suspend_acknowledge,print_suspend_acknowledge, + parse_suspend_acknowledge,build_suspend_acknowledge, "SUSPEND_ACKNOWLEDGE"}, {CC_RESUME_ACKNOWLEDGE,L3,EVENT_RESUME_ACKNOWLEDGE, - parse_resume_acknowledge,build_resume_acknowledge,print_resume_acknowledge, + parse_resume_acknowledge,build_resume_acknowledge, "RESUME_ACKNOWLEDGE"}, {CC_HOLD_REJECT,L3,EVENT_HOLD_REJECT, - parse_hold_reject,build_hold_reject,print_hold_reject, + parse_hold_reject,build_hold_reject, "HOLD_REJECT"}, {CC_RETRIEVE,L3,EVENT_RETRIEVE, - parse_retrieve,build_retrieve,print_retrieve, + parse_retrieve,build_retrieve, "RETRIEVE"}, {CC_RETRIEVE_ACKNOWLEDGE,L3,EVENT_RETRIEVE_ACKNOWLEDGE, - parse_retrieve_acknowledge,build_retrieve_acknowledge,print_retrieve_acknowledge, + parse_retrieve_acknowledge,build_retrieve_acknowledge, "RETRIEVE_ACKNOWLEDGE"}, {CC_RETRIEVE_REJECT,L3,EVENT_RETRIEVE_REJECT, - parse_retrieve_reject,build_retrieve_reject,print_retrieve_reject, + parse_retrieve_reject,build_retrieve_reject, "RETRIEVE_REJECT"}, {CC_DISCONNECT,L3,EVENT_DISCONNECT, - parse_disconnect,build_disconnect,print_disconnect, + parse_disconnect,build_disconnect, "DISCONNECT"}, {CC_RESTART,L3,EVENT_RESTART, - parse_restart,build_restart,print_restart, + parse_restart,build_restart, "RESTART"}, {CC_RELEASE,L3,EVENT_RELEASE, - parse_release,build_release,print_release, + parse_release,build_release, "RELEASE"}, {CC_RELEASE_COMPLETE,L3,EVENT_RELEASE_COMPLETE, - parse_release_complete,build_release_complete,print_release_complete, + parse_release_complete,build_release_complete, "RELEASE_COMPLETE"}, {CC_FACILITY,L3,EVENT_FACILITY, - parse_facility,build_facility,print_facility, + parse_facility,build_facility, "FACILITY"}, {CC_NOTIFY,L3,EVENT_NOTIFY, - parse_notify,build_notify,print_notify, + parse_notify,build_notify, "NOTIFY"}, {CC_STATUS_ENQUIRY,L3,EVENT_STATUS_ENQUIRY, - parse_status_enquiry,build_status_enquiry,print_status_enquiry, + parse_status_enquiry,build_status_enquiry, "STATUS_ENQUIRY"}, {CC_INFORMATION,L3,EVENT_INFORMATION, - parse_information,build_information,print_information, + parse_information,build_information, "INFORMATION"}, {CC_STATUS,L3,EVENT_STATUS, - parse_status,build_status,print_status, + parse_status,build_status, "STATUS"}, {CC_TIMEOUT,L3,EVENT_TIMEOUT, - parse_timeout,build_timeout,print_timeout, + parse_timeout,build_timeout, "TIMEOUT"}, - {0,0,0,NULL,NULL,NULL,NULL} + {0,0,0,NULL,NULL,NULL} }; #define msgs_max (sizeof(msgs_g)/sizeof(struct isdn_msg)) @@ -1271,15 +1162,12 @@ int isdn_msg_get_index(struct isdn_msg msgs[], msg_t *msg, int nt) int i; if (nt){ -#ifdef MISDNUSER_JOLLY mISDNuser_head_t *hh = (mISDNuser_head_t*)msg->data; -#else - mISDN_head_t *hh = (mISDN_head_t*)msg->data; -#endif - - for (i=0; i< msgs_max -1; i++) + + for (i=0; i< msgs_max -1; i++) { if ( (hh->prim&COMMAND_MASK)==(msgs[i].misdn_msg&COMMAND_MASK)) return i; - + } + } else { iframe_t *frm = (iframe_t*)msg->data; @@ -1296,7 +1184,7 @@ int isdn_msg_get_index_by_event(struct isdn_msg msgs[], enum event_e event, int for (i=0; i< msgs_max; i++) if ( event == msgs[i].event) return i; - cb_log(4,0, "get_index: EVENT NOT FOUND!!\n"); + cb_log(10,0, "get_index: event not found!\n"); return -1; } @@ -1320,7 +1208,10 @@ char EVENT_CLEAN_INFO[] = "CLEAN_UP"; char EVENT_DTMF_TONE_INFO[] = "DTMF_TONE"; char EVENT_NEW_L3ID_INFO[] = "NEW_L3ID"; char EVENT_NEW_BC_INFO[] = "NEW_BC"; +char EVENT_PORT_ALARM_INFO[] = "ALARM"; char EVENT_BCHAN_DATA_INFO[] = "BCHAN_DATA"; +char EVENT_BCHAN_ACTIVATED_INFO[] = "BCHAN_ACTIVATED"; +char EVENT_TONE_GENERATE_INFO[] = "TONE_GENERATE"; char * isdn_get_info(struct isdn_msg msgs[], enum event_e event, int nt) { @@ -1333,6 +1224,9 @@ char * isdn_get_info(struct isdn_msg msgs[], enum event_e event, int nt) if (event == EVENT_NEW_L3ID) return EVENT_NEW_L3ID_INFO; if (event == EVENT_NEW_BC) return EVENT_NEW_BC_INFO; if (event == EVENT_BCHAN_DATA) return EVENT_BCHAN_DATA_INFO; + if (event == EVENT_BCHAN_ACTIVATED) return EVENT_BCHAN_ACTIVATED_INFO; + if (event == EVENT_TONE_GENERATE) return EVENT_TONE_GENERATE_INFO; + if (event == EVENT_PORT_ALARM) return EVENT_PORT_ALARM_INFO; return NULL; } diff --git a/channels/misdn/mISDN.patch b/channels/misdn/mISDN.patch deleted file mode 100644 index ccc8ae4b2..000000000 --- a/channels/misdn/mISDN.patch +++ /dev/null @@ -1,2500 +0,0 @@ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/arith.h mISDN/drivers/isdn/hardware/mISDN/arith.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/arith.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/arith.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,347 @@ -+#ifndef _ZAPTEL_ARITH_H -+#define _ZAPTEL_ARITH_H -+/* -+ * Handy add/subtract functions to operate on chunks of shorts. -+ * Feel free to add customizations for additional architectures -+ * -+ */ -+ -+#ifdef CONFIG_ZAPTEL_MMX -+#ifdef ZT_CHUNKSIZE -+static inline void __ACSS(volatile short *dst, const short *src) -+{ -+ __asm__ __volatile__ ( -+ "movq 0(%0), %%mm0;\n" -+ "movq 0(%1), %%mm1;\n" -+ "movq 8(%0), %%mm2;\n" -+ "movq 8(%1), %%mm3;\n" -+ "paddsw %%mm1, %%mm0;\n" -+ "paddsw %%mm3, %%mm2;\n" -+ "movq %%mm0, 0(%0);\n" -+ "movq %%mm2, 8(%0);\n" -+ : "=r" (dst) -+ : "r" (src), "0" (dst) -+ : "memory" -+#if CLOBBERMMX -+ , "%mm0", "%mm1", "%mm2", "%mm3" -+#endif -+ ); -+ -+} -+static inline void __SCSS(volatile short *dst, const short *src) -+{ -+ __asm__ __volatile__ ( -+ "movq 0(%0), %%mm0;\n" -+ "movq 0(%1), %%mm1;\n" -+ "movq 8(%0), %%mm2;\n" -+ "movq 8(%1), %%mm3;\n" -+ "psubsw %%mm1, %%mm0;\n" -+ "psubsw %%mm3, %%mm2;\n" -+ "movq %%mm0, 0(%0);\n" -+ "movq %%mm2, 8(%0);\n" -+ : "=r" (dst) -+ : "r" (src), "0" (dst) -+ : "memory" -+#if CLOBBERMMX -+ , "%mm0", "%mm1", "%mm2", "%mm3" -+#endif -+ ); -+ -+} -+ -+#if (ZT_CHUNKSIZE == 8) -+#define ACSS(a,b) __ACSS(a,b) -+#define SCSS(a,b) __SCSS(a,b) -+#elif (ZT_CHUNKSIZE > 8) -+static inline void ACSS(volatile short *dst, const short *src) -+{ -+ int x; -+ for (x=0;x<ZT_CHUNKSIZE;x+=8) -+ __ACSS(dst + x, src + x); -+} -+static inline void SCSS(volatile short *dst, const short *src) -+{ -+ int x; -+ for (x=0;x<ZT_CHUNKSIZE;x+=8) -+ __SCSS(dst + x, src + x); -+} -+#else -+#error No MMX for ZT_CHUNKSIZE < 8 -+#endif -+#endif -+static inline int CONVOLVE(const int *coeffs, const short *hist, int len) -+{ -+ int sum; -+ /* Divide length by 16 */ -+ len >>= 4; -+ -+ /* Clear our accumulator, mm4 */ -+ -+ /* -+ -+ For every set of eight... -+ -+ Load 16 coefficients into four registers... -+ Shift each word right 16 to make them shorts... -+ Pack the resulting shorts into two registers... -+ With the coefficients now in mm0 and mm2, load the -+ history into mm1 and mm3... -+ Multiply/add mm1 into mm0, and mm3 into mm2... -+ Add mm2 into mm0 (without saturation, alas). Now we have two half-results. -+ Accumulate in mm4 (again, without saturation, alas) -+ */ -+ __asm__ ( -+ "pxor %%mm4, %%mm4;\n" -+ "mov %1, %%edi;\n" -+ "mov %2, %%esi;\n" -+ "mov %3, %%ecx;\n" -+ "1:" -+ "movq 0(%%edi), %%mm0;\n" -+ "movq 8(%%edi), %%mm1;\n" -+ "movq 16(%%edi), %%mm2;\n" -+ "movq 24(%%edi), %%mm3;\n" -+ /* can't use 4/5 since 4 is the accumulator for us */ -+ "movq 32(%%edi), %%mm6;\n" -+ "movq 40(%%edi), %%mm7;\n" -+ "psrad $16, %%mm0;\n" -+ "psrad $16, %%mm1;\n" -+ "psrad $16, %%mm2;\n" -+ "psrad $16, %%mm3;\n" -+ "psrad $16, %%mm6;\n" -+ "psrad $16, %%mm7;\n" -+ "packssdw %%mm1, %%mm0;\n" -+ "packssdw %%mm3, %%mm2;\n" -+ "packssdw %%mm7, %%mm6;\n" -+ "movq 0(%%esi), %%mm1;\n" -+ "movq 8(%%esi), %%mm3;\n" -+ "movq 16(%%esi), %%mm7;\n" -+ "pmaddwd %%mm1, %%mm0;\n" -+ "pmaddwd %%mm3, %%mm2;\n" -+ "pmaddwd %%mm7, %%mm6;\n" -+ "paddd %%mm6, %%mm4;\n" -+ "paddd %%mm2, %%mm4;\n" -+ "paddd %%mm0, %%mm4;\n" -+ /* Come back and do for the last few bytes */ -+ "movq 48(%%edi), %%mm6;\n" -+ "movq 56(%%edi), %%mm7;\n" -+ "psrad $16, %%mm6;\n" -+ "psrad $16, %%mm7;\n" -+ "packssdw %%mm7, %%mm6;\n" -+ "movq 24(%%esi), %%mm7;\n" -+ "pmaddwd %%mm7, %%mm6;\n" -+ "paddd %%mm6, %%mm4;\n" -+ "add $64, %%edi;\n" -+ "add $32, %%esi;\n" -+ "dec %%ecx;\n" -+ "jnz 1b;\n" -+ "movq %%mm4, %%mm0;\n" -+ "psrlq $32, %%mm0;\n" -+ "paddd %%mm0, %%mm4;\n" -+ "movd %%mm4, %0;\n" -+ : "=r" (sum) -+ : "r" (coeffs), "r" (hist), "r" (len) -+ : "%ecx", "%edi", "%esi" -+ ); -+ -+ return sum; -+} -+ -+static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps) -+{ -+ int i; -+ int correction; -+ for (i=0;i<ntaps;i++) { -+ correction = history[i] * nsuppr; -+ taps[i] += correction; -+ } -+} -+ -+static inline void UPDATE2(volatile int *taps, volatile short *taps_short, const short *history, const int nsuppr, const int ntaps) -+{ -+ int i; -+ int correction; -+#if 0 -+ ntaps >>= 4; -+ /* First, load up taps, */ -+ __asm__ ( -+ "pxor %%mm4, %%mm4;\n" -+ "mov %0, %%edi;\n" -+ "mov %1, %%esi;\n" -+ "mov %3, %%ecx;\n" -+ "1:" -+ "jnz 1b;\n" -+ "movq %%mm4, %%mm0;\n" -+ "psrlq $32, %%mm0;\n" -+ "paddd %%mm0, %%mm4;\n" -+ "movd %%mm4, %0;\n" -+ : "=r" (taps), "=r" (taps_short) -+ : "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps) -+ : "%ecx", "%edi", "%esi" -+ ); -+#endif -+#if 1 -+ for (i=0;i<ntaps;i++) { -+ correction = history[i] * nsuppr; -+ taps[i] += correction; -+ taps_short[i] = taps[i] >> 16; -+ } -+#endif -+} -+ -+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len) -+{ -+ int sum; -+ /* Divide length by 16 */ -+ len >>= 4; -+ -+ /* Clear our accumulator, mm4 */ -+ -+ /* -+ -+ For every set of eight... -+ Load in eight coefficients and eight historic samples, multliply add and -+ accumulate the result -+ */ -+ __asm__ ( -+ "pxor %%mm4, %%mm4;\n" -+ "mov %1, %%edi;\n" -+ "mov %2, %%esi;\n" -+ "mov %3, %%ecx;\n" -+ "1:" -+ "movq 0(%%edi), %%mm0;\n" -+ "movq 8(%%edi), %%mm2;\n" -+ "movq 0(%%esi), %%mm1;\n" -+ "movq 8(%%esi), %%mm3;\n" -+ "pmaddwd %%mm1, %%mm0;\n" -+ "pmaddwd %%mm3, %%mm2;\n" -+ "paddd %%mm2, %%mm4;\n" -+ "paddd %%mm0, %%mm4;\n" -+ "movq 16(%%edi), %%mm0;\n" -+ "movq 24(%%edi), %%mm2;\n" -+ "movq 16(%%esi), %%mm1;\n" -+ "movq 24(%%esi), %%mm3;\n" -+ "pmaddwd %%mm1, %%mm0;\n" -+ "pmaddwd %%mm3, %%mm2;\n" -+ "paddd %%mm2, %%mm4;\n" -+ "paddd %%mm0, %%mm4;\n" -+ "add $32, %%edi;\n" -+ "add $32, %%esi;\n" -+ "dec %%ecx;\n" -+ "jnz 1b;\n" -+ "movq %%mm4, %%mm0;\n" -+ "psrlq $32, %%mm0;\n" -+ "paddd %%mm0, %%mm4;\n" -+ "movd %%mm4, %0;\n" -+ : "=r" (sum) -+ : "r" (coeffs), "r" (hist), "r" (len) -+ : "%ecx", "%edi", "%esi" -+ ); -+ -+ return sum; -+} -+static inline short MAX16(const short *y, int len, int *pos) -+{ -+ int k; -+ short max = 0; -+ int bestpos = 0; -+ for (k=0;k<len;k++) { -+ if (max < y[k]) { -+ bestpos = k; -+ max = y[k]; -+ } -+ } -+ *pos = (len - 1 - bestpos); -+ return max; -+} -+ -+ -+ -+#else -+ -+#ifdef ZT_CHUNKSIZE -+static inline void ACSS(short *dst, short *src) -+{ -+ int x,sum; -+ /* Add src to dst with saturation, storing in dst */ -+ for (x=0;x<ZT_CHUNKSIZE;x++) { -+ sum = dst[x]+src[x]; -+ if (sum > 32767) -+ sum = 32767; -+ else if (sum < -32768) -+ sum = -32768; -+ dst[x] = sum; -+ } -+} -+ -+static inline void SCSS(short *dst, short *src) -+{ -+ int x,sum; -+ /* Add src to dst with saturation, storing in dst */ -+ for (x=0;x<ZT_CHUNKSIZE;x++) { -+ sum = dst[x]-src[x]; -+ if (sum > 32767) -+ sum = 32767; -+ else if (sum < -32768) -+ sum = -32768; -+ dst[x] = sum; -+ } -+} -+ -+#endif /* ZT_CHUNKSIZE */ -+ -+static inline int CONVOLVE(const int *coeffs, const short *hist, int len) -+{ -+ int x; -+ int sum = 0; -+ for (x=0;x<len;x++) -+ sum += (coeffs[x] >> 16) * hist[x]; -+ return sum; -+} -+ -+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len) -+{ -+ int x; -+ int sum = 0; -+ for (x=0;x<len;x++) -+ sum += coeffs[x] * hist[x]; -+ return sum; -+} -+ -+static inline void UPDATE(int *taps, const short *history, const int nsuppr, const int ntaps) -+{ -+ int i; -+ int correction; -+ for (i=0;i<ntaps;i++) { -+ correction = history[i] * nsuppr; -+ taps[i] += correction; -+ } -+} -+ -+static inline void UPDATE2(int *taps, short *taps_short, const short *history, const int nsuppr, const int ntaps) -+{ -+ int i; -+ int correction; -+ for (i=0;i<ntaps;i++) { -+ correction = history[i] * nsuppr; -+ taps[i] += correction; -+ taps_short[i] = taps[i] >> 16; -+ } -+} -+ -+static inline short MAX16(const short *y, int len, int *pos) -+{ -+ int k; -+ short max = 0; -+ int bestpos = 0; -+ for (k=0;k<len;k++) { -+ if (max < y[k]) { -+ bestpos = k; -+ max = y[k]; -+ } -+ } -+ *pos = (len - 1 - bestpos); -+ return max; -+} -+ -+#endif /* MMX */ -+#endif /* _ZAPTEL_ARITH_H */ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/biquad.h mISDN/drivers/isdn/hardware/mISDN/biquad.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/biquad.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/biquad.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,73 @@ -+/* -+ * SpanDSP - a series of DSP components for telephony -+ * -+ * biquad.h - General telephony bi-quad section routines (currently this just -+ * handles canonic/type 2 form) -+ * -+ * Written by Steve Underwood <steveu@coppice.org> -+ * -+ * Copyright (C) 2001 Steve Underwood -+ * -+ * All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+typedef struct -+{ -+ int32_t gain; -+ int32_t a1; -+ int32_t a2; -+ int32_t b1; -+ int32_t b2; -+ -+ int32_t z1; -+ int32_t z2; -+} biquad2_state_t; -+ -+static inline void biquad2_init (biquad2_state_t *bq, -+ int32_t gain, -+ int32_t a1, -+ int32_t a2, -+ int32_t b1, -+ int32_t b2) -+{ -+ bq->gain = gain; -+ bq->a1 = a1; -+ bq->a2 = a2; -+ bq->b1 = b1; -+ bq->b2 = b2; -+ -+ bq->z1 = 0; -+ bq->z2 = 0; -+} -+/*- End of function --------------------------------------------------------*/ -+ -+static inline int16_t biquad2 (biquad2_state_t *bq, int16_t sample) -+{ -+ int32_t y; -+ int32_t z0; -+ -+ z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; -+ y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; -+ -+ bq->z2 = bq->z1; -+ bq->z1 = z0 >> 15; -+ y >>= 15; -+ return y; -+} -+/*- End of function --------------------------------------------------------*/ -+/*- End of file ------------------------------------------------------------*/ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,390 @@ -+/* $Id$ -+ * -+ * Simple but fast Echo cancellation for mISDN_dsp. -+ * -+ * Copyright Andreas Eversberg (jolly@jolly.de) -+ * -+ * This software may be used and distributed according to the terms -+ * of the GNU General Public License, incorporated herein by reference. -+ * -+ */ -+ -+#include "layer1.h" -+#include "helper.h" -+#include "debug.h" -+#include "dsp.h" -+ -+ -+/* -+ * how this works: -+ * -+ * -+ * -+ */ -+void bchdev_echocancel_chunk(dsp_t* dev, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size); -+int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int train); -+void bchdev_echocancel_deactivate(dsp_t* dev); -+ -+ -+ -+ -+ -+ -+static char flip_table[256]; -+ -+void dsp_cancel_init_flip_bits() -+{ -+ int i,k; -+ -+ for (i = 0 ; i < 256 ; i++) { -+ unsigned char sample = 0 ; -+ for (k = 0; k<8; k++) { -+ if ( i & 1 << k ) sample |= 0x80 >> k; -+ } -+ flip_table[i] = sample; -+ } -+} -+ -+static unsigned char * flip_buf_bits ( unsigned char * buf , int len) -+{ -+ int i; -+ char * start = buf; -+ -+ for (i = 0 ; i < len; i++) { -+ buf[i] = flip_table[buf[i]]; -+ } -+ -+ return start; -+} -+ -+ -+ -+void -+dsp_cancel_tx(dsp_t *dsp, u8 *data, int len) -+{ -+ if (!dsp ) return ; -+ if (!data) return; -+ -+ if (dsp->txbuflen + len < ECHOCAN_BUFLEN) { -+ memcpy(&dsp->txbuf[dsp->txbuflen],data,len); -+ dsp->txbuflen+=len; -+ } else { -+ printk("ECHOCAN: TXBUF Overflow len:%d newlen:%d\n",dsp->txbuflen,len); -+ dsp->txbuflen=0; -+ } -+ -+} -+ -+void -+dsp_cancel_rx(dsp_t *dsp, u8 *data, int len) -+{ -+ if (!dsp ) return ; -+ if (!data) return; -+ -+ if (len <= dsp->txbuflen) { -+ char tmp[ECHOCAN_BUFLEN]; -+ -+ int delta=dsp->txbuflen-len; -+ -+ memcpy(tmp,&dsp->txbuf[len],delta); -+ -+ flip_buf_bits(data,len); -+ flip_buf_bits(dsp->txbuf,len); -+ bchdev_echocancel_chunk(dsp, data, dsp->txbuf, len); -+ flip_buf_bits(data,len); -+ -+ memcpy(dsp->txbuf,tmp,delta); -+ dsp->txbuflen=delta; -+ //dsp->txbuflen=0; -+ -+ //bchdev_echocancel_chunk(dsp, dsp->txbuf, data, len); -+ } else { -+ printk("ECHOCAN: TXBUF Underrun len:%d newlen:%d\n",dsp->txbuflen,len); -+ } -+ -+} -+ -+int -+dsp_cancel_init(dsp_t *dsp, int deftaps, int training, int delay) -+{ -+ -+ if (!dsp) return -1; -+ -+ printk("DSP_CANCEL_INIT called\n"); -+ -+ if (delay < 0) -+ { -+ printk("Disabling EC\n"); -+ dsp->cancel_enable = 0; -+ -+ dsp->txbuflen=0; -+ -+ bchdev_echocancel_deactivate(dsp); -+ -+ return(0); -+ } -+ -+ dsp->txbuflen=0; -+ dsp->rxbuflen=0; -+ -+ -+ bchdev_echocancel_activate(dsp,deftaps, training); -+ -+ printk("Enabling EC\n"); -+ dsp->cancel_enable = 1; -+ return(0); -+} -+ -+ -+ -+ -+ -+/*****************************************************/ -+#define __ECHO_STATE_MUTE (1 << 8) -+#define ECHO_STATE_IDLE (0) -+#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_ACTIVE (5) -+ -+#define AMI_MASK 0x55 -+ -+ -+static unsigned char linear2alaw (short linear) -+{ -+ int mask; -+ int seg; -+ int pcm_val; -+ static int seg_end[8] = -+ { -+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF -+ }; -+ -+ pcm_val = linear; -+ if (pcm_val >= 0) -+ { -+ /* Sign (7th) bit = 1 */ -+ mask = AMI_MASK | 0x80; -+ } -+ else -+ { -+ /* Sign bit = 0 */ -+ mask = AMI_MASK; -+ pcm_val = -pcm_val; -+ } -+ -+ /* Convert the scaled magnitude to segment number. */ -+ for (seg = 0; seg < 8; seg++) -+ { -+ if (pcm_val <= seg_end[seg]) -+ break; -+ } -+ /* Combine the sign, segment, and quantization bits. */ -+ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; -+} -+ -+/*- End of function --------------------------------------------------------*/ -+ -+static short int alaw2linear (uint8_t alaw) -+{ -+ int i; -+ int seg; -+ -+ alaw ^= AMI_MASK; -+ i = ((alaw & 0x0F) << 4); -+ seg = (((int) alaw & 0x70) >> 4); -+ if (seg) -+ i = (i + 0x100) << (seg - 1); -+ return (short int) ((alaw & 0x80) ? i : -i); -+} -+ -+ -+/** @return string of given echo cancellation state */ -+char* bchdev_echocancel_statestr(uint16_t state) -+{ -+ switch(state) { -+ case ECHO_STATE_IDLE: -+ return "idle"; -+ break; -+ case ECHO_STATE_PRETRAINING: -+ return "pre-training"; -+ break; -+ case ECHO_STATE_STARTTRAINING: -+ return "transmit impulse"; -+ break; -+ case ECHO_STATE_AWAITINGECHO: -+ return "awaiting echo"; -+ break; -+ case ECHO_STATE_TRAINING: -+ return "training start"; -+ break; -+ case ECHO_STATE_ACTIVE: -+ return "training finished"; -+ break; -+ default: -+ return "unknown"; -+ } -+} -+ -+/** Changes state of echo cancellation to given state */ -+void bchdev_echocancel_setstate(dsp_t* dev, uint16_t state) -+{ -+ char* statestr = bchdev_echocancel_statestr(state); -+ -+ printk("bchdev: echo cancel state %d (%s)\n", state & 0xff, statestr); -+ if (state == ECHO_STATE_ACTIVE) -+ printk("bchdev: %d taps trained\n", dev->echolastupdate); -+ dev->echostate = state; -+} -+ -+static int buf_size=0; -+static int ec_timer=2000; -+//static int ec_timer=1000; -+ -+ -+/** Activates echo cancellation for the given bch_dev, device must have been locked before! */ -+int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int training) -+{ -+ int taps; -+ -+ if (! dev) return -EINVAL; -+ -+ if (dev->ec && dev->ecdis_rd && dev->ecdis_wr) { -+ // already active -+ return 0; -+ } -+ -+ if (deftaps>0) { -+ taps=deftaps; -+ } else { -+ taps=128; -+ } -+ -+ -+ switch (buf_size) { -+ case 0: taps += 0; break; -+ case 1: taps += 256-128; break; -+ case 2: taps += 512-128; break; -+ default: taps += 1024-128; -+ } -+ -+ if (!dev->ec) dev->ec = echo_can_create(taps, 0); -+ if (!dev->ec) { -+ return -ENOMEM; -+ } -+ -+ dev->echolastupdate = 0; -+ -+ if (!training) { -+ dev->echotimer=0; -+ bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE); -+ } else { -+ if (training<10) -+ training= ec_timer; -+ -+ dev->echotimer = training; -+ bchdev_echocancel_setstate(dev, ECHO_STATE_PRETRAINING); -+ -+ } -+ -+ if (!dev->ecdis_rd) dev->ecdis_rd = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_KERNEL); -+ if (!dev->ecdis_rd) { -+ kfree(dev->ec); dev->ec = NULL; -+ return -ENOMEM; -+ } -+ echo_can_disable_detector_init(dev->ecdis_rd); -+ -+ if (!dev->ecdis_wr) dev->ecdis_wr = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_KERNEL); -+ if (!dev->ecdis_wr) { -+ kfree(dev->ec); dev->ec = NULL; -+ kfree(dev->ecdis_rd); dev->ecdis_rd = NULL; -+ return -ENOMEM; -+ } -+ echo_can_disable_detector_init(dev->ecdis_wr); -+ -+ return 0; -+} -+ -+/** Deactivates echo cancellation for the given bch_dev, device must have been locked before! */ -+void bchdev_echocancel_deactivate(dsp_t* dev) -+{ -+ if (! dev) return; -+ -+ //chan_misdn_log("bchdev: deactivating echo cancellation on port=%04x, chan=%02x\n", dev->stack->port, dev->channel); -+ -+ if (dev->ec) echo_can_free(dev->ec); -+ dev->ec = NULL; -+ -+ dev->echolastupdate = 0; -+ dev->echotimer = 0; -+ bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE); -+ -+ if (dev->ecdis_rd) kfree(dev->ecdis_rd); -+ dev->ecdis_rd = NULL; -+ -+ if (dev->ecdis_wr) kfree(dev->ecdis_wr); -+ dev->ecdis_wr = NULL; -+} -+ -+/** Processes one TX- and one RX-packet with echocancellation */ -+void bchdev_echocancel_chunk(dsp_t* dev, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size) -+{ -+ int16_t rxlin, txlin; -+ uint16_t pos; -+ -+ /* Perform echo cancellation on a chunk if requested */ -+ if (dev->ec) { -+ if (dev->echostate & __ECHO_STATE_MUTE) { -+ if (dev->echostate == ECHO_STATE_STARTTRAINING) { -+ // Transmit impulse now -+ txchunk[0] = linear2alaw(16384); -+ memset(txchunk+1, 0, size-1); -+ bchdev_echocancel_setstate(dev, ECHO_STATE_TRAINING); //AWAITINGECHO); -+ } else { -+ // train the echo cancellation -+ for (pos = 0; pos < size; pos++) { -+ rxlin = alaw2linear(rxchunk[pos]); -+ txlin = alaw2linear(txchunk[pos]); -+ if (dev->echostate == ECHO_STATE_PRETRAINING) { -+ if (dev->echotimer <= 0) { -+ dev->echotimer = 0; -+ bchdev_echocancel_setstate(dev, ECHO_STATE_STARTTRAINING); -+ } else { -+ dev->echotimer--; -+ } -+ } -+ if ((dev->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) { -+ dev->echolastupdate = 0; -+ bchdev_echocancel_setstate(dev, ECHO_STATE_TRAINING); -+ } -+ if (dev->echostate == ECHO_STATE_TRAINING) { -+ if (echo_can_traintap(dev->ec, dev->echolastupdate++, rxlin)) { -+ bchdev_echocancel_setstate(dev, ECHO_STATE_ACTIVE); -+ } -+ } -+ -+ rxchunk[pos] = linear2alaw(0); -+ txchunk[pos] = linear2alaw(0); -+ } -+ } -+ } else { -+ for (pos = 0; pos < size; pos++) { -+ rxlin = alaw2linear(rxchunk[pos]); -+ txlin = alaw2linear(txchunk[pos]); -+ -+ if (echo_can_disable_detector_update(dev->ecdis_rd, rxlin) || -+ echo_can_disable_detector_update(dev->ecdis_wr, txlin)) { -+ bchdev_echocancel_deactivate(dev); -+ printk("EC: Fax detected, EC disabled\n"); -+ return ; -+ } else { -+ rxlin = echo_can_update(dev->ec, txlin, rxlin); -+ rxchunk[pos] = linear2alaw(rxlin); -+ } -+ } -+ } -+ } -+} -+ -+/******************************************************/ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_core.c mISDN/drivers/isdn/hardware/mISDN/dsp_core.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_core.c 2005-01-29 17:15:21.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/dsp_core.c 2005-12-02 09:57:08.000000000 +0100 -@@ -42,17 +42,11 @@ - * v | - * +-----+-------------+-----+ - * |(3)(4) | -- * | | -- * | | - * | CMX | - * | | -- * | | -- * | | -- * | | - * | +-------------+ - * | | ^ - * | | | -- * | | | - * |+---------+| +----+----+ - * ||(1) || |(5) | - * || || | | -@@ -62,7 +56,6 @@ - * |+----+----+| +----+----+ - * +-----+-----+ ^ - * | | -- * | | - * v | - * +----+----+ +----+----+ - * |(5) | |(2) | -@@ -74,8 +67,18 @@ - * | ^ - * | | - * v | -+ * +----+-------------+----+ -+ * |(7) | -+ * | | -+ * | Echo Cancellation | -+ * | | -+ * | | -+ * +----+-------------+----+ -+ * | ^ -+ * | | -+ * v | - * +----+----+ +----+----+ -- * |(7) | |(7) | -+ * |(8) | |(8) | - * | | | | - * | Encrypt | | Decrypt | - * | | | | -@@ -115,6 +118,13 @@ - * data to/form upper layer may be swithed on/off individually without loosing - * features of CMX, Tones and DTMF. - * -+ * Echo Cancellation: Sometimes we like to cancel echo from the interface. -+ * Note that a VoIP call may not have echo caused by the IP phone. The echo -+ * is generated by the telephone line connected to it. Because the delay -+ * is high, it becomes an echo. RESULT: Echo Cachelation is required if -+ * both echo AND delay is applied to an interface. -+ * Remember that software CMX always generates a more or less delay. -+ * - * If all used features can be realized in hardware, and if transmit and/or - * receive data ist disabled, the card may not send/receive any data at all. - * Not receiving is usefull if only announcements are played. Not sending is -@@ -215,6 +225,9 @@ - printk(KERN_ERR "%s: failed to create tx packet\n", __FUNCTION__); - return; - } -+ /* if echo cancellation is enabled */ -+ if (dsp->cancel_enable) -+ dsp_cancel_tx(dsp, nskb->data, nskb->len); - /* crypt if enabled */ - if (dsp->bf_enable) - dsp_bf_encrypt(dsp, nskb->data, nskb->len); -@@ -380,6 +393,34 @@ - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; -+ case ECHOCAN_ON: /* turn echo calcellation on */ -+ -+ if (len<4) { -+ ret = -EINVAL; -+ break; -+ } -+ int ec_arr[2]; -+ -+ memcpy(&ec_arr,data,sizeof(ec_arr)); -+ -+ -+ printk("data[0]: %d data[1]: %d, len :%d\n",ec_arr[0], -+ ec_arr[1] ,len); -+ -+ if (dsp_debug & DEBUG_DSP_CORE) -+ printk(KERN_DEBUG "%s: turn echo cancelation on (delay=%d attenuation-shift=%d\n", __FUNCTION__, ec_arr[0], ec_arr[1]); -+ -+ ret = dsp_cancel_init(dsp, ec_arr[0], ec_arr[1] ,1); -+ -+ dsp_cmx_hardware(dsp->conf, dsp); -+ break; -+ case ECHOCAN_OFF: /* turn echo calcellation off */ -+ if (dsp_debug & DEBUG_DSP_CORE) -+ printk(KERN_DEBUG "%s: turn echo cancelation off\n", __FUNCTION__); -+ -+ ret = dsp_cancel_init(dsp, 0,0,-1); -+ dsp_cmx_hardware(dsp->conf, dsp); -+ break; - case BF_ENABLE_KEY: /* turn blowfish on */ - if (len<4 || len>56) { - ret = -EINVAL; -@@ -522,6 +563,9 @@ - /* decrypt if enabled */ - if (dsp->bf_enable) - dsp_bf_decrypt(dsp, skb->data, skb->len); -+ /* if echo cancellation is enabled */ -+ if (dsp->cancel_enable) -+ dsp_cancel_rx(dsp, skb->data, skb->len); - /* check if dtmf soft decoding is turned on */ - if (dsp->dtmf.software) { - digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); -@@ -919,6 +963,9 @@ - dsp_audio_generate_ulaw_samples(); - dsp_audio_generate_volume_changes(); - -+ -+ dsp_cancel_init_flip_bits(); -+ - /* init global lock */ - lock_HW_init(&dsp_lock); - -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp.h mISDN/drivers/isdn/hardware/mISDN/dsp.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp.h 2005-01-29 17:15:31.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/dsp.h 2005-12-02 09:57:08.000000000 +0100 -@@ -40,6 +40,13 @@ - #include "memdbg.h" - #endif - -+#include "ecdis.h" -+#include "mec2.h" -+ -+//#include "mec.h" -+//#include "mec3.h" -+ -+ - extern int dsp_options; - extern int dsp_debug; - -@@ -109,6 +116,8 @@ - - #define DSP_DTMF_NPOINTS 102 - -+#define ECHOCAN_BUFLEN 4*128 -+ - typedef struct _dtmf_t { - int software; /* dtmf uses software decoding */ - int hardware; /* dtmf uses hardware decoding */ -@@ -120,6 +129,13 @@ - } dtmf_t; - - -+/************** -+ *Cancel Stuff* -+ ***************/ -+ -+void dsp_cancel_init_flip_bits(void); -+ -+ - /*************** - * tones stuff * - ***************/ -@@ -200,6 +216,25 @@ - u8 bf_crypt_inring[16]; - u8 bf_data_out[9]; - int bf_sync; -+ -+ /* echo cancellation stuff */ -+ int cancel_enable; -+ echo_can_state_t* ec; /**< == NULL: echo cancellation disabled; -+ != NULL: echo cancellation enabled */ -+ -+ echo_can_disable_detector_state_t* ecdis_rd; -+ echo_can_disable_detector_state_t* ecdis_wr; -+ -+ uint16_t echotimer; -+ uint16_t echostate; -+ uint16_t echolastupdate; -+ -+ char txbuf[ECHOCAN_BUFLEN]; -+ int txbuflen; -+ -+ char rxbuf[ECHOCAN_BUFLEN]; -+ int rxbuflen; -+ - } dsp_t; - - /* functions */ -@@ -228,4 +263,8 @@ - extern int dsp_bf_init(dsp_t *dsp, const u8 *key, unsigned int keylen); - extern void dsp_bf_cleanup(dsp_t *dsp); - -+extern void dsp_cancel_tx(dsp_t *dsp, u8 *data, int len); -+extern void dsp_cancel_rx(dsp_t *dsp, u8 *data, int len); -+extern int dsp_cancel_init(dsp_t *dsp, int taps, int training, int delay); -+ - -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.c mISDN/drivers/isdn/hardware/mISDN/ec.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.c 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/ec.c 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,105 @@ -+#include "mec2.h" -+#include "ec.h" -+ -+ -+ -+#define __ECHO_STATE_MUTE (1 << 8) -+#define ECHO_STATE_IDLE (0) -+#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE)) -+#define ECHO_STATE_ACTIVE (5) -+ -+#define AMI_MASK 0x55 -+ -+static unsigned char linear2alaw (short linear) -+{ -+ int mask; -+ int seg; -+ int pcm_val; -+ static int seg_end[8] = -+ { -+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF -+ }; -+ -+ pcm_val = linear; -+ if (pcm_val >= 0) -+ { -+ /* Sign (7th) bit = 1 */ -+ mask = AMI_MASK | 0x80; -+ } -+ else -+ { -+ /* Sign bit = 0 */ -+ mask = AMI_MASK; -+ pcm_val = -pcm_val; -+ } -+ -+ /* Convert the scaled magnitude to segment number. */ -+ for (seg = 0; seg < 8; seg++) -+ { -+ if (pcm_val <= seg_end[seg]) -+ break; -+ } -+ /* Combine the sign, segment, and quantization bits. */ -+ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; -+} -+/*- End of function --------------------------------------------------------*/ -+ -+static short int alaw2linear (uint8_t alaw) -+{ -+ int i; -+ int seg; -+ -+ alaw ^= AMI_MASK; -+ i = ((alaw & 0x0F) << 4); -+ seg = (((int) alaw & 0x70) >> 4); -+ if (seg) -+ i = (i + 0x100) << (seg - 1); -+ return (short int) ((alaw & 0x80) ? i : -i); -+} -+ -+ -+void ec_chunk(struct echo_can_s *echo_can, unsigned char *rxchunk, const unsigned char *txchunk, int chunk_size) -+{ -+ short rxlin, txlin; -+ int x; -+ //unsigned long flags; -+ /* Perform echo cancellation on a chunk if necessary */ -+ if (echo_can->ec) { -+ if (echo_can->echostate & __ECHO_STATE_MUTE) { -+ /* Special stuff for training the echo can */ -+ for (x=0;x< chunk_size;x++) { -+ rxlin = alaw2linear(rxchunk[x]); -+ txlin = alaw2linear(txchunk[x]); -+ if (echo_can->echostate == ECHO_STATE_PRETRAINING) { -+ if (--echo_can->echotimer <= 0) { -+ echo_can->echotimer = 0; -+ echo_can->echostate = ECHO_STATE_STARTTRAINING; -+ } -+ } -+ if ((echo_can->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) { -+ echo_can->echolastupdate = 0; -+ echo_can->echostate = ECHO_STATE_TRAINING; -+ } -+ if (echo_can->echostate == ECHO_STATE_TRAINING) { -+ if (echo_can_traintap(echo_can->ec, echo_can->echolastupdate++, rxlin)) { -+#if 0 -+ printf("Finished training (%d taps trained)!\n", echo_can->echolastupdate); -+#endif -+ echo_can->echostate = ECHO_STATE_ACTIVE; -+ } -+ } -+ rxlin = 0; -+ rxchunk[x] = linear2alaw((int)rxlin); -+ } -+ } else { -+ for (x=0;x<chunk_size;x++) { -+ rxlin = alaw2linear(rxchunk[x]); -+ rxlin = echo_can_update(echo_can->ec, alaw2linear(txchunk[x]), rxlin); -+ rxchunk[x] = linear2alaw((int)rxlin); -+ } -+ } -+ } -+} -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/ecdis.h mISDN/drivers/isdn/hardware/mISDN/ecdis.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/ecdis.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/ecdis.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,118 @@ -+/* -+ * SpanDSP - a series of DSP components for telephony -+ * -+ * ec_disable_detector.h - A detector which should eventually meet the -+ * G.164/G.165 requirements for detecting the -+ * 2100Hz echo cancellor disable tone. -+ * -+ * Written by Steve Underwood <steveu@coppice.org> -+ * -+ * Copyright (C) 2001 Steve Underwood -+ * -+ * All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include "biquad.h" -+ -+typedef struct -+{ -+ biquad2_state_t notch; -+ int notch_level; -+ int channel_level; -+ int tone_present; -+ int tone_cycle_duration; -+ int good_cycles; -+ int hit; -+} echo_can_disable_detector_state_t; -+ -+ -+#define FALSE 0 -+#define TRUE (!FALSE) -+ -+static inline void echo_can_disable_detector_init (echo_can_disable_detector_state_t *det) -+{ -+ /* Elliptic notch */ -+ /* This is actually centred at 2095Hz, but gets the balance we want, due -+ to the asymmetric walls of the notch */ -+ biquad2_init (&det->notch, -+ (int32_t) (-0.7600000*32768.0), -+ (int32_t) (-0.1183852*32768.0), -+ (int32_t) (-0.5104039*32768.0), -+ (int32_t) ( 0.1567596*32768.0), -+ (int32_t) ( 1.0000000*32768.0)); -+ -+ det->channel_level = 0; -+ det->notch_level = 0; -+ det->tone_present = FALSE; -+ det->tone_cycle_duration = 0; -+ det->good_cycles = 0; -+ det->hit = 0; -+} -+/*- End of function --------------------------------------------------------*/ -+ -+static inline int echo_can_disable_detector_update (echo_can_disable_detector_state_t *det, -+ int16_t amp) -+{ -+ int16_t notched; -+ -+ notched = biquad2 (&det->notch, amp); -+ /* Estimate the overall energy in the channel, and the energy in -+ the notch (i.e. overall channel energy - tone energy => noise). -+ Use abs instead of multiply for speed (is it really faster?). -+ Damp the overall energy a little more for a stable result. -+ Damp the notch energy a little less, so we don't damp out the -+ blip every time the phase reverses */ -+ det->channel_level += ((abs(amp) - det->channel_level) >> 5); -+ det->notch_level += ((abs(notched) - det->notch_level) >> 4); -+ if (det->channel_level > 280) -+ { -+ /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ -+ if (det->notch_level*6 < det->channel_level) -+ { -+ /* The notch says yes, so we have the tone. */ -+ if (!det->tone_present) -+ { -+ /* Do we get a kick every 450+-25ms? */ -+ if (det->tone_cycle_duration >= 425*8 -+ && -+ det->tone_cycle_duration <= 475*8) -+ { -+ det->good_cycles++; -+ if (det->good_cycles > 2) -+ det->hit = TRUE; -+ } -+ det->tone_cycle_duration = 0; -+ } -+ det->tone_present = TRUE; -+ } -+ else -+ { -+ det->tone_present = FALSE; -+ } -+ det->tone_cycle_duration++; -+ } -+ else -+ { -+ det->tone_present = FALSE; -+ det->tone_cycle_duration = 0; -+ det->good_cycles = 0; -+ } -+ return det->hit; -+} -+/*- End of function --------------------------------------------------------*/ -+/*- End of file ------------------------------------------------------------*/ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.h mISDN/drivers/isdn/hardware/mISDN/ec.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/ec.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,12 @@ -+ -+ -+ -+struct echo_can_s { -+ int echostate; -+ int echotimer; -+ int echolastupdate; -+ echo_can_state_t *ec; -+}; -+ -+ -+ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c 2005-01-31 18:24:03.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c 2005-12-02 09:57:08.000000000 +0100 -@@ -136,7 +136,7 @@ - static int nt_t1_count[] = { 480, 240, 120, 60, 30, 15, 8, 4 }; - #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ - #define CLKDEL_NT 0x0c /* CLKDEL in NT mode (0x60 MUST not be included!) */ --static u_char silence = 0xff; /* silence by LAW */ -+static u_char mysilence = 0xff; /* silence by LAW */ - - /* enable 32 bit fifo access (PC usage) */ - #define FIFO_32BIT_ACCESS -@@ -903,11 +903,11 @@ - bch->tx_idx = bch->tx_len = 0; - } - /* now we have no more data, so in case of transparent, -- * we set the last byte in fifo to 'silence' in case we will get -+ * we set the last byte in fifo to 'mysilence' in case we will get - * no more data at all. this prevents sending an undefined value. - */ - if (!hdlc) -- HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); -+ HFC_outb_(hc, A_FIFO_DATA0_NOINC, mysilence); - } - - -@@ -1551,7 +1551,7 @@ - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); -- HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); /* tx silence */ -+ HFC_outb_(hc, A_FIFO_DATA0_NOINC, mysilence); /* tx silence */ - /* enable RX fifo */ - HFC_outb(hc, R_FIFO, (ch<<1)|1); - HFC_wait(hc); -@@ -1692,7 +1692,7 @@ - - /* if off */ - if (len <= 0) { -- HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); -+ HFC_outb_(hc, A_FIFO_DATA0_NOINC, mysilence); - if (hc->chan[ch].slot_tx>=0) { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: connecting PCM due to no more TONE: channel %d slot_tx %d\n", __FUNCTION__, ch, hc->chan[ch].slot_tx); -@@ -2183,7 +2183,7 @@ - ret = 0; - break; - -- /* set silence */ -+ /* set mysilence */ - case HW_SPL_LOOP_OFF: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_SPL_LOOP_OFF\n", __FUNCTION__); -@@ -2799,7 +2799,13 @@ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "setup_pci(): investigating card entry %d (looking for type %d)\n", i, hc->type); - inuse: -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) -+ tmp_dev = pci_get_subsys(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_sub, id_list[i].device_sub, tmp_dev); -+#else - tmp_dev = pci_find_subsys(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_sub, id_list[i].device_sub, tmp_dev); -+#endif -+ - if (tmp_dev) { - /* skip if already in use */ - list_for_each_entry_safe(hc_tmp, next, &HFCM_obj.ilist, list) { -@@ -3318,9 +3324,9 @@ - hc->type = type[HFC_cnt] & 0xff; - if (type[HFC_cnt] & 0x100) { - test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); -- silence = 0xff; /* ulaw silence */ -+ mysilence = 0xff; /* ulaw silence */ - } else -- silence = 0x2a; /* alaw silence */ -+ mysilence = 0x2a; /* alaw silence */ - if (type[HFC_cnt] & 0x200) - test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); - // if ((type[HFC_cnt]&0x400) && hc->type==4) -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c 2005-03-26 11:21:39.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c 2005-12-02 09:57:08.000000000 +0100 -@@ -1202,6 +1202,14 @@ - err = check_infoelements(pc, skb, ie_PROGRESS); - if (err) - l3dss1_std_ie_err(pc, err); -+ /* START: patch by steinwej - http://www.beronet.com/bugs/bug_view_page.php?bug_id=0000095 */ -+ /* clear T310 if running */ -+ L3DelTimer(&pc->timer); -+ if (pc->t303skb) { -+ dev_kfree_skb(pc->t303skb); -+ pc->t303skb = NULL; -+ } -+ /* END */ - if (ERR_IE_COMPREHENSION != err) { - if (mISDN_l3up(pc, CC_PROGRESS | INDICATION, skb)) - dev_kfree_skb(skb); -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile mISDN/drivers/isdn/hardware/mISDN/Makefile ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile 2005-06-05 14:44:10.000000000 +0200 -+++ mISDN/drivers/isdn/hardware/mISDN/Makefile 2005-12-05 19:03:11.000000000 +0100 -@@ -30,6 +30,7 @@ - - ifdef CONFIG_MISDN_SPEEDFAX - obj-$(CONFIG_MISDN_DRV) += sedlfax.o -+obj-$(CONFIG_MISDN_DRV) += faxl3.o - endif - - ifdef CONFIG_MISDN_W6692 -@@ -70,8 +71,6 @@ - asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \ - supp_serv.o - mISDN_dtmf-objs := dtmf.o --mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o -+mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o - mISDN_x25dte-objs := x25_dte.o x25_l3.o - I4LmISDN-objs := i4l_mISDN.o -- --include Rules.mISDN -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 2005-06-05 14:44:10.000000000 +0200 -+++ mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 2005-12-02 09:57:08.000000000 +0100 -@@ -71,6 +71,6 @@ - asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \ - supp_serv.o - mISDN_dtmf-objs := dtmf.o --mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o -+mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o - mISDN_x25dte-objs := x25_dte.o x25_l3.o - I4LmISDN-objs := i4l_mISDN.o -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2_const.h mISDN/drivers/isdn/hardware/mISDN/mec2_const.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2_const.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/mec2_const.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,25 @@ -+/* -+ Important constants for tuning mec2 echo can -+ */ -+#ifndef _MEC2_CONST_H -+#define _MEC2_CONST_H -+ -+ -+/* Convergence speed -- higher means slower */ -+#define DEFAULT_BETA1_I 2048 -+#define DEFAULT_SIGMA_LY_I 7 -+#define DEFAULT_SIGMA_LU_I 7 -+#define DEFAULT_ALPHA_ST_I 5 -+#define DEFAULT_ALPHA_YT_I 5 -+#define DEFAULT_CUTOFF_I 128 -+#define DEFAULT_HANGT 600 -+#define DEFAULT_SUPPR_I 16 -+#define MIN_UPDATE_THRESH_I 4096 -+#define DEFAULT_M 16 -+#define SUPPR_FLOOR -64 -+#define SUPPR_CEIL -24 -+#define RES_SUPR_FACTOR -20 -+#define AGGRESSIVE_HCNTR 160 /* 20ms */ -+ -+#endif /* _MEC2_CONST_H */ -+ -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2.h mISDN/drivers/isdn/hardware/mISDN/mec2.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/mec2.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,409 @@ -+/* -+ * Mark's Second Echo Canceller -+ * -+ * Copyright (C) 2002, Digium, Inc. -+ * -+ * This program is free software and may be used and -+ * distributed according to the terms of the GNU -+ * General Public License, incorporated herein by -+ * reference. -+ * -+ */ -+#ifndef _MARK2_ECHO_H -+#define _MARK2_ECHO_H -+ -+#ifdef __KERNEL__ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#define MALLOC(a) kmalloc((a), GFP_KERNEL) -+#define FREE(a) kfree(a) -+#else -+#include <stdlib.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <string.h> -+#include <math.h> -+#define MALLOC(a) malloc(a) -+#define FREE(a) free(a) -+#endif -+ -+/* Get optimized routines for math */ -+#include "arith.h" -+ -+#ifndef NULL -+#define NULL 0 -+#endif -+#ifndef FALSE -+#define FALSE 0 -+#endif -+#ifndef TRUE -+#define TRUE (!FALSE) -+#endif -+ -+#include "mec2_const.h" -+ -+/* Circular buffer definition */ -+typedef struct { -+ int idx_d; -+ int size_d; -+ short *buf_d; /* Twice as large as we need */ -+} echo_can_cb_s; -+ -+// class definition -+// -+typedef struct { -+ /* Echo canceller definition */ -+ -+ /* absolute time */ -+ int i_d; -+ -+ /* pre-computed constants */ -+ -+ int N_d; -+ int beta2_i; -+ -+ // declare accumulators for power computations -+ // -+ int Ly_i; -+ int Lu_i; -+ -+ // declare an accumulator for the near-end signal detector -+ // -+ int s_tilde_i; -+ int HCNTR_d; -+ -+ // circular buffers and coefficients -+ // -+ int *a_i; -+ short *a_s; -+ echo_can_cb_s y_s; -+ echo_can_cb_s s_s; -+ echo_can_cb_s u_s; -+ echo_can_cb_s y_tilde_s; -+ int y_tilde_i; -+ -+ /* Max memory */ -+ short max_y_tilde; -+ int max_y_tilde_pos; -+ -+} echo_can_state_t; -+ -+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where) -+{ -+ cb->buf_d = (short *)where; -+ cb->idx_d = 0; -+ cb->size_d = len; -+} -+ -+static inline void add_cc_s(echo_can_cb_s *cb, short newval) -+{ -+ /* Can't use modulus because N+M isn't a power of two (generally) */ -+ cb->idx_d--; -+ if (cb->idx_d < (int)0) -+ {cb->idx_d += cb->size_d;} -+ /* Load two copies into memory */ -+ cb->buf_d[cb->idx_d] = newval; -+ cb->buf_d[cb->idx_d + cb->size_d] = newval; -+} -+ -+static inline short get_cc_s(echo_can_cb_s *cb, int pos) -+{ -+ /* Load two copies into memory */ -+ return cb->buf_d[cb->idx_d + pos]; -+} -+ -+static inline void init_cc(echo_can_state_t *ec, int N, int maxy, int maxu) { -+ -+ void *ptr = ec; -+ unsigned long tmp; -+ /* double-word align past end of state */ -+ ptr += sizeof(echo_can_state_t); -+ tmp = (unsigned long)ptr; -+ tmp += 3; -+ tmp &= ~3L; -+ ptr = (void *)tmp; -+ -+ // reset parameters -+ // -+ ec->N_d = N; -+ ec->beta2_i = DEFAULT_BETA1_I; -+ -+ // allocate coefficient memory -+ // -+ ec->a_i = ptr; -+ ptr += (sizeof(int) * ec->N_d); -+ ec->a_s = ptr; -+ ptr += (sizeof(short) * ec->N_d); -+ -+ /* Reset Y circular buffer (short version) */ -+ init_cb_s(&ec->y_s, maxy, ptr); -+ ptr += (sizeof(short) * (maxy) * 2); -+ -+ /* Reset Sig circular buffer (short version for FIR filter) */ -+ init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr); -+ ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2); -+ -+ init_cb_s(&ec->u_s, maxu, ptr); -+ ptr += (sizeof(short) * maxu * 2); -+ -+ // allocate a buffer for the reference signal power computation -+ // -+ init_cb_s(&ec->y_tilde_s, ec->N_d, ptr); -+ -+ -+ // reset absolute time -+ // -+ ec->i_d = (int)0; -+ -+ // reset the power computations (for y and u) -+ // -+ ec->Ly_i = DEFAULT_CUTOFF_I; -+ ec->Lu_i = DEFAULT_CUTOFF_I; -+ -+ // reset the near-end speech detector -+ // -+ ec->s_tilde_i = 0; -+ ec->HCNTR_d = (int)0; -+ -+ // exit gracefully -+ // -+} -+ -+static inline void echo_can_free(echo_can_state_t *ec) -+{ -+ FREE(ec); -+} -+ -+static inline short echo_can_update(echo_can_state_t *ec, short iref, short isig) { -+ -+ /* declare local variables that are used more than once -+ */ -+ int k; -+ int rs; -+ short u; -+ int Py_i; -+ int two_beta_i; -+ -+ /*************************************************************************** -+ // -+ // flow A on pg. 428 -+ // -+ ***************************************************************************/ -+ -+ /* eq. (16): high-pass filter the input to generate the next value; -+ // push the current value into the circular buffer -+ // -+ // sdc_im1_d = sdc_d; -+ // sdc_d = sig; -+ // s_i_d = sdc_d; -+ // s_d = s_i_d; -+ // s_i_d = (float)(1.0 - gamma_d) * s_i_d -+ + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */ -+ -+ -+ /* Delete last sample from power estimate */ -+ ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I; -+ /* push the reference data onto the circular buffer */ -+ add_cc_s(&ec->y_s, iref); -+ -+ /* eq. (2): compute r in fixed-point */ -+ rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d); -+ rs >>= 15; -+ -+ /* eq. (3): compute the output value (see figure 3) and the error -+ // note: the error is the same as the output signal when near-end -+ // speech is not present -+ */ -+ u = isig - rs; -+ -+ add_cc_s(&ec->u_s, u); -+ -+ -+ -+ /* Delete oldest part of received s_tilde */ -+ ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 )); -+ -+ /* push the signal on the circular buffer, too */ -+ add_cc_s(&ec->s_s, isig); -+ ec->s_tilde_i += abs(isig); -+ ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_YT_I; -+ -+ /* Add to our list of recent y_tilde's */ -+ add_cc_s(&ec->y_tilde_s, ec->y_tilde_i); -+ -+ /**************************************************************************** -+ // -+ // flow B on pg. 428 -+ // -+ ****************************************************************************/ -+ -+ /* compute the new convergence factor -+ */ -+ Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I); -+ Py_i >>= 15; -+ if (ec->HCNTR_d > 0) { -+ Py_i = (1 << 15); -+ } -+ -+#if 0 -+ printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1); -+#endif -+ -+ /* Vary rate of adaptation depending on position in the file -+ // Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech -+ // has begun of the file to allow the echo cancellor to estimate the -+ // channel accurately -+ */ -+#if 0 -+ if (ec->start_speech_d != 0 ){ -+ if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){ -+ ec->beta2_d = max_cc_float(MIN_BETA, -+ DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - -+ DEFAULT_T0 - -+ ec->start_speech_d))); -+ } -+ } -+ else {ec->beta2_d = DEFAULT_BETA1;} -+#endif -+ -+ ec->beta2_i = DEFAULT_BETA1_I; /* Fixed point, inverted */ -+ -+ two_beta_i = (ec->beta2_i * Py_i) >> 15; /* Fixed point version, inverted */ -+ if (!two_beta_i) -+ two_beta_i++; -+ -+ /* Update Lu_i (Suppressed power estimate) */ -+ ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ; -+ ec->Lu_i += abs(u); -+ -+ /* eq. (10): update power estimate of the reference -+ */ -+ ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ; -+ ec->Ly_i += abs(iref); -+ -+ if (ec->Ly_i < DEFAULT_CUTOFF_I) -+ ec->Ly_i = DEFAULT_CUTOFF_I; -+ -+#if 0 -+ printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1); -+#endif -+ -+ if (ec->y_tilde_i > ec->max_y_tilde) { -+ /* New highest y_tilde with full life */ -+ ec->max_y_tilde = ec->y_tilde_i; -+ ec->max_y_tilde_pos = ec->N_d - 1; -+ } else if (--ec->max_y_tilde_pos < 0) { -+ /* Time to find new max y tilde... */ -+ ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos); -+ } -+ -+ if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde) -+ { -+ ec->HCNTR_d = DEFAULT_HANGT; -+ } -+ else if (ec->HCNTR_d > (int)0) -+ { -+ ec->HCNTR_d--; -+ } -+ -+ /* update coefficients if no near-end speech and we have enough signal -+ * to bother trying to update. -+ */ -+ if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) && -+ (ec->Lu_i > MIN_UPDATE_THRESH_I)) { -+ // loop over all filter coefficients -+ // -+ for (k=0; k<ec->N_d; k++) { -+ -+ // eq. (7): compute an expectation over M_d samples -+ // -+ int grad2; -+ grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d, -+ ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M); -+ // eq. (7): update the coefficient -+ // -+ ec->a_i[k] += grad2 / two_beta_i; -+ ec->a_s[k] = ec->a_i[k] >> 16; -+ } -+ } -+ -+ /* paragraph below eq. (15): if no near-end speech, -+ // check for residual error suppression -+ */ -+#ifndef NO_ECHO_SUPPRESSOR -+#ifdef AGGRESSIVE_SUPPRESSOR -+ if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) { -+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); -+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); -+ } -+#else -+ if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) { -+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1); -+ } -+#endif -+#endif -+ -+#if 0 -+ if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) && -+ (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) { -+ suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d) -+ - SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL); -+ -+ u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr; -+ -+ } -+#endif -+ ec->i_d++; -+ return u; -+} -+ -+static inline echo_can_state_t *echo_can_create(int len, int adaption_mode) -+{ -+ echo_can_state_t *ec; -+ int maxy; -+ int maxu; -+ maxy = len + DEFAULT_M; -+ maxu = DEFAULT_M; -+ if (maxy < (1 << DEFAULT_ALPHA_YT_I)) -+ maxy = (1 << DEFAULT_ALPHA_YT_I); -+ if (maxy < (1 << DEFAULT_SIGMA_LY_I)) -+ maxy = (1 << DEFAULT_SIGMA_LY_I); -+ if (maxu < (1 << DEFAULT_SIGMA_LU_I)) -+ maxu = (1 << DEFAULT_SIGMA_LU_I); -+ ec = (echo_can_state_t *)MALLOC(sizeof(echo_can_state_t) + -+ 4 + /* align */ -+ sizeof(int) * len + /* a_i */ -+ sizeof(short) * len + /* a_s */ -+ 2 * sizeof(short) * (maxy) + /* y_s */ -+ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ -+ 2 * sizeof(short) * (maxu) + /* u_s */ -+ 2 * sizeof(short) * len); /* y_tilde_s */ -+ if (ec) { -+ memset(ec, 0, sizeof(echo_can_state_t) + -+ 4 + /* align */ -+ sizeof(int) * len + /* a_i */ -+ sizeof(short) * len + /* a_s */ -+ 2 * sizeof(short) * (maxy) + /* y_s */ -+ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ -+ 2 * sizeof(short) * (maxu) + /* u_s */ -+ 2 * sizeof(short) * len); /* y_tilde_s */ -+ init_cc(ec, len, maxy, maxu); -+ } -+ return ec; -+} -+ -+static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val) -+{ -+ /* Reset hang counter to avoid adjustments after -+ initial forced training */ -+ ec->HCNTR_d = ec->N_d << 1; -+ if (pos >= ec->N_d) -+ return 1; -+ ec->a_i[pos] = val << 17; -+ ec->a_s[pos] = val << 1; -+ if (++pos >= ec->N_d) -+ return 1; -+ return 0; -+} -+ -+#endif -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec3.h mISDN/drivers/isdn/hardware/mISDN/mec3.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec3.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/mec3.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,243 @@ -+/* -+ * Mark's Third Echo Canceller -+ * -+ * Copyright (C) 2003, Digium, Inc. -+ * -+ * This program is free software and may be used -+ * and distributed under the terms of the GNU General Public -+ * License, incorporated herein by reference. -+ * -+ * Dedicated to the crew of the Columbia, STS-107 for their -+ * bravery and courageous sacrifice for science. -+ * -+ */ -+ -+#ifndef _MARK3_ECHO_H -+#define _MARK3_ECHO_H -+ -+ -+ -+#ifdef __KERNEL__ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#define MALLOC(a) kmalloc((a), GFP_KERNEL) -+#define FREE(a) kfree(a) -+#else -+#include <stdlib.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <string.h> -+#include <math.h> -+#define MALLOC(a) malloc(a) -+#define FREE(a) free(a) -+#endif -+ -+/* Features */ -+ -+/* -+ * DO_BACKUP -- Backup coefficients, and revert in the presense of double talk to try to prevent -+ * them from diverging during the ramp-up before the DTD kicks in -+ */ -+/* #define DO_BACKUP */ -+ -+#define STEP_SHIFT 2 /* Convergence rate higher = slower / better (as a shift) */ -+ -+#define SIGMA_REF_PWR 655 /* Keep denominator from being 0 */ -+ -+#define MIN_TX_ENERGY 256 /* Must have at least this much reference */ -+#define MIN_RX_ENERGY 32 /* Must have at least this much receive energy */ -+ -+#define MAX_ATTENUATION_SHIFT 6 /* Maximum amount of loss we care about */ -+#define MAX_BETA 1024 -+ -+#define SUPPR_SHIFT 4 /* Amount of loss at which we suppress audio */ -+ -+#define HANG_TIME 600 /* Hangover time */ -+ -+#define NTAPS 2048 /* Maximum number of echo can taps */ -+ -+#define BACKUP 256 /* Backup every this number of samples */ -+ -+#define POWER_OFFSET 5 /* Shift power by this amount to be sure we don't overflow the -+ reference power. Higher = less likely to overflow, lower = more accurage */ -+ -+#include "arith.h" -+ -+typedef struct { -+ short buf[NTAPS * 2]; -+ short max; -+ int maxexp; -+} cbuf_s; -+ -+typedef struct { -+ short a_s[NTAPS]; /* Coefficients in shorts */ -+ int a_i[NTAPS]; /* Coefficients in ints*/ -+#ifdef DO_BACKUP -+ int b_i[NTAPS]; /* Coefficients (backup1) */ -+ int c_i[NTAPS]; /* Coefficients (backup2) */ -+#endif -+ cbuf_s ref; /* Reference excitation */ -+ cbuf_s sig; /* Signal (echo + near end + noise) */ -+ cbuf_s e; /* Error */ -+ int refpwr; /* Reference power */ -+ int taps; /* Number of taps */ -+ int tappwr; /* Power of taps */ -+ int hcntr; /* Hangtime counter */ -+ int pos; /* Position in curcular buffers */ -+ int backup; /* Backup timer */ -+} echo_can_state_t; -+ -+static inline void echo_can_free(echo_can_state_t *ec) -+{ -+ FREE(ec); -+} -+ -+static inline void buf_add(cbuf_s *b, short sample, int pos, int taps) -+{ -+ /* Store and keep track of maxima */ -+ int x; -+ b->buf[pos] = sample; -+ b->buf[pos + taps] = sample; -+ if (sample > b->max) { -+ b->max = sample; -+ b->maxexp = taps; -+ } else { -+ b->maxexp--; -+ if (!b->maxexp) { -+ b->max = 0; -+ for (x=0;x<taps;x++) -+ if (b->max < abs(b->buf[pos + x])) { -+ b->max = abs(b->buf[pos + x]); -+ b->maxexp = x + 1; -+ } -+ } -+ } -+} -+ -+static inline short echo_can_update(echo_can_state_t *ec, short ref, short sig) -+{ -+ int x; -+ short u; -+ int refpwr; -+ int beta; /* Factor */ -+ int se; /* Simulated echo */ -+#ifdef DO_BACKUP -+ if (!ec->backup) { -+ /* Backup coefficients periodically */ -+ ec->backup = BACKUP; -+ memcpy(ec->c_i,ec->b_i,sizeof(ec->c_i)); -+ memcpy(ec->b_i,ec->a_i,sizeof(ec->b_i)); -+ } else -+ ec->backup--; -+#endif -+ /* Remove old samples from reference power calculation */ -+ ec->refpwr -= ((ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]) >> POWER_OFFSET); -+ -+ /* Store signal and reference */ -+ buf_add(&ec->ref, ref, ec->pos, ec->taps); -+ buf_add(&ec->sig, sig, ec->pos, ec->taps); -+ -+ /* Add new reference power */ -+ ec->refpwr += ((ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]) >> POWER_OFFSET); -+ -+ -+ /* Calculate simulated echo */ -+ se = CONVOLVE2(ec->a_s, ec->ref.buf + ec->pos, ec->taps); -+ se >>= 15; -+ -+ u = sig - se; -+ if (ec->hcntr) -+ ec->hcntr--; -+ -+ /* Store error */ -+ buf_add(&ec->e, sig, ec->pos, ec->taps); -+ if ((ec->ref.max > MIN_TX_ENERGY) && -+ (ec->sig.max > MIN_RX_ENERGY) && -+ (ec->e.max > (ec->ref.max >> MAX_ATTENUATION_SHIFT))) { -+ /* We have sufficient energy */ -+ if (ec->sig.max < (ec->ref.max >> 1)) { -+ /* No double talk */ -+ if (!ec->hcntr) { -+ refpwr = ec->refpwr >> (16 - POWER_OFFSET); -+ if (refpwr < SIGMA_REF_PWR) -+ refpwr = SIGMA_REF_PWR; -+ beta = (u << 16) / refpwr; -+ beta >>= STEP_SHIFT; -+ if (beta > MAX_BETA) -+ beta = 0; -+ if (beta < -MAX_BETA) -+ beta = 0; -+ /* Update coefficients */ -+ for (x=0;x<ec->taps;x++) { -+ ec->a_i[x] += beta * ec->ref.buf[ec->pos + x]; -+ ec->a_s[x] = ec->a_i[x] >> 16; -+ } -+ } -+ } else { -+#ifdef DO_BACKUP -+ if (!ec->hcntr) { -+ /* Our double talk detector is turning on for the first time. Revert -+ our coefficients, since we're probably well into the double talk by now */ -+ memcpy(ec->a_i, ec->c_i, sizeof(ec->a_i)); -+ for (x=0;x<ec->taps;x++) { -+ ec->a_s[x] = ec->a_i[x] >> 16; -+ } -+ } -+#endif -+ /* Reset hang-time counter, and prevent backups */ -+ ec->hcntr = HANG_TIME; -+#ifdef DO_BACKUP -+ ec->backup = BACKUP; -+#endif -+ } -+ } -+#ifndef NO_ECHO__SUPPRESSOR -+ if (ec->e.max < (ec->ref.max >> SUPPR_SHIFT)) { -+ /* Suppress residual echo */ -+ u *= u; -+ u >>= 16; -+ } -+#endif -+ ec->pos--; -+ if (ec->pos < 0) -+ ec->pos = ec->taps-1; -+ return u; -+} -+ -+static inline echo_can_state_t *echo_can_create(int taps, int adaption_mode) -+{ -+ echo_can_state_t *ec; -+ int x; -+ -+ //taps = NTAPS; -+ ec = MALLOC(sizeof(echo_can_state_t)); -+ if (ec) { -+ memset(ec, 0, sizeof(echo_can_state_t)); -+ ec->taps = taps; -+ ec->pos = ec->taps-1; -+ for (x=0;x<31;x++) { -+ if ((1 << x) >= ec->taps) { -+ ec->tappwr = x; -+ break; -+ } -+ } -+ } -+ return ec; -+} -+ -+static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val) -+{ -+ /* Reset hang counter to avoid adjustments after -+ initial forced training */ -+ ec->hcntr = ec->taps << 1; -+ if (pos >= ec->taps) -+ return 1; -+ ec->a_i[pos] = val << 17; -+ ec->a_s[pos] = val << 1; -+ if (++pos >= ec->taps) -+ return 1; -+ return 0; -+} -+ -+ -+#endif -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec.h mISDN/drivers/isdn/hardware/mISDN/mec.h ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec.h 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/drivers/isdn/hardware/mISDN/mec.h 2005-12-02 09:57:08.000000000 +0100 -@@ -0,0 +1,308 @@ -+/* -+ * Mark's Echo Canceller -+ * -+ * Mark Spencer <markster@linux-support.net> -+ * -+ * Simple, LMS Echo Canceller with double talk detection. -+ * Partly based on the TI App note: -+ * "Digital Voice Echo Canceller with a TMS 32020" -+ * -+ * Special additional thanks to: -+ * Jim Dixon (Lambda Telecommunications) -+ * Iman Ghobrial (Adtran, Inc.) -+ * -+ * Copyright (C) 2001, Linux Support Services, Inc. -+ * -+ * This program is free software and may be used and -+ * distributed according to the terms of the GNU -+ * General Public License, incorporated herein by -+ * reference. -+ * -+ */ -+ -+#ifndef _MEC_H -+#define _MEC_H -+ -+/* You have to express the size of the echo canceller in taps as -+ a power of 2 (6 = 64 taps, 7 = 128 taps, 8 = 256 taps) */ -+#define NUM_TAPS_POW2 6 /* Size of echo canceller in power of 2 (taps) */ -+#define NUM_TAPS (1 << NUM_TAPS_POW2) /* Actual number of taps */ -+#define TAP_MASK (NUM_TAPS-1) -+ -+ -+#define SIGMA_LU_POW NUM_TAPS_POW2 -+#define SIGMA_LY_POW NUM_TAPS_POW2 -+#define SIGMA_YT_POW (NUM_TAPS_POW2 - 1) -+#define SIGMA_ST_POW (NUM_TAPS_POW2 - 1) -+ -+#define BETA_POW 8 -+ -+#define CUTOFF_S 4 -+ -+/* The higher you make this, the better the quality, but the more CPU time required */ -+#define MIN_QUALITY 100 -+ -+/* This optimization saves a lot of processor but may degrade quality */ -+#define OPTIMIZEDIV -+ -+#if 0 -+/* This converges much more slowly but saves processor */ -+#define MIN_UPDATE 256 -+#define MIN_SKIP 8 -+#endif -+ -+#define HANG_T 600 /* 600 samples, or 75ms */ -+ -+typedef struct mark_ec { -+ /* Circular position */ -+ int cpos; -+ short y[NUM_TAPS]; /* Last N samples (relative to cpos) transmitted */ -+ short y_abs[NUM_TAPS]; /* Last N samples (relative to cpos) transmitted (abs value) */ -+ short s[NUM_TAPS]; /* Last N samples (relative to cpos) received */ -+ short s_abs[NUM_TAPS]; /* Last N samples (relative to cpos) received (abs value) */ -+ short u[NUM_TAPS]; /* Last N samples (relative to cpos) with echo removed */ -+ short u_abs[NUM_TAPS]; /* Last N samples (relative to cpos) with echo removed */ -+ -+ int Ly; /* tx power */ -+ int Lu; /* Power of echo-cancelled output */ -+ -+ int Ty[NUM_TAPS]; /* Short term power estimate of transmit */ -+ int Ts; /* Short term power estimate of received signal */ -+ -+ int a[NUM_TAPS]; /* Tap weight coefficients (not relative) */ -+ -+ short sdc[NUM_TAPS]; /* Near end signal before High Pass Filter */ -+ -+ int samples; /* Sample count */ -+ int pass; /* Number of passes we've made */ -+ -+ int hangt; -+ -+ int lastmax; /* Optimize maximum search */ -+ int maxTy; /* Maximum Ty */ -+} echo_can_state_t; -+ -+#define INLINE inline -+ -+#ifdef __KERNEL__ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#define MALLOC(a) kmalloc((a), GFP_KERNEL) -+#define FREE(a) kfree((a)) -+#else -+#include <stdlib.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <string.h> -+#define MALLOC(a) malloc(a) -+#define FREE(a) free(a) -+#endif -+ -+static INLINE echo_can_state_t *echo_can_create(int len, int adaption_mode) -+{ -+ echo_can_state_t *ec; -+ /* Uhm, we're only one length, sorry. */ -+ ec = MALLOC(sizeof(echo_can_state_t)); -+ if (ec) -+ memset(ec, 0, sizeof(*ec)); -+ return ec; -+} -+ -+#define PASSPOS 32000 -+#undef PASSPOS -+ -+static INLINE void echo_can_free(echo_can_state_t *ec) -+{ -+ FREE(ec); -+} -+ -+static INLINE int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx) -+{ -+ /* Process a sample, where tx is the near end and rx is the far end + echo */ -+ -+ int suppr; -+ int nsuppr; -+ short rxabs, txabs; -+ register int Lu; -+ register int x; -+ register int pos; -+ register int r_hat; /* Estimated echo */ -+ int oldrxabs; -+ int oldtxabs; -+ int oldsupprabs; -+ int supprabs; -+#ifdef MIN_UPDATE -+ int totalupd; -+#endif -+ -+ txabs = abs(tx); -+ rxabs = abs(rx); -+ -+ ec->pass++; -+ -+ r_hat = 0; -+ -+ /* Load next value */ -+ ec->y[ec->cpos] = tx; -+ -+ /* Load next abs value */ -+ oldtxabs = ec->y_abs[ec->cpos]; -+ ec->y_abs[ec->cpos] = txabs; -+ -+ /* Bring in receive value (near-end signal) */ -+ ec->sdc[ec->cpos] = rx; -+ -+ /* Bring in receive value absolute value */ -+ oldrxabs = ec->s_abs[ec->cpos]; -+ ec->s_abs[ec->cpos] = rxabs; -+ -+ Lu = ec->Lu | 1; -+ -+#if 0 -+ /* Apply first order high pass filter (3 dB @ 160 Hz) */ -+ tx = ec->s[ec->cpos] = (1.0-DEFGAMMA) * ec->s[(ec->cpos - 1) & TAP_MASK] + -+ 0.5 * (1.0-DEFGAMMA) * ( ec->sdc[(ec->cpos - 1) & TAP_MASK] - ec->sdc[(ec->cpos - 2) & TAP_MASK]); -+#endif -+ -+ /* Estimate echo */ -+ pos = ec->cpos; -+ for (x=0;x<NUM_TAPS;x++) { -+ r_hat += ec->a[x] * ec->y[pos]; -+ /* Go backwards in time and loop around circular buffer */ -+ pos = (pos - 1) & TAP_MASK; -+ } -+ -+ r_hat >>= 16; -+ -+ if (ec->hangt > 0) -+ ec->hangt--; -+ -+ /* printf("rx: %F, rhat: %F\n", rx, r_hat); */ -+ /* Calculate suppressed amount */ -+ suppr = rx - r_hat; -+ -+ if (ec->pass > NUM_TAPS) { -+ /* Have to have enough taps to start with */ -+ if (ec->maxTy > ec->Ts) { -+ /* There is no near-end speech detected */ -+ if (!ec->hangt) { -+ /* We're not in the hang-time from the end of near-end speech */ -+ if ((ec->Ly > 1024) && ((ec->Ly / Lu) < MIN_QUALITY)) { -+#ifdef OPTIMIZEDIV -+ /* We both have enough signal on the transmit */ -+ nsuppr = (suppr << 18) / ec->Ly; -+ -+ if (nsuppr > 32767) -+ nsuppr = 32767; -+ if (nsuppr < -32768) -+ nsuppr = -32768; -+ -+ nsuppr /= ec->Ly; -+#else -+ /* We both have enough signal on the transmit */ -+ nsuppr = (suppr << 16) / ec->Ly; -+ -+ if (nsuppr > 32767) -+ nsuppr = 32767; -+ if (nsuppr < -32768) -+ nsuppr = -32768; -+ -+#endif -+ -+ /* Update coefficients */ -+ pos = ec->cpos; -+#ifdef MIN_UPDATE -+ totalupd =0; -+#endif -+ for (x=0;x<NUM_TAPS;x++) { -+ register int adj; -+ adj = ec->y[pos] * nsuppr; -+#ifndef OPTIMIZEDIV -+ adj /= ec->Ly; -+ adj >>= BETA_POW; -+#else -+ adj >>= BETA_POW + 2; -+#endif -+#ifdef PASSPOS -+ if (ec->pass > PASSPOS) -+ printf("tx: %d, old %d: %d, adj %d, nsuppr: %d, power: %d\n", tx, x, ec->a[x], adj, nsuppr, ec->Ly); -+#endif -+ ec->a[x] += adj; -+#ifdef MIN_UPDATE -+ totalupd += abs(adj); -+#endif -+ /* Go backwards in time and loop around circular buffer */ -+ pos = (pos - 1) & TAP_MASK; -+ } -+#ifdef MIN_UPDATE -+ /* If we didn't update at least this much, delay for many more taps */ -+ if (totalupd < MIN_UPDATE) { -+ ec->hangt += MIN_SKIP; -+ } -+#endif -+ } -+ -+ } -+ } else -+ /* Near end speech detected */ -+ ec->hangt = HANG_T; -+ } -+ -+ /* Save supression and absolute values */ -+ supprabs = abs(suppr); -+ oldsupprabs = ec->u_abs[ec->cpos]; -+ ec->u[ec->cpos] = suppr; -+ ec->u_abs[ec->cpos] = supprabs; -+ -+ /* Update tx power */ -+ ec->Ly += (txabs >> SIGMA_LY_POW) - (oldtxabs >> SIGMA_LY_POW); -+ -+ /* Update rx power */ -+ ec->Lu += (supprabs >> SIGMA_LU_POW) - (oldsupprabs >> SIGMA_LU_POW); -+ -+ /* Short term power of tx */ -+ ec->Ty[ec->cpos] = ec->Ty[(ec->cpos - 1) & TAP_MASK] + -+ ((txabs >> SIGMA_YT_POW ) - (oldtxabs >> SIGMA_YT_POW)); -+ -+ /* Keep track of highest */ -+ if (ec->lastmax == ec->cpos) { -+ register int maxTy = 0; -+ /* Have to loop through and find the new highest since our old highest expired */ -+ /* Estimate echo */ -+ pos = ec->cpos; -+ for (x=0;x<NUM_TAPS;x++) { -+ if (ec->Ty[pos] > maxTy) -+ maxTy = ec->Ty[pos]; -+ /* Go backwards in time and loop around circular buffer */ -+ pos = (pos - 1) & TAP_MASK; -+ } -+ ec->maxTy = maxTy; -+ } else { -+ /* Just keep the highest */ -+ if (ec->Ty[ec->cpos] > ec->maxTy) { -+ ec->maxTy = ec->Ty[ec->cpos]; -+ ec->lastmax = ec->cpos; -+ } -+ } -+ ec->Ts += (rxabs >> SIGMA_ST_POW) - (oldrxabs >> SIGMA_ST_POW) ; -+ -+ /* Increment position memory */ -+ ec->cpos = (ec->cpos + 1 ) & TAP_MASK; -+ -+ return suppr; -+} -+ -+static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val) -+{ -+ /* Reset hang counter to avoid adjustments after -+ initial forced training */ -+ ec->hangt = NUM_TAPS << 1; -+ if (pos >= NUM_TAPS) -+ return 1; -+ ec->a[pos] = val << 17; -+ if (++pos >= NUM_TAPS) -+ return 1; -+ return 0; -+} -+ -+#endif -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c 2004-08-27 21:27:40.000000000 +0200 -+++ mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c 2005-12-02 09:57:08.000000000 +0100 -@@ -811,8 +811,8 @@ - return(err); - } - -- printk(KERN_INFO "mISDN: sedlpci found adapter %s at %s\n", -- (char *) ent->driver_data, pdev->slot_name); -+/* printk(KERN_INFO "mISDN: sedlpci found adapter %s at %s\n", -+ (char *) ent->driver_data, pdev->slot_name); */ - - card->cfg = pci_resource_start(pdev, 0); - card->irq = pdev->irq; -diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/w6692.c mISDN/drivers/isdn/hardware/mISDN/w6692.c ---- /tmp/mISDN/drivers/isdn/hardware/mISDN/w6692.c 2004-08-27 21:27:40.000000000 +0200 -+++ mISDN/drivers/isdn/hardware/mISDN/w6692.c 2005-12-02 09:57:08.000000000 +0100 -@@ -1502,8 +1502,8 @@ - return(err); - } - -- printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", -- (char *) ent->driver_data, pdev->slot_name); -+/* printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", -+ (char *) ent->driver_data, pdev->slot_name); */ - - card->addr = pci_resource_start(pdev, 1); - card->irq = pdev->irq; -diff -u -r -P /tmp/mISDN/include/linux/mISDNif.h mISDN/include/linux/mISDNif.h ---- /tmp/mISDN/include/linux/mISDNif.h 2005-02-05 11:18:17.000000000 +0100 -+++ mISDN/include/linux/mISDNif.h 2005-12-02 09:57:08.000000000 +0100 -@@ -173,6 +173,8 @@ - #define BF_DISABLE 0x2315 - #define BF_ACCEPT 0x2316 - #define BF_REJECT 0x2317 -+#define ECHOCAN_ON 0x2318 -+#define ECHOCAN_OFF 0x2319 - #define HW_POTS_ON 0x1001 - #define HW_POTS_OFF 0x1002 - #define HW_POTS_SETMICVOL 0x1100 -diff -u -r -P /tmp/mISDN/Makefile mISDN/Makefile ---- /tmp/mISDN/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ mISDN/Makefile 2005-12-05 19:08:57.000000000 +0100 -@@ -0,0 +1,54 @@ -+BASEDIR=$(shell pwd) -+ -+ -+INSTALL_PREFIX := / -+export INSTALL_PREFIX -+ -+#PATH to linux source/headers -+#LINUX=/usr/src/linux -+LINUX=/lib/modules/$(shell uname -r)/build -+ -+MISDNDIR=$(BASEDIR) -+MISDN_SRC=$(MISDNDIR)/drivers/isdn/hardware/mISDN -+ -+######################################## -+# USER CONFIGS END -+######################################## -+ -+CONFIGS+=CONFIG_MISDN_DRV=m CONFIG_MISDN_DSP=m -+CONFIGS+=CONFIG_MISDN_HFCMULTI=m -+CONFIGS+=CONFIG_MISDN_HFCPCI=m -+CONFIGS+=CONFIG_MISDN_HFCUSB=m -+#CONFIGS+=CONFIG_MISDN_AVM_FRITZ=m -+ -+ -+MINCLUDES+=-I$(MISDNDIR)/include -+ -+all: -+ @echo -+ @echo "Makeing mISDN" -+ @echo "=============" -+ @echo -+ cp $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile.v2.6 $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile -+ -+ cd $(LINUX) ; make SUBDIRS=$(MISDN_SRC) modules $(CONFIGS) LINUXINCLUDE="$(MINCLUDES) -I$(LINUX)/include" -+ -+ -+ -+install: all -+ cd $(LINUX) ; make SUBDIRS=$(MISDN_SRC) modules_install -+ cp $(MISDNDIR)/include/linux/*.h $(INSTALL_PREFIX)/usr/include/linux/ -+ depmod -+ -+.PHONY: install all clean -+ -+clean: -+ rm -rf drivers/isdn/hardware/mISDN/*.o -+ rm -rf drivers/isdn/hardware/mISDN/*.ko -+ rm -rf *~ -+ find . -iname ".*.cmd" -exec rm -rf {} \; -+ find . -iname ".*.d" -exec rm -rf {} \; -+ find . -iname "*.mod.c" -exec rm -rf {} \; -+ find . -iname "*.mod" -exec rm -rf {} \; -+ -+ diff --git a/channels/misdn/portinfo.c b/channels/misdn/portinfo.c deleted file mode 100644 index c7add95fb..000000000 --- a/channels/misdn/portinfo.c +++ /dev/null @@ -1,197 +0,0 @@ - - -#include "isdn_lib.h" - - -/* - * global function to show all available isdn ports - */ -void isdn_port_info(void) -{ - int err; - int i, ii, p; - int useable, nt, pri; - unsigned char buff[1025]; - iframe_t *frm = (iframe_t *)buff; - stack_info_t *stinf; - int device; - - /* open mISDN */ - if ((device = mISDN_open()) < 0) - { - fprintf(stderr, "mISDN_open() failed: ret=%d errno=%d (%s) Check for mISDN modules and device.\n", device, errno, strerror(errno)); - exit(-1); - } - - /* get number of stacks */ - i = 1; - ii = mISDN_get_stack_count(device); - printf("\n"); - if (ii <= 0) - { - printf("Found no card. Please be sure to load card drivers.\n"); - } - - /* loop the number of cards and get their info */ - while(i <= ii) - { - err = mISDN_get_stack_info(device, i, buff, sizeof(buff)); - if (err <= 0) - { - fprintf(stderr, "mISDN_get_stack_info() failed: port=%d err=%d\n", i, err); - break; - } - stinf = (stack_info_t *)&frm->data.p; - - nt = pri = 0; - useable = 1; - - /* output the port info */ - printf("Port %2d: ", i); - switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) - { - case ISDN_PID_L0_TE_S0: - printf("TE-mode BRI S/T interface line (for phone lines)"); -#if 0 - if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_S0_HFC & ISDN_PID_FEATURE_MASK) - printf(" HFC multiport card"); -#endif - break; - case ISDN_PID_L0_NT_S0: - nt = 1; - printf("NT-mode BRI S/T interface port (for phones)"); -#if 0 - if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_S0_HFC & ISDN_PID_FEATURE_MASK) - printf(" HFC multiport card"); -#endif - break; - case ISDN_PID_L0_TE_U: - printf("TE-mode BRI U interface line"); - break; - case ISDN_PID_L0_NT_U: - nt = 1; - printf("NT-mode BRI U interface port"); - break; - case ISDN_PID_L0_TE_UP2: - printf("TE-mode BRI Up2 interface line"); - break; - case ISDN_PID_L0_NT_UP2: - nt = 1; - printf("NT-mode BRI Up2 interface port"); - break; - case ISDN_PID_L0_TE_E1: - pri = 1; - printf("TE-mode PRI E1 interface line (for phone lines)"); -#if 0 - if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_E1_HFC & ISDN_PID_FEATURE_MASK) - printf(" HFC-E1 card"); -#endif - break; - case ISDN_PID_L0_NT_E1: - nt = 1; - pri = 1; - printf("NT-mode PRI E1 interface port (for phones)"); -#if 0 - if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_E1_HFC & ISDN_PID_FEATURE_MASK) - printf(" HFC-E1 card"); -#endif - break; - default: - useable = 0; - printf("unknown type 0x%08x",stinf->pid.protocol[0]); - } - printf("\n"); - - if (nt) - { - if (stinf->pid.protocol[1] == 0) - { - useable = 0; - printf(" -> Missing layer 1 NT-mode protocol.\n"); - } - p = 2; - while(p <= MAX_LAYER_NR) { - if (stinf->pid.protocol[p]) - { - useable = 0; - printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for NT lib.\n", p, stinf->pid.protocol[p]); - } - p++; - } - if (useable) - { - if (pri) - printf(" -> Interface is Point-To-Point (PRI).\n"); - else - printf(" -> Interface can be Poin-To-Point/Multipoint.\n"); - } - } else - { - if (stinf->pid.protocol[1] == 0) - { - useable = 0; - printf(" -> Missing layer 1 protocol.\n"); - } - if (stinf->pid.protocol[2] == 0) - { - useable = 0; - printf(" -> Missing layer 2 protocol.\n"); - } - if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP) - { - printf(" -> Interface is Poin-To-Point.\n"); - } - if (stinf->pid.protocol[3] == 0) - { - useable = 0; - printf(" -> Missing layer 3 protocol.\n"); - } else - { - printf(" -> Protocol: "); - switch(stinf->pid.protocol[3] & ~ISDN_PID_FEATURE_MASK) - { - case ISDN_PID_L3_DSS1USER: - printf("DSS1 (Euro ISDN)"); - break; - - default: - useable = 0; - printf("unknown protocol 0x%08x",stinf->pid.protocol[3]); - } - printf("\n"); - } - p = 4; - while(p <= MAX_LAYER_NR) { - if (stinf->pid.protocol[p]) - { - useable = 0; - printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for TE lib.\n", p, stinf->pid.protocol[p]); - } - p++; - } - printf(" -> childcnt: %d\n",stinf->childcnt); - } - - if (!useable) - printf(" * Port NOT useable for PBX\n"); - - printf("--------\n"); - - i++; - } - printf("\n"); - - /* close mISDN */ - if ((err = mISDN_close(device))) - { - fprintf(stderr, "mISDN_close() failed: err=%d '%s'\n", err, strerror(err)); - exit(-1); - } -} - - -int main() -{ - isdn_port_info(); - return 0; -} diff --git a/channels/misdn_config.c b/channels/misdn_config.c new file mode 100644 index 000000000..7c019dca0 --- /dev/null +++ b/channels/misdn_config.c @@ -0,0 +1,784 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2005, Christian Richter + * + * Christian Richter <crich@beronet.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + * + */ + +/*! + * \file + * + * \brief chan_misdn configuration management + * \author Christian Richter <crich@beronet.com> + * + * \ingroup channel_drivers + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "chan_misdn_config.h" + +#include <asterisk/config.h> +#include <asterisk/channel.h> +#include <asterisk/logger.h> +#include <asterisk/lock.h> +#include <asterisk/pbx.h> +#include <asterisk/strings.h> +#include <asterisk/utils.h> + +#define AST_LOAD_CFG ast_config_load +#define AST_DESTROY_CFG ast_config_destroy + +#define NO_DEFAULT "<>" +#define NONE 0 + +#define GEN_CFG 1 +#define PORT_CFG 2 +#define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec)) +#define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec)) + +enum misdn_cfg_type { + MISDN_CTYPE_STR, + MISDN_CTYPE_INT, + MISDN_CTYPE_BOOL, + MISDN_CTYPE_BOOLINT, + MISDN_CTYPE_MSNLIST, + MISDN_CTYPE_ASTGROUP +}; + +struct msn_list { + char *msn; + struct msn_list *next; +}; + +union misdn_cfg_pt { + char *str; + int *num; + struct msn_list *ml; + ast_group_t *grp; + void *any; +}; + +struct misdn_cfg_spec { + char name[BUFFERSIZE]; + enum misdn_cfg_elements elem; + enum misdn_cfg_type type; + char def[BUFFERSIZE]; + int boolint_def; +}; + +static const struct misdn_cfg_spec port_spec[] = { + { "name", MISDN_CFG_GROUPNAME, MISDN_CTYPE_STR, "default", NONE }, + { "allowed_bearers", MISDN_CFG_ALLOWED_BEARERS, MISDN_CTYPE_STR, "all", NONE }, + { "rxgain", MISDN_CFG_RXGAIN, MISDN_CTYPE_INT, "0", NONE }, + { "txgain", MISDN_CFG_TXGAIN, MISDN_CTYPE_INT, "0", NONE }, + { "te_choose_channel", MISDN_CFG_TE_CHOOSE_CHANNEL, MISDN_CTYPE_BOOL, "no", NONE }, + { "far_alerting", MISDN_CFG_FAR_ALERTING, MISDN_CTYPE_BOOL, "no", NONE }, + { "pmp_l1_check", MISDN_CFG_PMP_L1_CHECK, MISDN_CTYPE_BOOL, "yes", NONE }, + { "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "yes", NONE }, + { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE }, + { "context", MISDN_CFG_CONTEXT, MISDN_CTYPE_STR, "default", NONE }, + { "language", MISDN_CFG_LANGUAGE, MISDN_CTYPE_STR, "en", NONE }, + { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE }, + { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE }, + { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE }, + { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE }, + { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE }, + { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE }, + { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE }, + { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE }, + { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE }, + { "screen", MISDN_CFG_SCREEN, MISDN_CTYPE_INT, "-1", NONE }, + { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE }, + { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE }, + { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE }, + { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE }, + { "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE }, + { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE }, + { "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE }, + { "echocancel", MISDN_CFG_ECHOCANCEL, MISDN_CTYPE_BOOLINT, "0", 128 }, + { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE }, + { "jitterbuffer", MISDN_CFG_JITTERBUFFER, MISDN_CTYPE_INT, "4000", NONE }, + { "jitterbuffer_upper_threshold", MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, MISDN_CTYPE_INT, "0", NONE }, + { "callgroup", MISDN_CFG_CALLGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE }, + { "pickupgroup", MISDN_CFG_PICKUPGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE }, + { "msns", MISDN_CFG_MSNS, MISDN_CTYPE_MSNLIST, NO_DEFAULT, NONE } +}; + +static const struct misdn_cfg_spec gen_spec[] = { + { "debug", MISDN_GEN_DEBUG, MISDN_CTYPE_INT, "0", NONE }, + { "misdn_init", MISDN_GEN_MISDN_INIT, MISDN_CTYPE_STR, "/etc/misdn-init.conf", NONE }, + { "tracefile", MISDN_GEN_TRACEFILE, MISDN_CTYPE_STR, "/var/log/asterisk/misdn.log", NONE }, + { "bridging", MISDN_GEN_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE }, + { "stop_tone_after_first_digit", MISDN_GEN_STOP_TONE, MISDN_CTYPE_BOOL, "yes", NONE }, + { "append_digits2exten", MISDN_GEN_APPEND_DIGITS2EXTEN, MISDN_CTYPE_BOOL, "yes", NONE }, + { "dynamic_crypt", MISDN_GEN_DYNAMIC_CRYPT, MISDN_CTYPE_BOOL, "no", NONE }, + { "crypt_prefix", MISDN_GEN_CRYPT_PREFIX, MISDN_CTYPE_STR, NO_DEFAULT, NONE }, + { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE }, + { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE }, + { "ntdebugfile", MISDN_GEN_NTDEBUGFILE, MISDN_CTYPE_STR, "/var/log/misdn-nt.log", NONE } +}; + +/* array of port configs, default is at position 0. */ +static union misdn_cfg_pt **port_cfg; +/* max number of available ports, is set on init */ +static int max_ports; +/* general config */ +static union misdn_cfg_pt *general_cfg; +/* storing the ptp flag separated to save memory */ +static int *ptp; +/* maps enum config elements to array positions */ +static int *map; + +static ast_mutex_t config_mutex; + +#define CLI_ERROR(name, value, section) ({ \ + ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \ + "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \ +}) + +static void _enum_array_map (void) +{ + int i, j; + + for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) { + if (i == MISDN_CFG_PTP) + continue; + for (j = 0; j < NUM_PORT_ELEMENTS; ++j) { + if (port_spec[j].elem == i) { + map[i] = j; + break; + } + } + } + for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) { + for (j = 0; j < NUM_GEN_ELEMENTS; ++j) { + if (gen_spec[j].elem == i) { + map[i] = j; + break; + } + } + } +} + +static int get_cfg_position (char *name, int type) +{ + int i; + + switch (type) { + case PORT_CFG: + for (i = 0; i < NUM_PORT_ELEMENTS; ++i) { + if (!strcasecmp(name, port_spec[i].name)) + return i; + } + break; + case GEN_CFG: + for (i = 0; i < NUM_GEN_ELEMENTS; ++i) { + if (!strcasecmp(name, gen_spec[i].name)) + return i; + } + } + + return -1; +} + +static inline void misdn_cfg_lock (void) +{ + ast_mutex_lock(&config_mutex); +} + +static inline void misdn_cfg_unlock (void) +{ + ast_mutex_unlock(&config_mutex); +} + +static void _free_msn_list (struct msn_list* iter) +{ + if (iter->next) + _free_msn_list(iter->next); + if (iter->msn) + free(iter->msn); + free(iter); +} + +static void _free_port_cfg (void) +{ + int i, j; + int gn = map[MISDN_CFG_GROUPNAME]; + union misdn_cfg_pt* free_list[max_ports + 2]; + + memset(free_list, 0, sizeof(free_list)); + free_list[0] = port_cfg[0]; + for (i = 1; i <= max_ports; ++i) { + if (port_cfg[i][gn].str) { + /* we always have a groupname in the non-default case, so this is fine */ + for (j = 1; j <= max_ports; ++j) { + if (free_list[j] && free_list[j][gn].str == port_cfg[i][gn].str) + break; + else if (!free_list[j]) { + free_list[j] = port_cfg[i]; + break; + } + } + } + } + for (j = 0; free_list[j]; ++j) { + for (i = 0; i < NUM_PORT_ELEMENTS; ++i) { + if (free_list[j][i].any) { + if (port_spec[i].type == MISDN_CTYPE_MSNLIST) + _free_msn_list(free_list[j][i].ml); + else + free(free_list[j][i].any); + } + } + } +} + +static void _free_general_cfg (void) +{ + int i; + + for (i = 0; i < NUM_GEN_ELEMENTS; i++) + if (general_cfg[i].any) + free(general_cfg[i].any); +} + +void misdn_cfg_get (int port, enum misdn_cfg_elements elem, void *buf, int bufsize) +{ + int place; + + if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) { + memset(buf, 0, bufsize); + ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port); + return; + } + + misdn_cfg_lock(); + if (elem == MISDN_CFG_PTP) { + if (!memcpy(buf, &ptp[port], (bufsize > ptp[port]) ? sizeof(ptp[port]) : bufsize)) + memset(buf, 0, bufsize); + } else { + if ((place = map[elem]) < 0) { + memset (buf, 0, bufsize); + ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Invalid element (%d) requested.\n", elem); + } else { + if (elem < MISDN_CFG_LAST) { + switch (port_spec[place].type) { + case MISDN_CTYPE_STR: + if (port_cfg[port][place].str) { + if (!memccpy(buf, port_cfg[port][place].str, 0, bufsize)) + memset(buf, 0, 1); + } else if (port_cfg[0][place].str) { + if (!memccpy(buf, port_cfg[0][place].str, 0, bufsize)) + memset(buf, 0, 1); + } + break; + default: + if (port_cfg[port][place].any) + memcpy(buf, port_cfg[port][place].any, bufsize); + else if (port_cfg[0][place].any) + memcpy(buf, port_cfg[0][place].any, bufsize); + else + memset(buf, 0, bufsize); + } + } else { + switch (gen_spec[place].type) { + case MISDN_CTYPE_STR: + if (!general_cfg[place].str || !memccpy(buf, general_cfg[place].str, 0, bufsize)) + memset(buf, 0, 1); + break; + default: + if (general_cfg[place].any) + memcpy(buf, general_cfg[place].any, bufsize); + else + memset(buf, 0, bufsize); + } + } + } + } + misdn_cfg_unlock(); +} + +int misdn_cfg_is_msn_valid (int port, char* msn) +{ + int re = 0; + struct msn_list *iter; + + if (!misdn_cfg_is_port_valid(port)) { + ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port); + return 0; + } + + misdn_cfg_lock(); + if (port_cfg[port][map[MISDN_CFG_MSNS]].ml) + iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml; + else + iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml; + for (; iter; iter = iter->next) + if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) { + re = 1; + break; + } + misdn_cfg_unlock(); + + return re; +} + +int misdn_cfg_is_port_valid (int port) +{ + return (port >= 1 && port <= max_ports); +} + +int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth) +{ + int i, re = 0; + char *method = NULL; + + misdn_cfg_lock(); + for (i = 1; i <= max_ports; i++) { + if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) { + if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group)) + method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ? + port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str); + } + } + if (method) { + switch (meth) { + case METHOD_STANDARD: re = !strcasecmp(method, "standard"); + break; + case METHOD_ROUND_ROBIN: re = !strcasecmp(method, "round_robin"); + break; + } + } + misdn_cfg_unlock(); + + return re; +} + +void misdn_cfg_get_ports_string (char *ports) +{ + char tmp[16]; + int l, i; + int gn = map[MISDN_CFG_GROUPNAME]; + + *ports = 0; + + misdn_cfg_lock(); + for (i = 1; i <= max_ports; i++) { + if (port_cfg[i][gn].str) { + if (ptp[i]) + sprintf(tmp, "%dptp,", i); + else + sprintf(tmp, "%d,", i); + strcat(ports, tmp); + } + } + misdn_cfg_unlock(); + + if ((l = strlen(ports))) + ports[l-1] = 0; +} + +void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize) +{ + int place; + char tempbuf[BUFFERSIZE] = ""; + struct msn_list *iter; + + if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) { + *buf = 0; + ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port); + return; + } + + place = map[elem]; + + misdn_cfg_lock(); + if (elem == MISDN_CFG_PTP) { + snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no"); + } + else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) { + switch (port_spec[place].type) { + case MISDN_CTYPE_INT: + case MISDN_CTYPE_BOOLINT: + if (port_cfg[port][place].num) + snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num); + else if (port_cfg[0][place].num) + snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num); + else + snprintf(buf, bufsize, " -> %s:", port_spec[place].name); + break; + case MISDN_CTYPE_BOOL: + if (port_cfg[port][place].num) + snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no"); + else if (port_cfg[0][place].num) + snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no"); + else + snprintf(buf, bufsize, " -> %s:", port_spec[place].name); + break; + case MISDN_CTYPE_ASTGROUP: + if (port_cfg[port][place].grp) + snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, + ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp)); + else if (port_cfg[0][place].grp) + snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, + ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp)); + else + snprintf(buf, bufsize, " -> %s:", port_spec[place].name); + break; + case MISDN_CTYPE_MSNLIST: + if (port_cfg[port][place].ml) + iter = port_cfg[port][place].ml; + else + iter = port_cfg[0][place].ml; + if (iter) { + for (; iter; iter = iter->next) + sprintf(tempbuf, "%s%s, ", tempbuf, iter->msn); + tempbuf[strlen(tempbuf)-2] = 0; + } + snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none"); + break; + case MISDN_CTYPE_STR: + if ( port_cfg[port][place].str) { + snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str); + } else if (port_cfg[0][place].str) { + snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str); + } else { + snprintf(buf, bufsize, " -> %s:", port_spec[place].name); + } + break; + } + } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) { + switch (gen_spec[place].type) { + case MISDN_CTYPE_INT: + case MISDN_CTYPE_BOOLINT: + if (general_cfg[place].num) + snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num); + else + snprintf(buf, bufsize, " -> %s:", gen_spec[place].name); + break; + case MISDN_CTYPE_BOOL: + if (general_cfg[place].num) + snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no"); + else + snprintf(buf, bufsize, " -> %s:", gen_spec[place].name); + break; + case MISDN_CTYPE_STR: + if ( general_cfg[place].str) { + snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str); + } else { + snprintf(buf, bufsize, " -> %s:", gen_spec[place].name); + } + break; + default: + snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name); + break; + } + } else { + *buf = 0; + ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem); + } + misdn_cfg_unlock(); +} + +int misdn_cfg_get_next_port (int port) +{ + int p = -1; + int gn = map[MISDN_CFG_GROUPNAME]; + + misdn_cfg_lock(); + for (port++; port <= max_ports; port++) { + if (port_cfg[port][gn].str) { + p = port; + break; + } + } + misdn_cfg_unlock(); + + return p; +} + +int misdn_cfg_get_next_port_spin (int port) +{ + int p = misdn_cfg_get_next_port(port); + return (p > 0) ? p : misdn_cfg_get_next_port(0); +} + +static int _parse (union misdn_cfg_pt *dest, char *value, enum misdn_cfg_type type, int boolint_def) +{ + int re = 0; + int len, tmp; + char *valtmp; + + switch (type) { + case MISDN_CTYPE_STR: + if ((len = strlen(value))) { + dest->str = (char *)malloc((len + 1) * sizeof(char)); + strncpy(dest->str, value, len); + dest->str[len] = 0; + } else { + dest->str = (char *)malloc( sizeof(char)); + dest->str[0] = 0; + } + break; + case MISDN_CTYPE_INT: + { + char *pat; + if (strchr(value,'x')) + pat="%x"; + else + pat="%d"; + if (sscanf(value, pat, &tmp)) { + dest->num = (int *)malloc(sizeof(int)); + memcpy(dest->num, &tmp, sizeof(int)); + } else + re = -1; + } + break; + case MISDN_CTYPE_BOOL: + dest->num = (int *)malloc(sizeof(int)); + *(dest->num) = (ast_true(value) ? 1 : 0); + break; + case MISDN_CTYPE_BOOLINT: + dest->num = (int *)malloc(sizeof(int)); + if (sscanf(value, "%d", &tmp)) { + memcpy(dest->num, &tmp, sizeof(int)); + } else { + *(dest->num) = (ast_true(value) ? boolint_def : 0); + } + break; + case MISDN_CTYPE_MSNLIST: + for (valtmp = strsep(&value, ","); valtmp; valtmp = strsep(&value, ",")) { + if ((len = strlen(valtmp))) { + struct msn_list *ml = (struct msn_list *)malloc(sizeof(struct msn_list)); + ml->msn = (char *)calloc(len+1, sizeof(char)); + strncpy(ml->msn, valtmp, len); + ml->next = dest->ml; + dest->ml = ml; + } + } + break; + case MISDN_CTYPE_ASTGROUP: + dest->grp = (ast_group_t *)malloc(sizeof(ast_group_t)); + *(dest->grp) = ast_get_group(value); + break; + } + + return re; +} + +static void _build_general_config (struct ast_variable *v) +{ + int pos; + + for (; v; v = v->next) { + if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) || + (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0)) + CLI_ERROR(v->name, v->value, "general"); + } +} + +static void _build_port_config (struct ast_variable *v, char *cat) +{ + int pos, i; + union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS]; + int cfg_for_ports[max_ports + 1]; + + if (!v || !cat) + return; + + memset(cfg_tmp, 0, sizeof(cfg_tmp)); + memset(cfg_for_ports, 0, sizeof(cfg_for_ports)); + + if (!strcasecmp(cat, "default")) { + cfg_for_ports[0] = 1; + } + + if (((pos = get_cfg_position("name", PORT_CFG)) < 0) || + (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) { + CLI_ERROR(v->name, v->value, cat); + return; + } + + for (; v; v = v->next) { + if (!strcasecmp(v->name, "ports")) { + char *token; + char ptpbuf[BUFFERSIZE] = ""; + int start, end; + for (token = strsep(&v->value, ","); token; token = strsep(&v->value, ","), *ptpbuf = 0) { + if (!*token) + continue; + if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) { + for (; start <= end; start++) { + if (start <= max_ports && start > 0) { + cfg_for_ports[start] = 1; + ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0; + } else + CLI_ERROR(v->name, v->value, cat); + } + } else { + if (sscanf(token, "%d%s", &start, ptpbuf)) { + if (start <= max_ports && start > 0) { + cfg_for_ports[start] = 1; + ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0; + } else + CLI_ERROR(v->name, v->value, cat); + } else + CLI_ERROR(v->name, v->value, cat); + } + } + } else { + if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) || + (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) + CLI_ERROR(v->name, v->value, cat); + } + } + + for (i = 0; i < (max_ports + 1); ++i) { + if (cfg_for_ports[i]) { + memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp)); + } + } +} + +void misdn_cfg_update_ptp (void) +{ + char misdn_init[BUFFERSIZE]; + char line[BUFFERSIZE]; + FILE *fp; + char *tok, *p, *end; + int port; + + misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init)); + + if (misdn_init) { + fp = fopen(misdn_init, "r"); + if (fp) { + while(fgets(line, sizeof(line), fp)) { + if (!strncmp(line, "nt_ptp", 6)) { + for (tok = strtok_r(line,",=", &p); + tok; + tok = strtok_r(NULL,",=", &p)) { + port = strtol(tok, &end, 10); + if (end != tok && misdn_cfg_is_port_valid(port)) { + misdn_cfg_lock(); + ptp[port] = 1; + misdn_cfg_unlock(); + } + } + } + } + fclose(fp); + } else { + ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno)); + } + } +} + +static void _fill_defaults (void) +{ + int i; + + for (i = 0; i < NUM_PORT_ELEMENTS; ++i) { + if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT)) + _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def); + } + for (i = 0; i < NUM_GEN_ELEMENTS; ++i) { + if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT)) + _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def); + } +} + +void misdn_cfg_reload (void) +{ + misdn_cfg_init (0); +} + +void misdn_cfg_destroy (void) +{ + misdn_cfg_lock(); + + _free_port_cfg(); + _free_general_cfg(); + + free(port_cfg); + free(general_cfg); + free(ptp); + free(map); + + misdn_cfg_unlock(); + ast_mutex_destroy(&config_mutex); +} + +void misdn_cfg_init (int this_max_ports) +{ + char config[] = "misdn.conf"; + char *cat, *p; + int i; + struct ast_config *cfg; + struct ast_variable *v; + + if (!(cfg = AST_LOAD_CFG(config))) { + ast_log(LOG_WARNING,"no misdn.conf ?\n"); + return; + } + + misdn_cfg_lock(); + + if (this_max_ports) { + /* this is the first run */ + max_ports = this_max_ports; + 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; + p += (max_ports + 1) * sizeof(union misdn_cfg_pt *); + for (i = 0; i <= max_ports; ++i) { + port_cfg[i] = (union misdn_cfg_pt *)p; + p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt); + } + 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 */ + _free_port_cfg(); + _free_general_cfg(); + memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1)); + memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS); + memset(ptp, 0, sizeof(int) * (max_ports + 1)); + } + + cat = ast_category_browse(cfg, NULL); + + while(cat) { + v = ast_variable_browse(cfg, cat); + if (!strcasecmp(cat,"general")) { + _build_general_config(v); + } else { + _build_port_config(v, cat); + } + cat = ast_category_browse(cfg,cat); + } + + _fill_defaults(); + + misdn_cfg_unlock(); + AST_DESTROY_CFG(cfg); +} |