📄 isdn_lib.c
字号:
/* * Chan_Misdn -- Channel Driver for Asterisk * * Interface to mISDN * * Copyright (C) 2004, Christian Richter * * Christian Richter <crich@beronet.com> * * This program is free software, distributed under the terms of * the GNU General Public License */#include <syslog.h>#include <mISDNuser/isdn_debug.h>#include "isdn_lib_intern.h"#include "isdn_lib.h"void misdn_join_conf(struct misdn_bchannel *bc, int conf_id);void misdn_split_conf(struct misdn_bchannel *bc, int conf_id);int queue_cleanup_bc(struct misdn_bchannel *bc) ;int misdn_lib_get_l2_up(struct misdn_stack *stack);struct misdn_stack* get_misdn_stack( void );int misdn_lib_port_is_pri(int port){ struct misdn_stack *stack=get_misdn_stack(); for ( ; stack; stack=stack->next) { if (stack->port == port) { return stack->pri; } } return -1;}int misdn_lib_port_block(int port){ struct misdn_stack *stack=get_misdn_stack(); for ( ; stack; stack=stack->next) { if (stack->port == port) { stack->blocked=1; return 0; } } return -1;}int misdn_lib_port_unblock(int port){ struct misdn_stack *stack=get_misdn_stack(); for ( ; stack; stack=stack->next) { if (stack->port == port) { stack->blocked=0; return 0; } } return -1;}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){ struct misdn_stack *stack=get_misdn_stack(); for ( ; stack; stack=stack->next) { if (stack->port == port) return stack->ptp; } 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){ struct misdn_stack *stack=get_misdn_stack(); if (!bc) return NULL; for ( ; stack; stack=stack->next) { int i; for (i=0; i <=stack->b_num; i++) { if ( bc->port == stack->port) return stack; } } return NULL;}void get_show_stack_details(int port, char *buf){ struct misdn_stack *stack=get_misdn_stack(); for ( ; stack; stack=stack->next) { if (stack->port == port) break; } if (stack) { 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; } }static int nt_err_cnt =0 ;enum global_states { MISDN_INITIALIZING, MISDN_INITIALIZED} ;static enum global_states global_state=MISDN_INITIALIZING;#include <mISDNuser/net_l2.h>#include <mISDNuser/tone.h>#include <unistd.h>#include <semaphore.h>#include <pthread.h>#include <signal.h>#include "isdn_lib.h"struct misdn_lib { int midev; int midev_nt; pthread_t event_thread; pthread_t event_handler_thread; void *user_data; msg_queue_t upqueue; msg_queue_t activatequeue; sem_t new_msg; struct misdn_stack *stack_list;} ;#ifndef ECHOCAN_ON#define ECHOCAN_ON 123#define ECHOCAN_OFF 124#endif#define MISDN_DEBUG 0void misdn_tx_jitter(struct misdn_bchannel *bc, int len);struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id);struct misdn_bchannel *find_bc_by_confid(unsigned long confid);struct misdn_bchannel *stack_holder_find_bychan(struct misdn_stack *stack, int chan);int setup_bc(struct misdn_bchannel *bc);int manager_isdn_handler(iframe_t *frm ,msg_t *msg);int misdn_lib_port_restart(int port);int misdn_lib_pid_restart(int pid);extern struct isdn_msg msgs_g[]; #define ISDN_PID_L3_B_USER 0x430000ff#define ISDN_PID_L4_B_USER 0x440000ff/* #define MISDN_IBUF_SIZE 1024 */#define MISDN_IBUF_SIZE 512/* Fine Tuning of Inband Signalling time */#define TONE_ALERT_CNT 41 /* 1 Sec */#define TONE_ALERT_SILENCE_CNT 200 /* 4 Sec */#define TONE_BUSY_CNT 20 /* ? */#define TONE_BUSY_SILENCE_CNT 48 /* ? */static int entity;static struct misdn_lib *glob_mgr;char tone_425_flip[TONE_425_SIZE];char tone_silence_flip[TONE_SILENCE_SIZE];static void misdn_lib_isdn_event_catcher(void *arg);static int handle_event_nt(void *dat, void *arg);void stack_holder_add(struct misdn_stack *stack, struct misdn_bchannel *holder);void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holder);struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned long l3id);/* 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_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);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);void manager_bchannel_cleanup (struct misdn_bchannel *bc);void ec_chunk( struct misdn_bchannel *bc, unsigned char *rxchunk, unsigned char *txchunk, int chunk_size); /* end */int bchdev_echocancel_activate(struct misdn_bchannel* dev);void bchdev_echocancel_deactivate(struct misdn_bchannel* dev);/* end */static char *bearer2str(int cap) { static char *bearers[]={ "Speech", "Audio 3.1k", "Unres Digital", "Res Digital", "Unknown Bearer" }; switch (cap) { case INFO_CAPABILITY_SPEECH: return bearers[0]; break; case INFO_CAPABILITY_AUDIO_3_1K: return bearers[1]; break; case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: return bearers[2]; break; case INFO_CAPABILITY_DIGITAL_RESTRICTED: return bearers[3]; break; default: return bearers[4]; break; }}static char flip_table[256];static void init_flip_bits(void){ 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 char * flip_buf_bits ( char * buf , int len){ int i; char * start = buf; for (i = 0 ; i < len; i++) { buf[i] = flip_table[(unsigned char)buf[i]]; } return start;}static msg_t *create_l2msg(int prim, int dinfo, int size) /* NT only */{ int i = 0; msg_t *dmsg; while(i < 10) { dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL); if (dmsg) return(dmsg); if (!i) printf("cannot allocate memory, trying again...\n"); i++; usleep(300000); } printf("cannot allocate memory, system overloaded.\n"); exit(-1);}msg_t *create_l3msg(int prim, int mt, int dinfo, int size, int ntmode){ int i = 0; msg_t *dmsg; Q931_info_t *qi; iframe_t *frm; if (!ntmode) size = sizeof(Q931_info_t)+2; while(i < 10) { if (ntmode) { dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL); if (dmsg) { return(dmsg); } } else { dmsg = alloc_msg(size+256+mISDN_HEADER_LEN+DEFAULT_HEADROOM); if (dmsg) { memset(msg_put(dmsg,size+mISDN_HEADER_LEN), 0, size+mISDN_HEADER_LEN); frm = (iframe_t *)dmsg->data; frm->prim = prim; frm->dinfo = dinfo; qi = (Q931_info_t *)(dmsg->data + mISDN_HEADER_LEN); qi->type = mt; return(dmsg); } } if (!i) printf("cannot allocate memory, trying again...\n"); i++; usleep(300000); } printf("cannot allocate memory, system overloaded.\n"); exit(-1);}static 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 | 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=1;int misdn_cap_is_speech(int cap)/** Poor mans version **/{ if ( (cap != INFO_CAPABILITY_DIGITAL_UNRESTRICTED) && (cap != INFO_CAPABILITY_DIGITAL_RESTRICTED) ) return 1; return 0;}int misdn_inband_avail(struct misdn_bchannel *bc){ /*if ! early_bconnect we have never inband available*/ if ( ! bc->early_bconnect ) return 0; switch (bc->progress_indicator) { case INFO_PI_INBAND_AVAILABLE: case INFO_PI_CALL_NOT_E2E_ISDN: case INFO_PI_CALLED_NOT_ISDN: return 1; default: return 0; } return 0;}static void dump_chan_list(struct misdn_stack *stack){ int i; for (i=0; i <= stack->b_num; i++) { cb_log(6, stack->port, "Idx:%d stack->cchan:%d Chan:%d\n",i,stack->channels[i], i+1); }}static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchannel *bc, int channel, int dec){ int i; cb_log(5,stack->port,"find_free_chan: req_chan:%d\n",channel); if (channel < 0 || channel > MAX_BCHANS) { cb_log(0, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel); return 0; } channel--; int bnums=stack->pri?stack->b_num:stack->b_num-1; if (dec) { for (i = bnums; i >=0; i--) { if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 Dchannel ;) and work with chan preselection */ if (!stack->channels[i]) { cb_log (3, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1); bc->channel=i+1; return i+1; } } } } else { for (i = 0; i <= bnums; i++) { if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 Dchannel ;) and work with chan preselection */ if (!stack->channels[i]) { cb_log (3, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1); bc->channel=i+1; return i+1; } } } } cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n"); dump_chan_list(stack); return 0;}static int empty_chan_in_stack(struct misdn_stack *stack, int channel){ if (channel<=0 || channel>MAX_BCHANS) { cb_log(0,stack?stack->port:0, "empty_chan_in_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: l3id:%x from:%s to:%s\n", bc->l3_id, 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; }}static 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;}static void empty_bc(struct misdn_bchannel *bc){ bc->bframe_len=0; bc->in_use= 0; bc->cw= 0; bc->dec=0; bc->channel = 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; bc->txgain=0; bc->crypt=0; bc->curptx=0; bc->curprx=0; bc->crypt_key[0] = 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; bc->early_bconnect = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -