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)
118 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
121 interface->extension = 1;
124 static int inter_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
126 struct interface_port *ifport;
128 /* port in chain ? */
129 if (!interface->ifport) {
130 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
133 if (interface->ifport->ptmp) {
134 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptmp was given.\n", filename, line, parameter);
137 /* goto end of chain */
138 ifport = interface->ifport;
140 ifport = ifport->next;
143 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
150 static int inter_ptmp(struct interface *interface, char *filename, int line, char *parameter, char *value)
152 struct interface_port *ifport;
154 /* port in chain ? */
155 if (!interface->ifport) {
156 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
159 if (interface->ifport->ptp) {
160 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptp was given.\n", filename, line, parameter);
163 /* goto end of chain */
164 ifport = interface->ifport;
166 ifport = ifport->next;
169 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
176 static int inter_nt(struct interface *interface, char *filename, int line, char *parameter, char *value)
178 struct interface_port *ifport;
180 /* port in chain ? */
181 if (!interface->ifport) {
182 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
185 /* goto end of chain */
186 ifport = interface->ifport;
188 ifport = ifport->next;
191 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
197 static int inter_tespecial(struct interface *interface, char *filename, int line, char *parameter, char *value)
199 struct interface_port *ifport;
201 /* port in chain ? */
202 if (!interface->ifport) {
203 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
206 /* goto end of chain */
207 ifport = interface->ifport;
209 ifport = ifport->next;
212 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
215 ifport->tespecial = 1;
218 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
220 if (!strcasecmp(value, "yes")) {
221 interface->is_tones = IS_YES;
223 if (!strcasecmp(value, "no")) {
224 interface->is_tones = IS_NO;
226 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
231 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
233 if (!strcasecmp(value, "yes")) {
234 interface->is_earlyb = IS_YES;
236 if (!strcasecmp(value, "no")) {
237 interface->is_earlyb = IS_NO;
239 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
244 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
246 if (!strcasecmp(value, "linear")) {
247 interface->hunt = HUNT_LINEAR;
249 if (!strcasecmp(value, "roundrobin")) {
250 interface->hunt = HUNT_ROUNDROBIN;
252 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
257 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
259 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);
262 static int inter_portnum(struct interface *interface, char *filename, int line, char *parameter, char *value)
264 struct interface_port *ifport, **ifportp;
265 struct interface *searchif;
268 val = get_number(value);
270 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
273 /* check for port already assigned */
274 searchif = interface_newlist;
276 ifport = searchif->ifport;
278 if (ifport->portnum == val) {
279 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
282 ifport = ifport->next;
284 searchif = searchif->next;
286 /* alloc port substructure */
287 ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
289 ifport->interface = interface;
291 ifport->portnum = val;
293 ifportp = &interface->ifport;
295 ifportp = &((*ifportp)->next);
299 static int inter_portname(struct interface *interface, char *filename, int line, char *parameter, char *value)
301 struct interface_port *ifport, **ifportp;
302 struct interface *searchif;
304 /* check for port already assigned */
305 searchif = interface_newlist;
307 ifport = searchif->ifport;
309 if (!strcasecmp(ifport->portname, value)) {
310 SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
313 /* check for use as GSM */
315 SPRINT(interface_error, "Error in %s (line %d): Interface already used for GSM.\n", filename, line);
318 ifport = ifport->next;
320 searchif = searchif->next;
322 /* alloc port substructure */
323 ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
325 ifport->interface = interface;
327 ifport->portnum = -1; // disable until resolved
328 SCPY(ifport->portname, value);
330 ifportp = &interface->ifport;
332 ifportp = &((*ifportp)->next);
336 static int inter_l1hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
338 struct interface_port *ifport;
340 /* port in chain ? */
341 if (!interface->ifport) {
342 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
345 /* goto end of chain */
346 ifport = interface->ifport;
348 ifport = ifport->next;
349 if (!strcmp(value, "yes")) {
352 if (!strcmp(value, "no")) {
355 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
360 static int inter_l2hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
362 struct interface_port *ifport;
364 /* port in chain ? */
365 if (!interface->ifport) {
366 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
369 /* goto end of chain */
370 ifport = interface->ifport;
372 ifport = ifport->next;
373 if (!strcmp(value, "yes")) {
376 if (!strcmp(value, "no")) {
379 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
384 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
386 struct interface_port *ifport;
387 struct select_channel *selchannel, **selchannelp;
391 /* port in chain ? */
392 if (!interface->ifport) {
393 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
396 /* goto end of chain */
397 ifport = interface->ifport;
399 ifport = ifport->next;
403 p = get_seperated(p);
404 if (!strcasecmp(el, "force")) {
405 ifport->channel_force = 1;
406 if (ifport->out_channel) {
407 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
411 if (!strcasecmp(el, "any")) {
415 if (!strcasecmp(el, "free")) {
419 if (!strcasecmp(el, "no")) {
423 val = get_number(el);
425 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);
429 if (val<1 || val==16 || val>126) {
430 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
434 /* add to select-channel list */
435 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
438 selchannel->channel = val;
440 selchannelp = &ifport->out_channel;
442 selchannelp = &((*selchannelp)->next);
443 *selchannelp = selchannel;
448 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
450 struct interface_port *ifport;
451 struct select_channel *selchannel, **selchannelp;
455 /* port in chain ? */
456 if (!interface->ifport) {
457 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
460 /* goto end of chain */
461 ifport = interface->ifport;
463 ifport = ifport->next;
467 p = get_seperated(p);
468 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE) {
469 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
472 if (!strcasecmp(el, "free")) {
476 val = get_number(el);
478 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
482 if (val<1 || val==16 || val>126) {
483 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
487 /* add to select-channel list */
488 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
491 selchannel->channel = val;
493 selchannelp = &ifport->in_channel;
495 selchannelp = &((*selchannelp)->next);
496 *selchannelp = selchannel;
501 static int inter_timeouts(struct interface *interface, char *filename, int line, char *parameter, char *value)
503 struct interface_port *ifport;
504 // struct select_channel *selchannel, **selchannelp;
508 /* port in chain ? */
509 if (!interface->ifport) {
510 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
513 /* goto end of chain */
514 ifport = interface->ifport;
516 ifport = ifport->next;
520 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects five timeout values.\n", filename, line, parameter);
524 p = get_seperated(p);
525 ifport->tout_setup = atoi(el);
529 p = get_seperated(p);
530 ifport->tout_dialing = atoi(el);
534 p = get_seperated(p);
535 ifport->tout_proceeding = atoi(el);
539 p = get_seperated(p);
540 ifport->tout_alerting = atoi(el);
544 p = get_seperated(p);
545 ifport->tout_disconnect = atoi(el);
548 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
550 struct interface_msn *ifmsn, **ifmsnp;
554 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
557 if (interface->ifscreen_in) {
558 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
566 p = get_seperated(p);
567 /* add MSN to list */
568 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
571 SCPY(ifmsn->msn, el);
573 ifmsnp = &interface->ifmsn;
575 ifmsnp = &((*ifmsnp)->next);
580 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
582 struct interface_screen *ifscreen;
586 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
589 /* add screen entry to list*/
590 ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
592 ifscreen->match_type = -1; /* unchecked */
593 ifscreen->match_present = -1; /* unchecked */
594 ifscreen->result_type = -1; /* unchanged */
595 ifscreen->result_present = -1; /* unchanged */
598 ifscreenp = &((*ifscreenp)->next);
599 *ifscreenp = ifscreen;
600 // printf("interface=%s\n", interface->name);
605 p = get_seperated(p);
606 if (!strcasecmp(el, "unknown")) {
607 if (ifscreen->match_type != -1) {
609 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
612 ifscreen->match_type = INFO_NTYPE_UNKNOWN;
614 if (!strcasecmp(el, "subscriber")) {
615 if (ifscreen->match_type != -1)
617 ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
619 if (!strcasecmp(el, "national")) {
620 if (ifscreen->match_type != -1)
622 ifscreen->match_type = INFO_NTYPE_NATIONAL;
624 if (!strcasecmp(el, "international")) {
625 if (ifscreen->match_type != -1)
627 ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
629 if (!strcasecmp(el, "allowed")) {
630 if (ifscreen->match_present != -1) {
632 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
635 ifscreen->match_present = INFO_PRESENT_ALLOWED;
637 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted")) {
638 if (ifscreen->match_present != -1)
640 ifscreen->match_present = INFO_PRESENT_RESTRICTED;
642 SCPY(ifscreen->match, el);
643 /* check for % at the end */
644 if (strchr(el, '%')) {
645 if (strchr(el, '%') != el+strlen(el)-1) {
646 SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
653 if (ifscreen->match[0] == '\0') {
654 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
660 p = get_seperated(p);
661 if (!strcasecmp(el, "unknown")) {
662 if (ifscreen->result_type != -1)
664 ifscreen->result_type = INFO_NTYPE_UNKNOWN;
666 if (!strcasecmp(el, "subscriber")) {
667 if (ifscreen->result_type != -1)
669 ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
671 if (!strcasecmp(el, "national")) {
672 if (ifscreen->result_type != -1)
674 ifscreen->result_type = INFO_NTYPE_NATIONAL;
676 if (!strcasecmp(el, "international")) {
677 if (ifscreen->result_type != -1)
679 ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
681 if (!strcasecmp(el, "present") || !strcasecmp(el, "presented") || !strcasecmp(el, "allowed") || !strcasecmp(el, "allow")) {
682 if (ifscreen->result_present != -1)
684 ifscreen->result_present = INFO_PRESENT_ALLOWED;
686 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted") || !strcasecmp(el, "deny") || !strcasecmp(el, "denied")) {
687 if (ifscreen->result_present != -1)
689 ifscreen->result_present = INFO_PRESENT_RESTRICTED;
691 SCPY(ifscreen->result, el);
692 /* check for % at the end */
693 if (strchr(el, '%')) {
694 if (strchr(el, '%') != el+strlen(el)-1) {
695 SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
702 if (ifscreen->result[0] == '\0') {
703 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
708 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
710 if (interface->ifmsn) {
711 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
715 return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
717 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
719 return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
721 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
723 struct interface_port *ifport;
725 /* port in chain ? */
726 if (!interface->ifport) {
727 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
730 /* goto end of chain */
731 ifport = interface->ifport;
733 ifport = ifport->next;
737 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
741 /* seperate parameter from filter */
747 while(*p > 0 && *p <= 32)
751 if (!strcasecmp(value, "gain")) {
757 while(*q > 0 && *q <= 32)
760 if (*p == 0 || *q == 0) {
761 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects two gain values.\n", filename, line, parameter, value);
764 if (atoi(p)<-8 || atoi(p)>8 || atoi(q)<-8 || atoi(q)>8) {
765 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' gain values not in range. (-8...8)\n", filename, line, parameter, value);
768 interface->tx_gain = atoi(p);
769 interface->rx_gain = atoi(q);
771 if (!strcasecmp(value, "pipeline")) {
773 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects pipeline string.\n", filename, line, parameter, value);
776 SCPY(interface->pipeline, p);
778 if (!strcasecmp(value, "blowfish")) {
779 unsigned char key[56];
782 if (!!strncmp(p, "0x", 2)) {
783 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects blowfish key starting with '0x'.\n", filename, line, parameter, value);
790 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key too long.\n", filename, line, parameter, value);
793 if (*p >= '0' && *p <= '9')
794 key[l] = (*p-'0')<<4;
795 else if (*p >= 'a' && *p <= 'f')
796 key[l] = (*p-'a'+10)<<4;
797 else if (*p >= 'A' && *p <= 'F')
798 key[l] = (*p-'A'+10)<<4;
801 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);
806 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);
809 if (*p >= '0' && *p <= '9')
810 key[l] = (*p-'0')<<4;
811 else if (*p >= 'a' && *p <= 'f')
812 key[l] = (*p-'a'+10)<<4;
813 else if (*p >= 'A' && *p <= 'F')
814 key[l] = (*p-'A'+10)<<4;
821 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);
824 memcpy(interface->bf_key, key, l);
825 interface->bf_len = l;
827 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has unknown filter '%s'.\n", filename, line, parameter, value);
832 static int inter_dialmax(struct interface *interface, char *filename, int line, char *parameter, char *value)
834 struct interface_port *ifport;
836 /* port in chain ? */
837 if (!interface->ifport) {
838 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
841 /* goto end of chain */
842 ifport = interface->ifport;
844 ifport = ifport->next;
845 ifport->dialmax = atoi(value);
848 static int inter_tones_dir(struct interface *interface, char *filename, int line, char *parameter, char *value)
850 struct interface_port *ifport;
852 /* port in chain ? */
853 if (!interface->ifport) {
854 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
857 /* goto end of chain */
858 ifport = interface->ifport;
860 ifport = ifport->next;
861 SCPY(ifport->tones_dir, value);
864 static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
867 SPRINT(interface_error, "Error in %s (line %d): GSM not compiled in.\n", filename, line);
870 struct interface_port *ifport;
871 struct interface *searchif;
875 SPRINT(interface_error, "Error in %s (line %d): GSM is not activated.\n", filename, line);
878 searchif = interface_newlist;
880 ifport = searchif->ifport;
883 SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm\n", filename, line, value);
886 ifport = ifport->next;
888 searchif = searchif->next;
892 if (inter_portname(interface, filename, line, "portname", gsm->conf.interface_lcr))
894 /* goto end of chain again to set gsmflag*/
895 ifport = interface->ifport;
897 ifport = ifport->next;
905 * structure of parameters
907 struct interface_param interface_param[] = {
908 { "extension", &inter_extension, "",
909 "If keyword is given, calls to interface are handled as internal extensions."},
910 {"tones", &inter_tones, "yes | no",
911 "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
913 {"earlyb", &inter_earlyb, "yes | no",
914 "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
916 {"hunt", &inter_hunt, "linear | roundrobin",
917 "Select the algorithm for selecting port with free channel."},
919 {"port", &inter_port, "<number>",
921 {"portnum", &inter_portnum, "<number>",
922 "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
923 {"portname", &inter_portname, "<name>",
924 "Same as 'portnum', but the name is given instead.\nUse 'isdninfo' to list all available ports and names."},
926 {"block", &inter_block, "",
927 "If keyword is given, calls on this interface are blocked.\n"
928 "This parameter must follow a 'port' parameter."},
930 {"ptp", &inter_ptp, "",
931 "The given port above is opened as point-to-point.\n"
932 "This is required on NT-mode ports that are multipoint by default.\n"
933 "This parameter must follow a 'port' parameter."},
936 {"ptmp", &inter_ptmp, "",
937 "The given port above is opened as point-to-multipoint.\n"
938 "This is required on PRI NT-mode ports that are point-to-point by default.\n"
939 "This parameter must follow a 'port' parameter."},
942 {"nt", &inter_nt, "",
943 "The given port above is opened in NT-mode.\n"
944 "This is required on interfaces that support both NT-mode and TE-mode.\n"
945 "This parameter must follow a 'port' parameter."},
947 {"te-special", &inter_tespecial, "",
948 "The given port uses a modified TE-mode.\n"
949 "All information elements that are allowed Network->User will then be\n"
950 "transmitted User->Network also. This is usefull to pass all informations\n"
951 "between two interconnected LCRs, like 'redirected number' or 'display'.\n"
952 "Note that this is not compliant with ISDN protocol.\n"
953 "This parameter must follow a 'port' parameter."},
955 {"layer1hold", &inter_l1hold, "yes | no",
956 "The given port will not release layer 1 after layer 2 is down.\n"
957 "It is required to keep layer 1 of telephones up, to solve activation problems.\n"
958 "This parameter must follow a 'port' parameter."},
960 {"layer2hold", &inter_l2hold, "yes | no",
961 "The given port will continuously try to establish layer 2 link and hold it.\n"
962 "It is required for PTP links in most cases, therefore it is default.\n"
963 "This parameter must follow a 'port' parameter."},
965 {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
966 "Channel selection list for all outgoing calls to the interface.\n"
967 "A free channels is searched in order of appearance.\n"
968 "This parameter must follow a 'port' parameter.\n"
969 " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
970 " <number>[,...] - List of channels to search.\n"
971 " free - Select any free channel\n"
972 " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
973 " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
975 {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
976 "Channel selection list for all incoming calls from the interface.\n"
977 "A free channels is accepted if in the list.\n"
978 "If any channel was requested, the first free channel found is selected.\n"
979 "This parameter must follow a 'port' parameter.\n"
980 " <number>[,...] - List of channels to accept.\n"
981 " free - Accept any free channel"},
983 {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
984 "Timeout values for call states. They are both for incoming and outgoing states.\n"
985 "The default is 120 seconds for all states. Use 0 to disable.\n"
986 "This parameter must follow a 'port' parameter.\n"},
988 {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
989 "Incoming caller ID is checked against given MSN numbers.\n"
990 "If the caller ID is not found in this list, it is overwritten by the first MSN"},
992 {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
993 "Adds an entry for incoming calls to the caller ID screen list.\n"
994 "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
995 "If '%' is given after old caller ID, it matches even if caller ID has\n"
996 "additional digits.\n"
997 "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
1000 " unknown | subsciber | national | international - Change caller ID type.\n"
1001 " present | restrict - Change presentation of caller ID."},
1003 {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1004 "Adds an entry for outgoing calls to the caller ID screen list.\n"
1005 "See 'screen-in' for help."},
1007 {"nodtmf", &inter_nodtmf, "",
1008 "Disables DTMF detection for this interface.\n"
1009 "This parameter must follow a 'port' parameter."},
1011 {"filter", &inter_filter, "<filter> <parameters>",
1012 "Adds/appends a filter. Filters are ordered in transmit direction.\n"
1013 "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
1014 "pipeline <string> - Sets echo cancelation pipeline.\n"
1015 "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
1017 {"dialmax", &inter_dialmax, "<digits>",
1018 "Limits the number of digits in setup/information message."},
1020 {"tones_dir", &inter_tones_dir, "<path>",
1021 "Overrides the given tone_dir in options.conf.\n"
1022 "To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
1024 {"gsm", &inter_gsm, "",
1025 "Sets up GSM interface for using OpenBSC.\n"
1026 "This interface must be a loopback interface. The second loopback interface\n"
1027 "must be assigned to OpenBSC"},
1029 {NULL, NULL, NULL, NULL}
1034 * read settings from interface.conf
1036 char interface_error[256];
1037 struct interface *read_interfaces(void)
1042 unsigned int line, i;
1044 struct interface *interface = NULL, /* in case no interface */
1045 **interfacep = &interface_newlist;
1046 char parameter[128];
1048 int expecting = 1; /* expecting new interface */
1049 struct interface_param *ifparam;
1051 if (interface_newlist != NULL)
1052 FATAL("list is not empty.\n");
1053 interface_error[0] = '\0';
1054 SPRINT(filename, "%s/interface.conf", CONFIG_DATA);
1056 if (!(fp = fopen(filename,"r"))) {
1057 SPRINT(interface_error, "Cannot open '%s'\n", filename);
1062 while((fgets(buffer,sizeof(buffer),fp))) {
1063 buffer[sizeof(buffer)-1]=0;
1064 if (buffer[0]) buffer[strlen(buffer)-1]=0;
1068 while(*p <= 32) { /* skip spaces */
1073 if (*p==0 || *p=='#') /* ignore comments and empty line */
1078 i=0; /* read parameter */
1080 if (i+1 >= sizeof(parameter)) {
1081 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
1084 parameter[i+1] = '\0';
1085 parameter[i++] = *p++;
1088 while(*p <= 32) { /* skip spaces */
1094 if (*p!=0 && *p!='#') { /* missing name */
1095 i=0; /* read until end */
1096 while(*p!=0 && *p!='#') {
1097 if (i+1 >= sizeof(value)) {
1098 SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
1105 /* remove trailing spaces from value */
1107 if (value[i-1]==0 || value[i-1]>32)
1114 /* check for interface name as first statement */
1115 if (expecting && parameter[0]!='[') {
1116 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1121 /* check for new interface */
1122 if (parameter[0] == '[') {
1123 if (parameter[strlen(parameter)-1] != ']') {
1124 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1127 parameter[strlen(parameter)-1] = '\0';
1129 /* check if interface name already exists */
1130 interface = interface_newlist;
1132 if (!strcasecmp(interface->name, parameter+1)) {
1133 SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
1136 interface = interface->next;
1139 /* append interface to new list */
1140 interface = (struct interface *)MALLOC(sizeof(struct interface));
1143 /* name interface */
1144 SCPY(interface->name, parameter+1);
1147 *interfacep = interface;
1148 interfacep = &interface->next;
1153 ifparam = interface_param;
1154 while(ifparam->name) {
1155 if (!strcasecmp(parameter, ifparam->name)) {
1156 if (ifparam->func(interface, filename, line, parameter, value))
1165 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1170 return(interface_newlist);
1172 PERROR_RUNTIME("%s", interface_error);
1174 free_interfaces(interface_newlist);
1175 interface_newlist = NULL;
1181 * freeing chain of interfaces
1183 void free_interfaces(struct interface *interface)
1186 struct interface_port *ifport;
1187 struct select_channel *selchannel;
1188 struct interface_msn *ifmsn;
1189 struct interface_screen *ifscreen;
1192 ifport = interface->ifport;
1194 selchannel = ifport->in_channel;
1197 selchannel = selchannel->next;
1198 FREE(temp, sizeof(struct select_channel));
1201 selchannel = ifport->out_channel;
1204 selchannel = selchannel->next;
1205 FREE(temp, sizeof(struct select_channel));
1209 ifport = ifport->next;
1210 FREE(temp, sizeof(struct interface_port));
1213 ifmsn = interface->ifmsn;
1216 ifmsn = ifmsn->next;
1217 FREE(temp, sizeof(struct interface_msn));
1220 ifscreen = interface->ifscreen_in;
1223 ifscreen = ifscreen->next;
1224 FREE(temp, sizeof(struct interface_screen));
1227 ifscreen = interface->ifscreen_out;
1230 ifscreen = ifscreen->next;
1231 FREE(temp, sizeof(struct interface_screen));
1235 interface = interface->next;
1236 FREE(temp, sizeof(struct interface));
1242 * defaults of ports if not specified by config
1244 static void set_defaults(struct interface_port *ifport)
1246 /* default channel selection list */
1247 if (!ifport->out_channel)
1248 default_out_channel(ifport);
1249 if (!ifport->in_channel)
1250 default_in_channel(ifport);
1251 /* default is_tones */
1252 if (ifport->interface->is_tones)
1253 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1255 ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
1256 /* default is_earlyb */
1257 if (ifport->interface->is_earlyb)
1258 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1260 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
1261 /* set locally flag */
1262 if (ifport->interface->extension)
1263 ifport->mISDNport->locally = 1;
1265 ifport->mISDNport->locally = 0;
1270 * all links between mISDNport and interface are made
1271 * unused mISDNports are closed, new mISDNports are opened
1272 * also set default select_channel lists
1274 void relink_interfaces(void)
1276 struct mISDNport *mISDNport;
1277 struct interface *interface;
1278 struct interface_port *ifport;
1280 /* unlink all mISDNports */
1281 mISDNport = mISDNport_first;
1283 mISDNport->ifport = NULL;
1284 mISDNport = mISDNport->next;
1287 /* relink existing mISDNports */
1288 interface = interface_newlist;
1290 ifport = interface->ifport;
1292 mISDNport = mISDNport_first;
1294 if (!strcmp(mISDNport->name, ifport->portname))
1295 ifport->portnum = mISDNport->portnum; /* same name, so we use same number */
1296 if (mISDNport->portnum == ifport->portnum) {
1297 PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", mISDNport->portnum);
1298 ifport->mISDNport = mISDNport;
1299 mISDNport->ifport = ifport;
1300 set_defaults(ifport);
1302 mISDNport = mISDNport->next;
1304 ifport = ifport->next;
1306 interface = interface->next;
1309 /* close unused mISDNports */
1311 mISDNport = mISDNport_first;
1313 if (mISDNport->ifport == NULL) {
1314 PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1315 /* remove all port objects and destroy port */
1316 mISDNport_close(mISDNport);
1319 mISDNport = mISDNport->next;
1322 /* open and link new mISDNports */
1323 interface = interface_newlist;
1325 ifport = interface->ifport;
1327 if (!ifport->mISDNport) {
1330 ifport = ifport->next;
1332 interface = interface->next;
1341 void load_port(struct interface_port *ifport)
1343 struct mISDNport *mISDNport;
1346 mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm);
1349 ifport->mISDNport = mISDNport;
1350 mISDNport->ifport = ifport;
1351 /* set number and name */
1352 ifport->portnum = mISDNport->portnum;
1353 SCPY(ifport->portname, mISDNport->name);
1355 set_defaults(ifport);
1357 ifport->block = 2; /* not available */
1362 * give summary of interface syntax
1364 void doc_interface(void)
1366 struct interface_param *ifparam;
1368 printf("Syntax overview\n");
1369 printf("---------------\n\n");
1371 printf("[<name>]\n");
1372 ifparam = interface_param;
1373 while(ifparam->name) {
1374 if (ifparam->name[0])
1375 printf("%s %s\n", ifparam->name, ifparam->usage);
1379 ifparam = interface_param;
1380 while(ifparam->name) {
1381 if (ifparam->name[0]) {
1382 printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1383 printf("%s\n", ifparam->help);
1391 * out==0: incoming caller id, out==1: outgoing caller id
1393 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1396 struct interface_msn *ifmsn;
1397 struct interface_screen *ifscreen;
1400 /* screen incoming caller id */
1402 /* check for MSN numbers, use first MSN if no match */
1404 ifmsn = interface->ifmsn;
1408 if (!strcmp(ifmsn->msn, id)) {
1411 ifmsn = ifmsn->next;
1414 start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (found in MSN list)");
1415 add_trace("msn", NULL, "%s", id);
1418 if (!ifmsn && msn1) { // not in list, first msn given
1419 start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (not found in MSN list)");
1420 add_trace("msn", "given", "%s", id);
1421 add_trace("msn", "used", "%s", msn1);
1423 UNCPY(id, msn1, idsize);
1424 id[idsize-1] = '\0';
1428 /* check screen list */
1430 ifscreen = interface->ifscreen_out;
1432 ifscreen = interface->ifscreen_in;
1434 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1435 if (ifscreen->match_present==-1 || ifscreen->match_present==*present) {
1436 if (strchr(ifscreen->match,'%')) {
1437 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1440 if (!strcmp(ifscreen->match, id))
1444 ifscreen = ifscreen->next;
1446 if (ifscreen) { // match
1447 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)");
1449 case INFO_NTYPE_UNKNOWN:
1450 add_trace("given", "type", "unknown");
1452 case INFO_NTYPE_SUBSCRIBER:
1453 add_trace("given", "type", "subscriber");
1455 case INFO_NTYPE_NATIONAL:
1456 add_trace("given", "type", "national");
1458 case INFO_NTYPE_INTERNATIONAL:
1459 add_trace("given", "type", "international");
1463 case INFO_PRESENT_ALLOWED:
1464 add_trace("given", "present", "allowed");
1466 case INFO_PRESENT_RESTRICTED:
1467 add_trace("given", "present", "restricted");
1469 case INFO_PRESENT_NOTAVAIL:
1470 add_trace("given", "present", "not available");
1473 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1474 if (ifscreen->result_type != -1) {
1475 *type = ifscreen->result_type;
1477 case INFO_NTYPE_UNKNOWN:
1478 add_trace("used", "type", "unknown");
1480 case INFO_NTYPE_SUBSCRIBER:
1481 add_trace("used", "type", "subscriber");
1483 case INFO_NTYPE_NATIONAL:
1484 add_trace("used", "type", "national");
1486 case INFO_NTYPE_INTERNATIONAL:
1487 add_trace("used", "type", "international");
1491 if (ifscreen->result_present != -1) {
1492 *present = ifscreen->result_present;
1494 case INFO_PRESENT_ALLOWED:
1495 add_trace("used", "present", "allowed");
1497 case INFO_PRESENT_RESTRICTED:
1498 add_trace("used", "present", "restricted");
1500 case INFO_PRESENT_NOTAVAIL:
1501 add_trace("used", "present", "not available");
1505 if (strchr(ifscreen->match,'%')) {
1506 SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1507 UNCPY(id, ifscreen->result, idsize);
1508 id[idsize-1] = '\0';
1509 if (strchr(id,'%')) {
1510 *strchr(id,'%') = '\0';
1511 UNCAT(id, suffix, idsize);
1512 id[idsize-1] = '\0';
1515 UNCPY(id, ifscreen->result, idsize);
1516 id[idsize-1] = '\0';
1518 add_trace("used", "id", "%s", id[0]?id:"<empty>");