1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** reading interface.conf file and filling structure **
10 \*****************************************************************************/
14 struct interface *interface_first = NULL; /* first interface is current list */
15 struct interface *interface_newlist = NULL; /* first interface in new list */
18 /* set default out_channel */
19 void default_out_channel(struct interface_port *ifport)
21 struct select_channel *selchannel, **selchannelp;
23 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
26 if (ifport->mISDNport->ntmode)
27 selchannel->channel = CHANNEL_FREE;
29 selchannel->channel = CHANNEL_ANY;
31 ifport->out_channel = selchannel;
33 /* additional channel selection for multipoint NT ports */
34 if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode) {
35 selchannelp = &(selchannel->next);
36 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
38 selchannel->channel = CHANNEL_NO; // call waiting
39 *selchannelp = selchannel;
44 /* set default in_channel */
45 void default_in_channel(struct interface_port *ifport)
47 struct select_channel *selchannel;
49 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
52 selchannel->channel = CHANNEL_FREE;
54 ifport->in_channel = selchannel;
58 /* parse string for a positive number */
59 static int get_number(char *value)
66 SPRINT(text, "%d", val);
68 if (!strcmp(value, text))
75 /* remove element from buffer
76 * and return pointer to next element in buffer */
77 static char *get_seperated(char *buffer)
80 if (*buffer==',' || *buffer<=32) { /* seperate */
82 while((*buffer>'\0' && *buffer<=32) || *buffer==',')
92 * parameter processing
94 static int inter_block(struct interface *interface, char *filename, int line, char *parameter, char *value)
96 struct interface_port *ifport;
99 if (!interface->ifport) {
100 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
103 /* goto end of chain */
104 ifport = interface->ifport;
106 ifport = ifport->next;
109 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
115 static int inter_extension(struct interface *interface, char *filename, int line, char *parameter, char *value)
117 if (interface->external) {
118 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is external interface.\n", filename, line, parameter);
122 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
125 interface->extension = 1;
128 static int inter_extern(struct interface *interface, char *filename, int line, char *parameter, char *value)
130 if (interface->extension) {
131 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is an extension.\n", filename, line, parameter);
135 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
138 interface->external = 1;
141 static int inter_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
143 struct interface_port *ifport;
145 /* port in chain ? */
146 if (!interface->ifport) {
147 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
150 if (interface->ifport->ptmp) {
151 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptmp was given.\n", filename, line, parameter);
154 /* goto end of chain */
155 ifport = interface->ifport;
157 ifport = ifport->next;
160 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
167 static int inter_ptmp(struct interface *interface, char *filename, int line, char *parameter, char *value)
169 struct interface_port *ifport;
171 /* port in chain ? */
172 if (!interface->ifport) {
173 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
176 if (interface->ifport->ptp) {
177 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptp was given.\n", filename, line, parameter);
180 /* goto end of chain */
181 ifport = interface->ifport;
183 ifport = ifport->next;
186 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
193 static int inter_nt(struct interface *interface, char *filename, int line, char *parameter, char *value)
195 struct interface_port *ifport;
197 /* port in chain ? */
198 if (!interface->ifport) {
199 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
202 /* goto end of chain */
203 ifport = interface->ifport;
205 ifport = ifport->next;
208 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
214 static int inter_tespecial(struct interface *interface, char *filename, int line, char *parameter, char *value)
216 struct interface_port *ifport;
218 /* port in chain ? */
219 if (!interface->ifport) {
220 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
223 /* goto end of chain */
224 ifport = interface->ifport;
226 ifport = ifport->next;
229 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
232 ifport->tespecial = 1;
235 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
237 if (!strcasecmp(value, "yes")) {
238 interface->is_tones = IS_YES;
240 if (!strcasecmp(value, "no")) {
241 interface->is_tones = IS_NO;
243 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
248 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
250 if (!strcasecmp(value, "yes")) {
251 interface->is_earlyb = IS_YES;
253 if (!strcasecmp(value, "no")) {
254 interface->is_earlyb = IS_NO;
256 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
261 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
263 if (!strcasecmp(value, "linear")) {
264 interface->hunt = HUNT_LINEAR;
266 if (!strcasecmp(value, "roundrobin")) {
267 interface->hunt = HUNT_ROUNDROBIN;
269 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
274 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
276 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' is outdated.\nPlease use 'portnum' and decrease port number by 1! Ports are counted from 0 now.\n", filename, line, parameter);
279 static int inter_portnum(struct interface *interface, char *filename, int line, char *parameter, char *value)
281 struct interface_port *ifport, **ifportp;
282 struct interface *searchif;
285 val = get_number(value);
287 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
290 /* check for port already assigned */
291 searchif = interface_newlist;
293 ifport = searchif->ifport;
295 if (ifport->portnum == val) {
296 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
299 ifport = ifport->next;
301 searchif = searchif->next;
303 /* alloc port substructure */
304 ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
306 ifport->interface = interface;
308 ifport->portnum = val;
310 ifportp = &interface->ifport;
312 ifportp = &((*ifportp)->next);
316 static int inter_portname(struct interface *interface, char *filename, int line, char *parameter, char *value)
318 struct interface_port *ifport, **ifportp;
319 struct interface *searchif;
321 /* check for port already assigned */
322 searchif = interface_newlist;
324 ifport = searchif->ifport;
326 if (!strcasecmp(ifport->portname, value)) {
327 SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
330 // /* check for use as GSM */
331 // if (ifport->gsm) {
332 // SPRINT(interface_error, "Error in %s (line %d): Interface already used for GSM.\n", filename, line);
335 ifport = ifport->next;
337 searchif = searchif->next;
339 /* alloc port substructure */
340 ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
342 ifport->interface = interface;
344 ifport->portnum = -1; // disable until resolved
345 SCPY(ifport->portname, value);
347 ifportp = &interface->ifport;
349 ifportp = &((*ifportp)->next);
353 static int inter_l1hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
355 struct interface_port *ifport;
357 /* port in chain ? */
358 if (!interface->ifport) {
359 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
362 /* goto end of chain */
363 ifport = interface->ifport;
365 ifport = ifport->next;
366 if (!strcmp(value, "yes")) {
369 if (!strcmp(value, "no")) {
372 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
377 static int inter_l2hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
379 struct interface_port *ifport;
381 /* port in chain ? */
382 if (!interface->ifport) {
383 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
386 /* goto end of chain */
387 ifport = interface->ifport;
389 ifport = ifport->next;
390 if (!strcmp(value, "yes")) {
393 if (!strcmp(value, "no")) {
396 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
401 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
403 struct interface_port *ifport;
404 struct select_channel *selchannel, **selchannelp;
408 /* port in chain ? */
409 if (!interface->ifport) {
410 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
413 /* goto end of chain */
414 ifport = interface->ifport;
416 ifport = ifport->next;
420 p = get_seperated(p);
421 if (!strcasecmp(el, "force")) {
422 ifport->channel_force = 1;
423 if (ifport->out_channel) {
424 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
428 if (!strcasecmp(el, "any")) {
432 if (!strcasecmp(el, "free")) {
436 if (!strcasecmp(el, "no")) {
440 val = get_number(el);
442 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of 'force', 'any', 'free', 'no' and any channel number.\n", filename, line, parameter);
446 if (val<1 || val==16 || val>126) {
447 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
451 /* add to select-channel list */
452 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
455 selchannel->channel = val;
457 selchannelp = &ifport->out_channel;
459 selchannelp = &((*selchannelp)->next);
460 *selchannelp = selchannel;
465 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
467 struct interface_port *ifport;
468 struct select_channel *selchannel, **selchannelp;
472 /* port in chain ? */
473 if (!interface->ifport) {
474 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
477 /* goto end of chain */
478 ifport = interface->ifport;
480 ifport = ifport->next;
484 p = get_seperated(p);
485 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE) {
486 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
489 if (!strcasecmp(el, "free")) {
493 val = get_number(el);
495 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
499 if (val<1 || val==16 || val>126) {
500 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
504 /* add to select-channel list */
505 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
508 selchannel->channel = val;
510 selchannelp = &ifport->in_channel;
512 selchannelp = &((*selchannelp)->next);
513 *selchannelp = selchannel;
518 static int inter_timeouts(struct interface *interface, char *filename, int line, char *parameter, char *value)
520 struct interface_port *ifport;
521 // struct select_channel *selchannel, **selchannelp;
525 /* port in chain ? */
526 if (!interface->ifport) {
527 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
530 /* goto end of chain */
531 ifport = interface->ifport;
533 ifport = ifport->next;
537 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects five timeout values.\n", filename, line, parameter);
541 p = get_seperated(p);
542 ifport->tout_setup = atoi(el);
546 p = get_seperated(p);
547 ifport->tout_dialing = atoi(el);
551 p = get_seperated(p);
552 ifport->tout_proceeding = atoi(el);
556 p = get_seperated(p);
557 ifport->tout_alerting = atoi(el);
561 p = get_seperated(p);
562 ifport->tout_disconnect = atoi(el);
565 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
567 struct interface_msn *ifmsn, **ifmsnp;
571 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
574 if (interface->ifscreen_in) {
575 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
583 p = get_seperated(p);
584 /* add MSN to list */
585 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
588 SCPY(ifmsn->msn, el);
590 ifmsnp = &interface->ifmsn;
592 ifmsnp = &((*ifmsnp)->next);
597 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
599 struct interface_screen *ifscreen;
603 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
606 /* add screen entry to list*/
607 ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
609 ifscreen->match_type = -1; /* unchecked */
610 ifscreen->match_present = -1; /* unchecked */
611 ifscreen->result_type = -1; /* unchanged */
612 ifscreen->result_present = -1; /* unchanged */
615 ifscreenp = &((*ifscreenp)->next);
616 *ifscreenp = ifscreen;
617 // printf("interface=%s\n", interface->name);
622 p = get_seperated(p);
623 if (!strcasecmp(el, "unknown")) {
624 if (ifscreen->match_type != -1) {
626 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
629 ifscreen->match_type = INFO_NTYPE_UNKNOWN;
631 if (!strcasecmp(el, "subscriber")) {
632 if (ifscreen->match_type != -1)
634 ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
636 if (!strcasecmp(el, "national")) {
637 if (ifscreen->match_type != -1)
639 ifscreen->match_type = INFO_NTYPE_NATIONAL;
641 if (!strcasecmp(el, "international")) {
642 if (ifscreen->match_type != -1)
644 ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
646 if (!strcasecmp(el, "allowed")) {
647 if (ifscreen->match_present != -1) {
649 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
652 ifscreen->match_present = INFO_PRESENT_ALLOWED;
654 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted")) {
655 if (ifscreen->match_present != -1)
657 ifscreen->match_present = INFO_PRESENT_RESTRICTED;
659 SCPY(ifscreen->match, el);
660 /* check for % at the end */
661 if (strchr(el, '%')) {
662 if (strchr(el, '%') != el+strlen(el)-1) {
663 SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
670 if (ifscreen->match[0] == '\0') {
671 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
677 p = get_seperated(p);
678 if (!strcasecmp(el, "unknown")) {
679 if (ifscreen->result_type != -1)
681 ifscreen->result_type = INFO_NTYPE_UNKNOWN;
683 if (!strcasecmp(el, "subscriber")) {
684 if (ifscreen->result_type != -1)
686 ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
688 if (!strcasecmp(el, "national")) {
689 if (ifscreen->result_type != -1)
691 ifscreen->result_type = INFO_NTYPE_NATIONAL;
693 if (!strcasecmp(el, "international")) {
694 if (ifscreen->result_type != -1)
696 ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
698 if (!strcasecmp(el, "present") || !strcasecmp(el, "presented") || !strcasecmp(el, "allowed") || !strcasecmp(el, "allow")) {
699 if (ifscreen->result_present != -1)
701 ifscreen->result_present = INFO_PRESENT_ALLOWED;
703 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted") || !strcasecmp(el, "deny") || !strcasecmp(el, "denied")) {
704 if (ifscreen->result_present != -1)
706 ifscreen->result_present = INFO_PRESENT_RESTRICTED;
708 SCPY(ifscreen->result, el);
709 /* check for % at the end */
710 if (strchr(el, '%')) {
711 if (strchr(el, '%') != el+strlen(el)-1) {
712 SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
719 if (ifscreen->result[0] == '\0') {
720 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
725 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
727 if (interface->ifmsn) {
728 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
732 return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
734 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
736 return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
738 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
740 struct interface_port *ifport;
742 /* port in chain ? */
743 if (!interface->ifport) {
744 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
747 /* goto end of chain */
748 ifport = interface->ifport;
750 ifport = ifport->next;
754 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
758 /* seperate parameter from filter */
764 while(*p > 0 && *p <= 32)
768 if (!strcasecmp(value, "gain")) {
774 while(*q > 0 && *q <= 32)
777 if (*p == 0 || *q == 0) {
778 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects two gain values.\n", filename, line, parameter, value);
781 if (atoi(p)<-8 || atoi(p)>8 || atoi(q)<-8 || atoi(q)>8) {
782 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' gain values not in range. (-8...8)\n", filename, line, parameter, value);
785 interface->tx_gain = atoi(p);
786 interface->rx_gain = atoi(q);
788 if (!strcasecmp(value, "pipeline")) {
790 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects pipeline string.\n", filename, line, parameter, value);
793 SCPY(interface->pipeline, p);
795 if (!strcasecmp(value, "blowfish")) {
796 unsigned char key[56];
799 if (!!strncmp(p, "0x", 2)) {
800 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects blowfish key starting with '0x'.\n", filename, line, parameter, value);
807 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key too long.\n", filename, line, parameter, value);
810 if (*p >= '0' && *p <= '9')
811 key[l] = (*p-'0')<<4;
812 else if (*p >= 'a' && *p <= 'f')
813 key[l] = (*p-'a'+10)<<4;
814 else if (*p >= 'A' && *p <= 'F')
815 key[l] = (*p-'A'+10)<<4;
818 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key has digits out of range. (0...9, a...f)\n", filename, line, parameter, value);
823 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key must end on an 8 bit boundary (two character boundary).\n", filename, line, parameter, value);
826 if (*p >= '0' && *p <= '9')
827 key[l] = (*p-'0')<<4;
828 else if (*p >= 'a' && *p <= 'f')
829 key[l] = (*p-'a'+10)<<4;
830 else if (*p >= 'A' && *p <= 'F')
831 key[l] = (*p-'A'+10)<<4;
838 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key must be at least 4 bytes (8 characters).\n", filename, line, parameter, value);
841 memcpy(interface->bf_key, key, l);
842 interface->bf_len = l;
844 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has unknown filter '%s'.\n", filename, line, parameter, value);
849 static int inter_dialmax(struct interface *interface, char *filename, int line, char *parameter, char *value)
851 struct interface_port *ifport;
853 /* port in chain ? */
854 if (!interface->ifport) {
855 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
858 /* goto end of chain */
859 ifport = interface->ifport;
861 ifport = ifport->next;
862 ifport->dialmax = atoi(value);
865 static int inter_tones_dir(struct interface *interface, char *filename, int line, char *parameter, char *value)
867 struct interface_port *ifport;
869 /* port in chain ? */
870 if (!interface->ifport) {
871 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
874 /* goto end of chain */
875 ifport = interface->ifport;
877 ifport = ifport->next;
878 SCPY(ifport->tones_dir, value);
881 static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
884 SPRINT(interface_error, "Error in %s (line %d): GSM not compiled in.\n", filename, line);
887 struct interface_port *ifport;
888 struct interface *searchif;
892 SPRINT(interface_error, "Error in %s (line %d): GSM is not activated.\n", filename, line);
895 searchif = interface_newlist;
897 ifport = searchif->ifport;
900 SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm\n", filename, line, value);
903 ifport = ifport->next;
905 searchif = searchif->next;
909 if (inter_portname(interface, filename, line, (char *)"portname", gsm->conf.interface_lcr))
911 /* goto end of chain again to set gsmflag*/
912 ifport = interface->ifport;
914 ifport = ifport->next;
919 static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value)
921 struct interface_port *ifport;
923 /* port in chain ? */
924 if (!interface->ifport) {
925 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
928 /* goto end of chain */
929 ifport = interface->ifport;
931 ifport = ifport->next;
932 ifport->nonotify = 1;
936 static int inter_ss5(struct interface *interface, char *filename, int line, char *parameter, char *value)
938 struct interface_port *ifport;
941 /* port in chain ? */
942 if (!interface->ifport) {
943 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
946 /* goto end of chain */
947 ifport = interface->ifport;
949 ifport = ifport->next;
950 ifport->ss5 |= SS5_ENABLE;
951 while((element = strsep(&value, " "))) {
952 if (element[0] == '\0')
954 if (!strcasecmp(element, "connect"))
955 ifport->ss5 |= SS5_FEATURE_CONNECT;
957 if (!strcasecmp(element, "nodisconnect"))
958 ifport->ss5 |= SS5_FEATURE_NODISCONNECT;
960 if (!strcasecmp(element, "releaseguardtimer"))
961 ifport->ss5 |= SS5_FEATURE_RELEASEGUARDTIMER;
963 if (!strcasecmp(element, "bell"))
964 ifport->ss5 |= SS5_FEATURE_BELL;
966 if (!strcasecmp(element, "pulsedialing"))
967 ifport->ss5 |= SS5_FEATURE_PULSEDIALING;
969 if (!strcasecmp(element, "delay"))
970 ifport->ss5 |= SS5_FEATURE_DELAY;
972 if (!strcasecmp(element, "starrelease"))
973 ifport->ss5 |= SS5_FEATURE_STAR_RELEASE;
975 if (!strcasecmp(element, "suppress"))
976 ifport->ss5 |= SS5_FEATURE_SUPPRESS;
978 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' does not allow value element '%s'.\n", filename, line, parameter, element);
988 * structure of parameters
990 struct interface_param interface_param[] = {
991 { "extension", &inter_extension, "",
992 "If keyword is given, calls to interface are handled as internal extensions."},
994 { "extern", &inter_extern, "",
995 "If keyword is given, this interface will be used for external calls.\n"
996 "Calls require an external interface, if the routing action 'extern' is used\nwithout specific interface given.\n"
997 "Calls forwarded by extension's 'settings' also require an external interface."},
999 {"tones", &inter_tones, "yes | no",
1000 "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
1002 {"earlyb", &inter_earlyb, "yes | no",
1003 "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
1005 {"hunt", &inter_hunt, "linear | roundrobin",
1006 "Select the algorithm for selecting port with free channel."},
1008 {"port", &inter_port, "<number>",
1010 {"portnum", &inter_portnum, "<number>",
1011 "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
1012 {"portname", &inter_portname, "<name>",
1013 "Same as 'portnum', but the name is given instead.\nUse 'isdninfo' to list all available ports and names."},
1015 {"block", &inter_block, "",
1016 "If keyword is given, calls on this interface are blocked.\n"
1017 "This parameter must follow a 'port' parameter."},
1019 {"ptp", &inter_ptp, "",
1020 "The given port above is opened as point-to-point.\n"
1021 "This is required on NT-mode ports that are multipoint by default.\n"
1022 "This parameter must follow a 'port' parameter."},
1025 {"ptmp", &inter_ptmp, "",
1026 "The given port above is opened as point-to-multipoint.\n"
1027 "This is required on PRI NT-mode ports that are point-to-point by default.\n"
1028 "This parameter must follow a 'port' parameter."},
1031 {"nt", &inter_nt, "",
1032 "The given port above is opened in NT-mode.\n"
1033 "This is required on interfaces that support both NT-mode and TE-mode.\n"
1034 "This parameter must follow a 'port' parameter."},
1036 {"te-special", &inter_tespecial, "",
1037 "The given port uses a modified TE-mode.\n"
1038 "All information elements that are allowed Network->User will then be\n"
1039 "transmitted User->Network also. This is usefull to pass all informations\n"
1040 "between two interconnected LCRs, like 'redirected number' or 'display'.\n"
1041 "Note that this is not compliant with ISDN protocol.\n"
1042 "This parameter must follow a 'port' parameter."},
1044 {"layer1hold", &inter_l1hold, "yes | no",
1045 "The given port will not release layer 1 after layer 2 is down.\n"
1046 "It is required to keep layer 1 of telephones up, to solve activation problems.\n"
1047 "This parameter must follow a 'port' parameter."},
1049 {"layer2hold", &inter_l2hold, "yes | no",
1050 "The given port will continuously try to establish layer 2 link and hold it.\n"
1051 "It is required for PTP links in most cases, therefore it is default.\n"
1052 "This parameter must follow a 'port' parameter."},
1054 {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
1055 "Channel selection list for all outgoing calls to the interface.\n"
1056 "A free channels is searched in order of appearance.\n"
1057 "This parameter must follow a 'port' parameter.\n"
1058 " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
1059 " <number>[,...] - List of channels to search.\n"
1060 " free - Select any free channel\n"
1061 " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
1062 " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
1064 {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
1065 "Channel selection list for all incoming calls from the interface.\n"
1066 "A free channels is accepted if in the list.\n"
1067 "If any channel was requested, the first free channel found is selected.\n"
1068 "This parameter must follow a 'port' parameter.\n"
1069 " <number>[,...] - List of channels to accept.\n"
1070 " free - Accept any free channel"},
1072 {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
1073 "Timeout values for call states. They are both for incoming and outgoing states.\n"
1074 "The default is 120 seconds for all states. Use 0 to disable.\n"
1075 "This parameter must follow a 'port' parameter.\n"},
1077 {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
1078 "Incoming caller ID is checked against given MSN numbers.\n"
1079 "If the caller ID is not found in this list, it is overwritten by the first MSN"},
1081 {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1082 "Adds an entry for incoming calls to the caller ID screen list.\n"
1083 "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
1084 "If '%' is given after old caller ID, it matches even if caller ID has\n"
1085 "additional digits.\n"
1086 "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
1089 " unknown | subsciber | national | international - Change caller ID type.\n"
1090 " present | restrict - Change presentation of caller ID."},
1092 {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1093 "Adds an entry for outgoing calls to the caller ID screen list.\n"
1094 "See 'screen-in' for help."},
1096 {"nodtmf", &inter_nodtmf, "",
1097 "Disables DTMF detection for this interface.\n"
1098 "This parameter must follow a 'port' parameter."},
1100 {"filter", &inter_filter, "<filter> <parameters>",
1101 "Adds/appends a filter. Filters are ordered in transmit direction.\n"
1102 "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
1103 "pipeline <string> - Sets echo cancelation pipeline.\n"
1104 "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
1106 {"dialmax", &inter_dialmax, "<digits>",
1107 "Limits the number of digits in setup/information message."},
1109 {"tones_dir", &inter_tones_dir, "<path>",
1110 "Overrides the given tone_dir in options.conf.\n"
1111 "To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
1113 {"gsm", &inter_gsm, "",
1114 "Sets up GSM interface for using OpenBSC.\n"
1115 "This interface must be a loopback interface. The second loopback interface\n"
1116 "must be assigned to OpenBSC."},
1118 {"nonotify", &inter_nonotify, "",
1119 "Prevents sending notify messages to this interface. A call placed on hold will\n"
1120 "Not affect the remote end (phone or telcom switch).\n"
1121 "This parameter must follow a 'port' parameter."},
1124 {"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
1125 "Interface uses CCITT No. 5 inband signalling rather than D-channel.\n"
1126 "This feature causes CPU load to rise and has no practical intend.\n"
1127 "If you don't know what it is, you don't need it.\n"
1128 "Features apply to protocol behaviour and blueboxing specials, they are:\n"
1129 " connect - Connect incomming call to throughconnect audio, if required.\n"
1130 " nodisconnect - Don't disconnect if incomming exchange disconnects.\n"
1131 " releaseguardtimer - Tries to prevent Blueboxing by a longer release-guard.\n"
1132 " bell - Allow releasing and pulse-dialing via 2600 Hz like old Bell systems.\n"
1133 " pulsedialing - Use pulse dialing on outgoing exchange. (takes long!)\n"
1134 " delay - Use on incomming exchange, to make you feel a delay when blueboxing.\n"
1135 " starrelease - Pulse dialing a star (11 pulses per digit) clears current call.\n"
1136 " suppress - Suppress received tones, as they will be recognized."},
1139 {NULL, NULL, NULL, NULL}
1144 * read settings from interface.conf
1146 char interface_error[256];
1147 struct interface *read_interfaces(void)
1152 unsigned int line, i;
1154 struct interface *interface = NULL, /* in case no interface */
1155 **interfacep = &interface_newlist;
1156 char parameter[128];
1158 int expecting = 1; /* expecting new interface */
1159 struct interface_param *ifparam;
1161 if (interface_newlist != NULL)
1162 FATAL("list is not empty.\n");
1163 interface_error[0] = '\0';
1164 SPRINT(filename, "%s/interface.conf", CONFIG_DATA);
1166 if (!(fp = fopen(filename,"r"))) {
1167 SPRINT(interface_error, "Cannot open '%s'\n", filename);
1172 while((GETLINE(buffer, fp))) {
1176 while(*p <= 32) { /* skip spaces */
1181 if (*p==0 || *p=='#') /* ignore comments and empty line */
1186 i=0; /* read parameter */
1188 if (i+1 >= sizeof(parameter)) {
1189 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
1192 parameter[i+1] = '\0';
1193 parameter[i++] = *p++;
1196 while(*p <= 32) { /* skip spaces */
1202 if (*p!=0 && *p!='#') { /* missing name */
1203 i=0; /* read until end */
1204 while(*p!=0 && *p!='#') {
1205 if (i+1 >= sizeof(value)) {
1206 SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
1213 /* remove trailing spaces from value */
1215 if (value[i-1]==0 || value[i-1]>32)
1222 /* check for interface name as first statement */
1223 if (expecting && parameter[0]!='[') {
1224 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1229 /* check for new interface */
1230 if (parameter[0] == '[') {
1231 if (parameter[strlen(parameter)-1] != ']') {
1232 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1235 parameter[strlen(parameter)-1] = '\0';
1237 /* check if interface name already exists */
1238 interface = interface_newlist;
1240 if (!strcasecmp(interface->name, parameter+1)) {
1241 SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
1244 interface = interface->next;
1247 /* append interface to new list */
1248 interface = (struct interface *)MALLOC(sizeof(struct interface));
1251 /* name interface */
1252 SCPY(interface->name, parameter+1);
1255 *interfacep = interface;
1256 interfacep = &interface->next;
1261 ifparam = interface_param;
1262 while(ifparam->name) {
1263 if (!strcasecmp(parameter, ifparam->name)) {
1264 if (ifparam->func(interface, filename, line, parameter, value))
1273 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1278 return(interface_newlist);
1280 PERROR_RUNTIME("%s", interface_error);
1282 free_interfaces(interface_newlist);
1283 interface_newlist = NULL;
1289 * freeing chain of interfaces
1291 void free_interfaces(struct interface *interface)
1294 struct interface_port *ifport;
1295 struct select_channel *selchannel;
1296 struct interface_msn *ifmsn;
1297 struct interface_screen *ifscreen;
1300 ifport = interface->ifport;
1302 selchannel = ifport->in_channel;
1305 selchannel = selchannel->next;
1306 FREE(temp, sizeof(struct select_channel));
1309 selchannel = ifport->out_channel;
1312 selchannel = selchannel->next;
1313 FREE(temp, sizeof(struct select_channel));
1317 ifport = ifport->next;
1318 FREE(temp, sizeof(struct interface_port));
1321 ifmsn = interface->ifmsn;
1324 ifmsn = ifmsn->next;
1325 FREE(temp, sizeof(struct interface_msn));
1328 ifscreen = interface->ifscreen_in;
1331 ifscreen = ifscreen->next;
1332 FREE(temp, sizeof(struct interface_screen));
1335 ifscreen = interface->ifscreen_out;
1338 ifscreen = ifscreen->next;
1339 FREE(temp, sizeof(struct interface_screen));
1343 interface = interface->next;
1344 FREE(temp, sizeof(struct interface));
1350 * defaults of ports if not specified by config
1352 static void set_defaults(struct interface_port *ifport)
1354 /* default channel selection list */
1355 if (!ifport->out_channel)
1356 default_out_channel(ifport);
1357 if (!ifport->in_channel)
1358 default_in_channel(ifport);
1359 /* default is_tones */
1360 if (ifport->interface->is_tones)
1361 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1363 ifport->mISDNport->tones = (ifport->mISDNport->ntmode || ifport->mISDNport->ss5)?1:0;
1364 /* default is_earlyb */
1365 if (ifport->interface->is_earlyb)
1366 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1368 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode && !ifport->mISDNport->ss5)?0:1;
1369 /* set locally flag */
1370 if (ifport->interface->extension)
1371 ifport->mISDNport->locally = 1;
1373 ifport->mISDNport->locally = 0;
1378 * all links between mISDNport and interface are made
1379 * unused mISDNports are closed, new mISDNports are opened
1380 * also set default select_channel lists
1382 void relink_interfaces(void)
1384 struct mISDNport *mISDNport;
1385 struct interface *interface;
1386 struct interface_port *ifport;
1388 /* unlink all mISDNports */
1389 mISDNport = mISDNport_first;
1391 mISDNport->ifport = NULL;
1392 mISDNport = mISDNport->next;
1395 /* relink existing mISDNports */
1396 interface = interface_newlist;
1398 ifport = interface->ifport;
1400 mISDNport = mISDNport_first;
1402 if (!strcmp(mISDNport->name, ifport->portname))
1403 ifport->portnum = mISDNport->portnum; /* same name, so we use same number */
1404 if (mISDNport->portnum == ifport->portnum) {
1405 PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", ifport->portnum, ifport->portname);
1406 ifport->mISDNport = mISDNport;
1407 mISDNport->ifport = ifport;
1408 set_defaults(ifport);
1410 mISDNport = mISDNport->next;
1412 ifport = ifport->next;
1414 interface = interface->next;
1417 /* close unused mISDNports */
1419 mISDNport = mISDNport_first;
1421 if (mISDNport->ifport == NULL) {
1422 PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1423 /* remove all port objects and destroy port */
1424 mISDNport_close(mISDNport);
1427 mISDNport = mISDNport->next;
1430 /* open and link new mISDNports */
1431 interface = interface_newlist;
1433 ifport = interface->ifport;
1435 if (!ifport->mISDNport) {
1438 ifport = ifport->next;
1440 interface = interface->next;
1449 void load_port(struct interface_port *ifport)
1451 struct mISDNport *mISDNport;
1454 mISDNport = mISDNport_open(ifport);
1457 ifport->mISDNport = mISDNport;
1458 mISDNport->ifport = ifport;
1459 /* set number and name */
1460 ifport->portnum = mISDNport->portnum;
1461 SCPY(ifport->portname, mISDNport->name);
1463 set_defaults(ifport);
1464 /* load static port instances */
1465 mISDNport_static(mISDNport);
1467 ifport->block = 2; /* not available */
1472 * give summary of interface syntax
1474 void doc_interface(void)
1476 struct interface_param *ifparam;
1478 printf("Syntax overview\n");
1479 printf("---------------\n\n");
1481 printf("[<name>]\n");
1482 ifparam = interface_param;
1483 while(ifparam->name) {
1484 if (ifparam->name[0])
1485 printf("%s %s\n", ifparam->name, ifparam->usage);
1489 ifparam = interface_param;
1490 while(ifparam->name) {
1491 if (ifparam->name[0]) {
1492 printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1493 printf("%s\n", ifparam->help);
1501 * out==0: incoming caller id, out==1: outgoing caller id
1503 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1506 struct interface_msn *ifmsn;
1507 struct interface_screen *ifscreen;
1510 /* screen incoming caller id */
1512 /* check for MSN numbers, use first MSN if no match */
1514 ifmsn = interface->ifmsn;
1518 if (!strcmp(ifmsn->msn, id)) {
1521 ifmsn = ifmsn->next;
1524 start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (found in MSN list)");
1525 add_trace("msn", NULL, "%s", id);
1528 if (!ifmsn && msn1) { // not in list, first msn given
1529 start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (not found in MSN list)");
1530 add_trace("msn", "given", "%s", id);
1531 add_trace("msn", "used", "%s", msn1);
1533 UNCPY(id, msn1, idsize);
1534 id[idsize-1] = '\0';
1538 /* check screen list */
1540 ifscreen = interface->ifscreen_out;
1542 ifscreen = interface->ifscreen_in;
1544 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1545 if (ifscreen->match_present==-1 || ifscreen->match_present==*present) {
1546 if (strchr(ifscreen->match,'%')) {
1547 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1550 if (!strcmp(ifscreen->match, id))
1554 ifscreen = ifscreen->next;
1556 if (ifscreen) { // match
1557 start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, out?DIRECTION_OUT:DIRECTION_IN, 0, 0, "SCREEN (found in screen list)");
1559 case INFO_NTYPE_UNKNOWN:
1560 add_trace("given", "type", "unknown");
1562 case INFO_NTYPE_SUBSCRIBER:
1563 add_trace("given", "type", "subscriber");
1565 case INFO_NTYPE_NATIONAL:
1566 add_trace("given", "type", "national");
1568 case INFO_NTYPE_INTERNATIONAL:
1569 add_trace("given", "type", "international");
1573 case INFO_PRESENT_ALLOWED:
1574 add_trace("given", "present", "allowed");
1576 case INFO_PRESENT_RESTRICTED:
1577 add_trace("given", "present", "restricted");
1579 case INFO_PRESENT_NOTAVAIL:
1580 add_trace("given", "present", "not available");
1583 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1584 if (ifscreen->result_type != -1) {
1585 *type = ifscreen->result_type;
1587 case INFO_NTYPE_UNKNOWN:
1588 add_trace("used", "type", "unknown");
1590 case INFO_NTYPE_SUBSCRIBER:
1591 add_trace("used", "type", "subscriber");
1593 case INFO_NTYPE_NATIONAL:
1594 add_trace("used", "type", "national");
1596 case INFO_NTYPE_INTERNATIONAL:
1597 add_trace("used", "type", "international");
1601 if (ifscreen->result_present != -1) {
1602 *present = ifscreen->result_present;
1604 case INFO_PRESENT_ALLOWED:
1605 add_trace("used", "present", "allowed");
1607 case INFO_PRESENT_RESTRICTED:
1608 add_trace("used", "present", "restricted");
1610 case INFO_PRESENT_NOTAVAIL:
1611 add_trace("used", "present", "not available");
1615 if (strchr(ifscreen->match,'%')) {
1616 SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1617 UNCPY(id, ifscreen->result, idsize);
1618 id[idsize-1] = '\0';
1619 if (strchr(id,'%')) {
1620 *strchr(id,'%') = '\0';
1621 UNCAT(id, suffix, idsize);
1622 id[idsize-1] = '\0';
1625 UNCPY(id, ifscreen->result, idsize);
1626 id[idsize-1] = '\0';
1628 add_trace("used", "id", "%s", id[0]?id:"<empty>");