modified: chan_lcr.c
[lcr.git] / chan_lcr.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** Asterisk socket client                                                    **
9 **                                                                           **
10 \*****************************************************************************/
11
12 /*
13
14 How does it work:
15
16 To connect, open a socket and send a MESSAGE_HELLO to admin socket with
17 the application name. This name is unique an can be used for routing calls.
18
19 To make a call, send a MESSAGE_NEWREF and a new reference is received.
20 When receiving a call, a new reference is received.
21 The reference is received with MESSAGE_NEWREF.
22
23 Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference.
24
25 To release call and reference, send or receive MESSAGE_RELEASE.
26 From that point on, the ref is not valid, so no other message may be sent
27 with that reference.
28
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #include "extension.h"
44 #include "message.h"
45 #include "lcrsocket.h"
46 #include "cause.h"
47 #include "bchannel.h"
48 #include "chan_lcr.h"
49
50 int lcr_sock = -1;
51
52 struct admin_list {
53         struct admin_list *next;
54         struct admin_msg msg;
55 } *admin_first = NULL;
56
57 /*
58  * channel and call instances
59  */
60 struct chan_call *call_first;
61
62 struct chan_call *find_call_ref(unsigned long ref)
63 {
64         struct chan_call *call = call_first;
65
66         while(call)
67         {
68                 if (call->ref == ref)
69                         break;
70                 call = call->next;
71         }
72         return(call);
73 }
74
75 struct chan_call *find_call_handle(unsigned long handle)
76 {
77         struct chan_call *call = call_first;
78
79         while(call)
80         {
81                 if (call->bchannel_handle == handle)
82                         break;
83                 call = call->next;
84         }
85         return(call);
86 }
87
88 struct chan_call *alloc_call(void)
89 {
90         struct chan_call **callp = &call_first;
91
92         while(*callp)
93                 callp = &((*callp)->next);
94
95         *callp = (struct chan_call *)malloc(sizeof(struct chan_call));
96         return(*callp);
97 }
98
99 void free_call(struct chan_call *call)
100 {
101         struct chan_call **temp = &call_first;
102
103         while(*temp)
104         {
105                 if (*temp == call)
106                 {
107                         *temp = (*temp)->next;
108                         free(call);
109                         return;
110                 }
111                 temp = &((*temp)->next);
112         }
113 }
114
115 unsigned short new_brige_id(void)
116 {
117         struct chan_call *call;
118         unsigned short id = 1;
119
120         /* search for lowest bridge id that is not in use and not 0 */
121         while(id)
122         {
123                 call = call_first;
124                 while(call)
125                 {
126                         if (call->bridge_id == id)
127                                 break;
128                         call = call->next;
129                 }
130                 if (!call)
131                         break;
132                 id++;
133         }
134         return(id);
135 }
136
137
138 /*
139  * receive bchannel data
140  */
141 void rx_data(struct bchannel *bchannel, unsigned char *data, int len)
142 {
143 }
144
145 void rx_dtmf(struct bchannel *bchannel, char tone)
146 {
147 }
148
149 /*
150  * enque message to LCR
151  */
152 int send_message(int message_type, unsigned long ref, union parameter *param)
153 {
154         struct admin_list *admin, **adminp;
155
156         adminp = &admin_first;
157         while(*adminp)
158                 adminp = &((*adminp)->next);
159         admin = (struct admin_list *)malloc(sizeof(struct admin_list));
160         *adminp = admin;
161
162         admin->msg.type = message_type;
163         admin->msg.ref = ref;
164         memcpy(&admin->msg.param, param, sizeof(union parameter));
165
166         return(0);
167 }
168
169 /*
170  * message received from LCR
171  */
172 int receive_message(int message_type, unsigned long ref, union parameter *param)
173 {
174         union parameter newparam;
175         struct bchannel *bchannel;
176         struct chan_call *call;
177
178         memset(&newparam, 0, sizeof(union parameter));
179
180         /* handle bchannel message*/
181         if (message_type == MESSAGE_BCHANNEL)
182         {
183                 switch(param->bchannel.type)
184                 {
185                         case BCHANNEL_ASSIGN:
186                         if ((bchannel = find_bchannel_handle(param->bchannel.handle)))
187                         {
188                                 fprintf(stderr, "error: bchannel handle %x already assigned.\n", param->bchannel.handle);
189                                 return(-1);
190                         }
191                         /* create bchannel */
192                         bchannel = alloc_bchannel(param->bchannel.handle);
193                         if (!bchannel)
194                         {
195                                 fprintf(stderr, "error: alloc bchannel handle %x failed.\n", param->bchannel.handle);
196                                 return(-1);
197                         }
198
199                         /* configure channel */
200                         bchannel->b_tx_gain = param->bchannel.tx_gain;
201                         bchannel->b_rx_gain = param->bchannel.rx_gain;
202                         strncpy(bchannel->b_pipeline, param->bchannel.pipeline, sizeof(bchannel->b_pipeline)-1);
203                         if (param->bchannel.crypt_len)
204                         {
205                                 bchannel->b_crypt_len = param->bchannel.crypt_len;
206                                 bchannel->b_crypt_type = param->bchannel.crypt_type;
207                                 memcpy(bchannel->b_crypt_key, param->bchannel.crypt, param->bchannel.crypt_len);
208                         }
209                         bchannel->b_txdata = 0;
210                         bchannel->b_dtmf = 1;
211                         bchannel->b_tx_dejitter = 1;
212
213                         /* in case, ref is not set, this bchannel instance must
214                          * be created until it is removed again by LCR */
215                         /* link to call */
216                         if ((call = find_call_ref(ref)))
217                         {
218                                 bchannel->ref = ref;
219                                 call->bchannel_handle = param->bchannel.handle;
220 #warning hier muesen alle stati gesetzt werden falls sie vor dem b-kanal verf├╝gbar waren
221                                 bchannel_join(call->bridge_id);
222                         }
223                         if (bchannel_create(bchannel))
224                                 bchannel_activate(bchannel, 1);
225
226                         /* acknowledge */
227                         newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
228                         newparam.bchannel.handle = param->bchannel.handle;
229                         send_message(MESSAGE_BCHANNEL, 0, &newparam);
230                         break;
231
232                         case BCHANNEL_REMOVE:
233                         if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
234                         {
235                                 alle fprintf nach ast_log
236                                 fprintf(stderr, "error: bchannel handle %x not assigned.\n", param->bchannel.handle);
237                                 return(-1);
238                         }
239                         /* unlink from call */
240                         if ((call = find_call_ref(bchannel->ref)))
241                         {
242                                 call->bchannel_handle = 0;
243                         }
244                         /* destroy and remove bchannel */
245                         free_bchannel(bchannel);
246
247                         /* acknowledge */
248                         newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
249                         newparam.bchannel.handle = param->bchannel.handle;
250                         send_message(MESSAGE_BCHANNEL, 0, &newparam);
251                         
252                         break;
253
254                         default:
255                         fprintf(stderr, "received unknown bchannel message %d\n", param->bchannel.type);
256                 }
257                 return(0);
258         }
259
260         /* handle new ref */
261         if (message_type == MESSAGE_NEWREF)
262         {
263                 if (param->direction)
264                 {
265                         /* new ref from lcr */
266                         if (!ref || find_call_ref(ref))
267                         {
268                                 fprintf(stderr, "illegal new ref %d received\n", ref);
269                                 return(-1);
270                         }
271                         call = alloc_call();
272                         call->ref = ref;
273                 } else
274                 {
275                         /* new ref, as requested from this remote application */
276                         call = find_call_ref(0);
277                         if (!call)
278                         {
279                                 /* send release, if ref does not exist */
280                                 newparam.disconnectinfo.cause = CAUSE_NORMAL;
281                                 newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
282                                 send_message(MESSAGE_RELEASE, ref, &newparam);
283                                 return(0);
284                         }
285                         call->ref = ref;
286 #warning process call (send setup, if pending)
287                 }
288                 return(0);
289         }
290
291         /* check ref */
292         if (!ref)
293         {
294                 fprintf(stderr, "received message %d without ref\n", message_type);
295                 return(-1);
296         }
297         call = find_call_ref(ref);
298         if (!call)
299         {
300                 /* ignore ref that is not used (anymore) */
301                 return(0);
302         }
303
304         /* handle messages */
305         switch(message_type)
306         {
307                 case MESSAGE_SETUP:
308 todo
309                 break;
310
311                 case MESSAGE_OVERLAP:
312 todo
313                 break;
314
315                 case MESSAGE_PROCEEDING:
316 todo
317                 break;
318
319                 case MESSAGE_ALERTING:
320 todo
321                 break;
322
323                 case MESSAGE_CONNECT:
324 todo
325                 break;
326
327                 case MESSAGE_DISCONNECT:
328 todo
329                 break;
330
331                 case MESSAGE_RELEASE:
332 todo
333                 free_call(call);
334                 return(0);
335
336                 case MESSAGE_INFORMATION:
337 todo
338                 break;
339
340                 case MESSAGE_FACILITY:
341 todo
342                 break;
343
344                 case MESSAGE_PATTERN:
345 todo
346                 break;
347
348                 case MESSAGE_NOPATTERN:
349 todo
350                 break;
351
352                 case MESSAGE_AUDIOPATH:
353 todo
354                 break;
355
356                 default:
357 unhandled
358         }
359         return(0);
360 }
361
362
363 /* asterisk handler
364  * warning! not thread safe
365  * returns -1 for socket error, 0 for no work, 1 for work
366  */
367 int handle_socket(void)
368 {
369         int work = 0;
370         int len;
371         struct admin_message msg;
372         struct admin_list *admin;
373
374         /* read from socket */
375         len = read(sock, &msg, sizeof(msg));
376         if (len == 0)
377         {
378                 printf("Socket closed\n");
379                 return(-1); // socket closed
380         }
381         if (len > 0)
382         {
383                 if (len != sizeof(msg))
384                 {
385                         fprintf(stderr, "Socket short read (%d)\n", len);
386                         return(-1); // socket error
387                 }
388                 if (msg.message != ADMIN_MESSAGE)
389                 {
390                         fprintf(stderr, "Socket received illegal message %d\n", msg.message);
391                         return(-1); // socket error
392                 }
393                 receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
394                 printf("message received %d\n", msg.u.msg.type);
395                 work = 1;
396         } else
397         {
398                 if (errno != EWOULDBLOCK)
399                 {
400                         fprintf(stderr, "Socket error %d\n", errno);
401                         return(-1);
402                 }
403         }
404
405         /* write to socket */
406         if (!admin_first)
407                 return(work);
408         admin = admin_first;
409         len = write(sock, &admin->msg, sizeof(msg));
410         if (len == 0)
411         {
412                 printf("Socket closed\n");
413                 return(-1); // socket closed
414         }
415         if (len > 0)
416         {
417                 if (len != sizeof(msg))
418                 {
419                         fprintf(stderr, "Socket short write (%d)\n", len);
420                         return(-1); // socket error
421                 }
422                 /* free head */
423                 admin_first = admin->next;
424                 free(admin);
425
426                 work = 1;
427         } else
428         {
429                 if (errno != EWOULDBLOCK)
430                 {
431                         fprintf(stderr, "Socket error %d\n", errno);
432                         return(-1);
433                 }
434         }
435
436         return(work);
437 }
438
439 /*
440  * open and close socket
441  */
442 int open_socket(void)
443 {
444         int ret;
445         int sock;
446         char *socket_name = SOCKET_NAME;
447         int conn;
448         struct sockaddr_un sock_address;
449         int ret;
450         unsigned long on = 1;
451         union parameter param;
452
453         /* open socket */
454         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
455         {
456                 ast_log(LOG_ERROR, "Failed to create socket.\n");
457                 return(sock);
458         }
459
460         /* set socket address and name */
461         memset(&sock_address, 0, sizeof(sock_address));
462         sock_address.sun_family = PF_UNIX;
463         strcpy(sock_address.sun_path, socket_name);
464
465         /* connect socket */
466         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
467         {
468                 close(sock);
469                 ast_log(LOG_ERROR, "Failed to connect to socket \"%s\". Is LCR running?\n", sock_address.sun_path);
470                 return(conn);
471         }
472
473         /* set non-blocking io */
474         if ((ret = ioctl(sock, FIONBIO, (unsigned char *)(&on))) < 0)
475         {
476                 close(sock);
477                 ast_log(LOG_ERROR, "Failed to set socket into non-blocking IO.\n");
478                 return(ret);
479         }
480
481         /* enque hello message */
482         memset(&param, 0, sizeof(param));
483         strcpy(param.hello.application, "asterisk");
484         send_message(MESSAGE_HELLO, 0, &param);
485
486         return(sock);
487 }
488
489 void close_socket(int sock)
490 {
491         /* close socket */
492         if (socket >= 0)        
493                 close(sock);
494 }
495
496
497 void lcr_thread(void)
498 {
499         int work;
500
501         while(42)
502         {
503                 work = 0;
504
505                 /* handle socket */
506                 ret = handle_socket();
507                 if (ret < 0)
508                         break;
509                 if (ret)
510                         work = 1;
511
512                 /* handle mISDN */
513                 ret = bchannel_handle();
514                 if (ret)
515                         work = 1;
516                 
517                 if (!work)
518                         usleep(30000);
519         }
520 }
521
522 /* call from asterisk (new instance) */
523 static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
524 {
525         int port=0;
526         int r;
527         struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast);
528         struct misdn_bchannel *newbc;
529         char *opts=NULL, *ext;
530         char dest_cp[256];
531         
532         {
533                 strncpy(dest_cp,dest,sizeof(dest_cp)-1);
534                 dest_cp[sizeof(dest_cp)]=0;
535
536                 ext=dest_cp;
537                 strsep(&ext,"/");
538                 if (ext) {
539                         opts=ext;
540                         strsep(&opts,"/");
541                 }  else {
542                         ast_log(LOG_WARNING, "Malformed dialstring\n");
543                         return -1;
544                 }
545         }
546
547         if (!ast) {
548                 ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
549                 return -1;
550         }
551
552         if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest  ) {
553                 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
554                 ast->hangupcause=41;
555                 ast_setstate(ast, AST_STATE_DOWN);
556                 return -1;
557         }
558
559         if (!ch) {
560                 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
561                 ast->hangupcause=41;
562                 ast_setstate(ast, AST_STATE_DOWN);
563                 return -1;
564         }
565         
566         newbc=ch->bc;
567         
568         if (!newbc) {
569                 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
570                 ast->hangupcause=41;
571                 ast_setstate(ast, AST_STATE_DOWN);
572                 return -1;
573         }
574         
575         port=newbc->port;
576
577         
578         chan_misdn_log(1, port, "* CALL: %s\n",dest);
579         
580         chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context);
581         
582         chan_misdn_log(3, port, " --> * adding2newbc ext %s\n",ast->exten);
583         if (ast->exten) {
584                 int l = sizeof(newbc->dad);
585                 strncpy(ast->exten,ext,sizeof(ast->exten));
586
587                 strncpy(newbc->dad,ext,l);
588
589                 newbc->dad[l-1] = 0;
590         }
591         newbc->rad[0]=0;
592         chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n",AST_CID_P(ast));
593         if (ast_strlen_zero(newbc->oad) && AST_CID_P(ast) ) {
594
595                 if (AST_CID_P(ast)) {
596                         int l = sizeof(newbc->oad);
597                         strncpy(newbc->oad,AST_CID_P(ast), l);
598                         newbc->oad[l-1] = 0;
599                 }
600         }
601
602         {
603                 struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast);
604                 if (!ch) { ast_verbose("No chan_list in misdn_call\n"); return -1;}
605                 
606                 newbc->capability=ast->transfercapability;
607                 pbx_builtin_setvar_helper(ast,"TRANSFERCAPABILITY",ast_transfercapability2str(newbc->capability));
608                 if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
609                         chan_misdn_log(2, port, " --> * Call with flag Digital\n");
610                 }
611                 
612
613                 /* update screening and presentation */ 
614                 update_config(ch,ORG_AST);
615                 
616                 /* fill in some ies from channel vary*/
617                 import_ch(ast, newbc, ch);
618                 
619                 /* Finally The Options Override Everything */
620                 if (opts)
621                         misdn_set_opt_exec(ast,opts);
622                 else
623                         chan_misdn_log(2,port,"NO OPTS GIVEN\n");
624
625                 /*check for bridging*/
626                 int bridging;
627                 misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int));
628                 if (bridging && ch->other_ch) {
629                         chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
630                         *ch->bc->pipeline=0;
631                         *ch->other_ch->bc->pipeline=0;
632                 }
633                 
634                 r=misdn_lib_send_event( newbc, EVENT_SETUP );
635                 
636                 /** we should have l3id after sending setup **/
637                 ch->l3id=newbc->l3_id;
638         }
639         
640         if ( r == -ENOCHAN  ) {
641                 chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
642                 chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n",newbc?newbc->pid:-1);
643                 ast->hangupcause=34;
644                 ast_setstate(ast, AST_STATE_DOWN);
645                 return -1;
646         }
647         
648         chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n",newbc?newbc->pid:1);
649
650         ast_setstate(ast, AST_STATE_DIALING);
651         ast->hangupcause=16;
652
653 wenn pattern available soll gestoppt werden, sonst nicht:       
654         if (newbc->nt) stop_bc_tones(ch);
655
656         ch->state=MISDN_CALLING;
657         
658         return 0; 
659 }
660
661
662 static struct ast_channel_tech misdn_tech = {
663         .type="lcr",
664         .description="Channel driver for connecting to Linux-Call-Router",
665         .capabilities= je nach option?AST_FORMAT_ALAW:AST_FORMAT_ULAW ,
666         .requester=lcr_request,
667         .send_digit=lcr_digit,
668         .call=lcr_call,
669         .bridge=lcr_bridge, 
670         .hangup=lcr_hangup,
671         .answer=lcr_answer,
672         .read=lcr_read,
673         .write=lcr_write,
674         .indicate=lcr_indication,
675         .fixup=lcr_fixup,
676         .send_text=lcr_send_text,
677         .properties=0
678 };
679
680 /*
681  * cli
682  */
683 static int cli_show_lcr (int fd, int argc, char *argv[])
684 {
685 }
686
687 static int cli_show_calls (int fd, int argc, char *argv[])
688 {
689 }
690
691 static int cli_reload_routing (int fd, int argc, char *argv[])
692 {
693 }
694
695 static int cli_reload_interfaces (int fd, int argc, char *argv[])
696 {
697 }
698
699 static int cli_port_block (int fd, int argc, char *argv[])
700 {
701 }
702
703 static int cli_port_unblock (int fd, int argc, char *argv[])
704 {
705 }
706
707 static int cli_port_unload (int fd, int argc, char *argv[])
708 {
709 }
710
711 static struct ast_cli_entry cli_show_lcr =
712 { {"lcr", "show", "lcr", NULL},
713  lcr_show_lcr,
714  "Shows current states of LCR core",
715  "Usage: lcr show lcr\n",
716 };
717
718 static struct ast_cli_entry cli_show_calls =
719 { {"lcr", "show", "calls", NULL},
720  lcr_show_calls,
721  "Shows current calls made by LCR and Asterisk",
722  "Usage: lcr show calls\n",
723 };
724
725 static struct ast_cli_entry cli_reload_routing =
726 { {"lcr", "reload", "routing", NULL},
727  lcr_reload_routing,
728  "Reloads routing conf of LCR, current uncomplete calls will be disconnected",
729  "Usage: lcr reload routing\n",
730 };
731
732 static struct ast_cli_entry cli_reload_interfaces =
733 { {"lcr", "reload", "interfaces", NULL},
734  lcr_reload_interfaces,
735  "Reloads interfaces conf of LCR",
736  "Usage: lcr reload interfaces\n",
737 };
738
739 static struct ast_cli_entry cli_port_block =
740 { {"lcr", "port", "block", NULL},
741  lcr_port_block,
742  "Blocks LCR port for further calls",
743  "Usage: lcr port block \"<port>\"\n",
744 };
745
746 static struct ast_cli_entry cli_port_unblock =
747 { {"lcr", "port", "unblock", NULL},
748  lcr_port_unblock,
749  "Unblocks or loads LCR port, port is opened my mISDN",
750  "Usage: lcr port unblock \"<port>\"\n",
751 };
752
753 static struct ast_cli_entry cli_port_unload =
754 { {"lcr", "port", "unload", NULL},
755  lcr_port_unload,
756  "Unloads LCR port, port is closes by mISDN",
757  "Usage: lcr port unload \"<port>\"\n",
758 };
759
760
761 /*
762  * module loading and destruction
763  */
764 int load_module(void)
765 {
766 //      ast_mutex_init(&release_lock);
767
768 //      lcr_cfg_update_ptp();
769
770         if (!(lcr_sock = open_socket())) {
771                 ast_log(LOG_ERROR, "Unable to connect %s\n", misdn_type);
772                 lcr_sock = -1;
773                 /* continue with closed socket */
774         }
775
776         if (!bchannel_initialize()) {
777                 ast_log(LOG_ERROR, "Unable to open mISDN device\n");
778                 unload_module();
779                 return -1;
780         }
781         mISDN_created = 1;
782
783         if (ast_channel_register(&lcr_tech)) {
784                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
785                 unload_module();
786                 return -1;
787         }
788   
789         ast_cli_register(&cli_show_lcr);
790         ast_cli_register(&cli_show_calls);
791
792         ast_cli_register(&cli_reload_routing);
793         ast_cli_register(&cli_reload_interfaces);
794         ast_cli_register(&cli_port_block);
795         ast_cli_register(&cli_port_unblock);
796         ast_cli_register(&cli_port_unload);
797   
798         ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
799                                  "misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n"
800                                  "Sets mISDN opts. and optargs\n"
801                                  "\n"
802                                  "The available options are:\n"
803                                  "    d - Send display text on called phone, text is the optparam\n"
804                                  "    n - don't detect dtmf tones on called channel\n"
805                                  "    h - make digital outgoing call\n" 
806                                  "    c - make crypted outgoing call, param is keyindex\n"
807                                  "    e - perform echo cancelation on this channel,\n"
808                                  "        takes taps as arguments (32,64,128,256)\n"
809                                  "    s - send Non Inband DTMF as inband\n"
810                                  "   vr - rxgain control\n"
811                                  "   vt - txgain control\n"
812                 );
813
814         
815         lcr_cfg_get( 0, LCR_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
816
817         chan_lcr_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n");
818
819         return 0;
820 }
821
822 int unload_module(void)
823 {
824         /* First, take us out of the channel loop */
825         ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
826         
827         misdn_tasks_destroy();
828         
829         if (!g_config_initialized) return 0;
830         
831         ast_cli_unregister(&cli_show_lcr);
832         ast_cli_unregister(&cli_show_calls);
833         ast_cli_unregister(&cli_reload_routing);
834         ast_cli_unregister(&cli_reload_interfaces);
835         ast_cli_unregister(&cli_port_block);
836         ast_cli_unregister(&cli_port_unblock);
837         ast_unregister_application("misdn_set_opt");
838   
839         ast_channel_unregister(&lcr_tech);
840
841         if (mISDN_created) {
842                 bchannel_deinitialize();
843                 mISDN_created = 0;
844         }
845
846         if (lcr_sock >= 0) {
847                 close(lcr_sock);
848                 lcr_sock = -1;
849         }
850
851         was ist mit dem mutex
852         
853         return 0;
854 }
855
856 int reload(void)
857 {
858         reload_config();
859
860         return 0;
861 }
862
863 int usecount(void)
864 {
865         int res;
866         ast_mutex_lock(&usecnt_lock);
867         res = usecnt;
868         ast_mutex_unlock(&usecnt_lock);
869         return res;
870 }
871
872 char *description(void)
873 {
874         return desc;
875 }
876
877 char *key(void)
878 {
879         return ASTERISK_GPL_KEY;
880 }
881
882