struct interface *interface_newlist = NULL; /* first interface in new list */
+#ifdef WITH_MISDN
/* set default out_channel */
void default_out_channel(struct interface_port *ifport)
{
selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
memuse++;
-
+
if (ifport->mISDNport->ntmode)
selchannel->channel = CHANNEL_FREE;
else
ifport->in_channel = selchannel;
}
+#endif
/* parse string for a positive number */
}
static int inter_extension(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
+ if (interface->external) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is external interface.\n", filename, line, parameter);
+ return(-1);
+ }
if (value[0]) {
SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
return(-1);
interface->extension = 1;
return(0);
}
+static int inter_extern(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ if (interface->extension) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is an extension.\n", filename, line, parameter);
+ return(-1);
+ }
+ if (value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
+ return(-1);
+ }
+ interface->external = 1;
+ return(0);
+}
static int inter_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
struct interface_port *ifport;
}
static int inter_portnum(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
+#ifndef WITH_MISDN
+ SPRINT(interface_error, "Error in %s (line %d): mISDN support is not compiled in.\n", filename, line);
+ return(-1);
+#else
struct interface_port *ifport, **ifportp;
struct interface *searchif;
int val;
ifportp = &((*ifportp)->next);
*ifportp = ifport;
return(0);
+#endif
}
static int inter_portname(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
+#ifndef WITH_MISDN
+ SPRINT(interface_error, "Error in %s (line %d): mISDN support is not compiled in.\n", filename, line);
+ return(-1);
+#else
struct interface_port *ifport, **ifportp;
struct interface *searchif;
- /* check for port already assigned */
+ /* goto end of chain */
+ ifport = interface->ifport;
+ if (ifport) {
+ while(ifport->next)
+ ifport = ifport->next;
+ }
+
+ /* check for port already assigned, but not for shared loop interface */
searchif = interface_newlist;
- while(searchif) {
- ifport = searchif->ifport;
- while(ifport) {
- if (!strcasecmp(ifport->portname, value)) {
- SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
- return(-1);
- }
- /* check for use as GSM */
- if (ifport->gsm) {
- SPRINT(interface_error, "Error in %s (line %d): Interface already used for GSM.\n", filename, line);
- return(-1);
+ if (!!strcmp(value, options.loopback_lcr))
+ {
+ while(searchif) {
+ ifport = searchif->ifport;
+ while(ifport) {
+ if (!strcasecmp(ifport->portname, value)) {
+ SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
+ return(-1);
+ }
+ ifport = ifport->next;
}
- ifport = ifport->next;
+ searchif = searchif->next;
}
- searchif = searchif->next;
}
/* alloc port substructure */
ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
ifportp = &((*ifportp)->next);
*ifportp = ifport;
return(0);
+#endif
}
static int inter_l1hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
}
static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
-#ifndef WITH_GSM
- SPRINT(interface_error, "Error in %s (line %d): GSM not compiled in.\n", filename, line);
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' is outdated.\nPlease use 'gsm-bs' for base station or 'gsm-ms' for mobile station interface!\n", filename, line, parameter);
+ return(-1);
+}
+static int inter_gsm_bs(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+#ifndef WITH_GSM_BS
+ SPRINT(interface_error, "Error in %s (line %d): GSM BS side not compiled in.\n", filename, line);
return(-1);
#else
+ struct interface *searchif;
+
+ searchif = interface_newlist;
+ while(searchif) {
+ if (searchif->gsm_bs) {
+ SPRINT(interface_error, "Error in %s (line %d): interface '%s' already uses gsm BS side.\n", filename, line, searchif->name);
+ return(-1);
+ }
+ searchif = searchif->next;
+ }
+
+ /* goto end of chain again to set gsmflag */
+ interface->gsm_bs = 1;
+
+ return(0);
+#endif
+}
+static int inter_gsm_ms(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+#ifndef WITH_GSM_MS
+ SPRINT(interface_error, "Error in %s (line %d): GSM MS side not compiled in.\n", filename, line);
+ return(-1);
+#else
+ struct interface *searchif;
+
+ interface->gsm_ms = 1;
+
+ /* copy values */
+ if (!value || !value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): Missing MS name and socket name.\n", filename, line);
+ return(-1);
+ }
+ SCPY(interface->gsm_ms_name, value);
+
+ /* check if name is used multiple times */
+ searchif = interface_newlist;
+ while(searchif) {
+ if (!strcmp(searchif->gsm_ms_name, interface->gsm_ms_name)) {
+ SPRINT(interface_error, "Error in %s (line %d): mobile '%s' already uses the given MS name '%s', choose a different one.\n", filename, line, interface->gsm_ms_name, searchif->gsm_ms_name);
+ return(-1);
+ }
+ searchif = searchif->next;
+ }
+
+ return(0);
+#endif
+}
+static int inter_sip(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+#ifndef WITH_SIP
+ SPRINT(interface_error, "Error in %s (line %d): SIP not compiled in.\n", filename, line);
+ return(-1);
+#else
+ char *p;
+
+ interface->sip = 1;
+
+ /* copy values */
+ if (!value || !value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): Missing SIP local IP.\n", filename, line);
+ return(-1);
+ }
+ p = get_seperated(value);
+ if (!p[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): Missing SIP remote IP.\n", filename, line);
+ return(-1);
+ }
+ SCPY(interface->sip_local_peer, value);
+ SCPY(interface->sip_remote_peer, p);
+
+ return(0);
+#endif
+}
+static int inter_rtp_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ int supported = 0;
+
+#ifdef WITH_GSM_BS
+ if (interface->gsm_bs)
+ supported = 1;
+#endif
+#ifdef WITH_SIP
+ if (interface->sip)
+ supported = 1;
+#endif
+ if (!supported) {
+ SPRINT(interface_error, "Error in %s (line %d): Interface does not support RTP\n", filename, line);
+ return(-1);
+ }
+ interface->rtp_bridge = 1;
+
+ return(0);
+}
+#if 0
+static int inter_rtp_payload(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+#ifndef WITH_GSM_BS
+ SPRINT(interface_error, "Error in %s (line %d): GSM BS side not compiled in.\n", filename, line);
+ return(-1);
+#else
+ if (!interface->gsm_bs) {
+ SPRINT(interface_error, "Error in %s (line %d): This parameter only works for GSM BS side interface\n", filename, line);
+ return(-1);
+ }
+ if (!interface->rtp_bridge) {
+ SPRINT(interface_error, "Error in %s (line %d): This parameter only works here, if RTP bridging is enabled\n", filename, line);
+ return(-1);
+ }
+ if (!value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one payload type\n", filename, line, parameter);
+ return(-1);
+ }
+ if (interface->gsm_bs_payloads == sizeof(interface->gsm_bs_payload_types)) {
+ SPRINT(interface_error, "Error in %s (line %d): Too many payload types defined\n", filename, line);
+ return(-1);
+ }
+ interface->gsm_bs_payload_types[interface->gsm_bs_payloads++] = atoi(value);
+
+ return(0);
+#endif
+}
+#endif
+static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ struct interface_port *ifport;
+
+ /* port in chain ? */
+ if (!interface->ifport) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
+ return(-1);
+ }
+ /* goto end of chain */
+ ifport = interface->ifport;
+ while(ifport->next)
+ ifport = ifport->next;
+ ifport->nonotify = 1;
+ return(0);
+}
+#ifdef WITH_SS5
+static int inter_ss5(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ struct interface_port *ifport;
+ char *element;
+
+ /* port in chain ? */
+ if (!interface->ifport) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
+ return(-1);
+ }
+ /* goto end of chain */
+ ifport = interface->ifport;
+ while(ifport->next)
+ ifport = ifport->next;
+ ifport->ss5 |= SS5_ENABLE;
+ while((element = strsep(&value, " "))) {
+ if (element[0] == '\0')
+ continue;
+ if (!strcasecmp(element, "connect"))
+ ifport->ss5 |= SS5_FEATURE_CONNECT;
+ else
+ if (!strcasecmp(element, "nodisconnect"))
+ ifport->ss5 |= SS5_FEATURE_NODISCONNECT;
+ else
+ if (!strcasecmp(element, "releaseguardtimer"))
+ ifport->ss5 |= SS5_FEATURE_RELEASEGUARDTIMER;
+ else
+ if (!strcasecmp(element, "bell"))
+ ifport->ss5 |= SS5_FEATURE_BELL;
+ else
+ if (!strcasecmp(element, "pulsedialing"))
+ ifport->ss5 |= SS5_FEATURE_PULSEDIALING;
+ else
+ if (!strcasecmp(element, "delay"))
+ ifport->ss5 |= SS5_FEATURE_DELAY;
+ else
+ if (!strcasecmp(element, "starrelease"))
+ ifport->ss5 |= SS5_FEATURE_STAR_RELEASE;
+ else
+ if (!strcasecmp(element, "suppress"))
+ ifport->ss5 |= SS5_FEATURE_SUPPRESS;
+ else {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' does not allow value element '%s'.\n", filename, line, parameter, element);
+ return(-1);
+ }
+ }
+ return(0);
+}
+#endif
+static int inter_remote(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
struct interface_port *ifport;
struct interface *searchif;
- /* check gsm */
- if (!gsm) {
- SPRINT(interface_error, "Error in %s (line %d): GSM is not activated.\n", filename, line);
+ if (!value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects application name as value.\n", filename, line, parameter);
return(-1);
}
searchif = interface_newlist;
while(searchif) {
ifport = searchif->ifport;
while(ifport) {
- if (ifport->gsm) {
- SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm\n", filename, line, value);
+ if (ifport->remote && !strcmp(ifport->remote_app, value)) {
+ SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses remote application '%s'.\n", filename, line, ifport->portname, value);
return(-1);
}
ifport = ifport->next;
}
/* set portname */
- if (inter_portname(interface, filename, line, "portname", gsm->conf.interface_lcr))
+ if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
return(-1);
- /* goto end of chain again to set gsmflag*/
+
+ /* goto end of chain again to set application name */
ifport = interface->ifport;
while(ifport->next)
ifport = ifport->next;
- ifport->gsm = 1;
+ ifport->remote = 1;
+ SCPY(ifport->remote_app, value);
+
+ return(0);
+}
+static int inter_shutdown(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ interface->shutdown = 1;
+
+ return(0);
+}
+static int inter_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ if (!value || !value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): Missing destination interface name.\n", filename, line);
+ return(-1);
+ }
+ interface->app = EAPP_TYPE_BRIDGE;
+ SCPY(interface->bridge_if, value);
+
return(0);
-#endif
}
struct interface_param interface_param[] = {
{ "extension", &inter_extension, "",
"If keyword is given, calls to interface are handled as internal extensions."},
+
+ { "extern", &inter_extern, "",
+ "If keyword is given, this interface will be used for external calls.\n"
+ "Calls require an external interface, if the routing action 'extern' is used\nwithout specific interface given.\n"
+ "Calls forwarded by extension's 'settings' also require an external interface."},
+
{"tones", &inter_tones, "yes | no",
"Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
"Channel selection list for all outgoing calls to the interface.\n"
"A free channels is searched in order of appearance.\n"
"This parameter must follow a 'port' parameter.\n"
- " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
+ " force - Forces the selected port with no acceptable alternative (see Q.931).\n"
+ " -> this will be automatically set for multipoint (ptmp) NT-mode ports\n"
" <number>[,...] - List of channels to search.\n"
" free - Select any free channel\n"
" any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
"To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
{"gsm", &inter_gsm, "",
- "Sets up GSM interface for using OpenBSC.\n"
- "This interface must be a loopback interface. The second loopback interface\n"
- "must be assigned to OpenBSC"},
+ ""},
+ {"gsm-bs", &inter_gsm_bs, "",
+ "Sets up GSM base station interface for using OpenBSC."},
+ {"gsm-ms", &inter_gsm_ms, "<socket>",
+ "Sets up GSM mobile station interface for using Osmocom-BB.\n"
+ "The name of the MS folows the interface name.\n"
+ "The socket is /tmp/osmocom_l2 by default and need to be changed when multiple\n"
+ "MS interfaces are used."},
+ {"sip", &inter_sip, "<local IP> <remote IP>",
+ "Sets up SIP interface that represents one SIP endpoint.\n"
+ "Give SIP configuration file."},
+ {"rtp-bridge", &inter_rtp_bridge, "",
+ "Enables RTP bridging directly from this interface.\n"
+ "This only works, if both ends support RTP. (like gsm-bs and sip)"},
+#if 0
+ not needed, since ms defines what is supports and remote (sip) tells what is selected
+ {"rtp-payload", &inter_rtp_payload, "<codec>",
+ "Define RTP payload to use. Only valid in conjuntion with gsm-bs!\n"
+ "If multiple payloads are defined, the first has highest priority.\n"
+ "If none are defined, GSM fullrate V1 (type 3) is assumed.\n"},
+#endif
+ {"nonotify", &inter_nonotify, "",
+ "Prevents sending notify messages to this interface. A call placed on hold will\n"
+ "Not affect the remote end (phone or telcom switch).\n"
+ "This parameter must follow a 'port' parameter."},
+ {"bridge", &inter_bridge, "<destination interface>",
+ "Define bridge application for this interface. All calls received on this\n"
+ "interface will be directly bridged to the given destination interface.\n"
+ "There will be no PBX application, nor routing."},
+
+#ifdef WITH_SS5
+ {"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
+ "Interface uses CCITT No. 5 inband signalling rather than D-channel.\n"
+ "This feature causes CPU load to rise and has no practical intend.\n"
+ "If you don't know what it is, you don't need it.\n"
+ "Features apply to protocol behaviour and blueboxing specials, they are:\n"
+ " connect - Connect incomming call to throughconnect audio, if required.\n"
+ " nodisconnect - Don't disconnect if incomming exchange disconnects.\n"
+ " releaseguardtimer - Tries to prevent Blueboxing by a longer release-guard.\n"
+ " bell - Allow releasing and pulse-dialing via 2600 Hz like old Bell systems.\n"
+ " pulsedialing - Use pulse dialing on outgoing exchange. (takes long!)\n"
+ " delay - Use on incomming exchange, to make you feel a delay when blueboxing.\n"
+ " starrelease - Pulse dialing a star (11 pulses per digit) clears current call.\n"
+ " suppress - Suppress received tones, as they will be recognized."},
+#endif
+
+ {"remote", &inter_remote, "<application>",
+ "Sets up an interface that communicates with the remote application.\n"
+ "Use \"asterisk\" to use chan_lcr as remote application."},
+
+ {"shutdown", &inter_shutdown, "",
+ "Interface will not be loaded when processing interface.conf"},
{NULL, NULL, NULL, NULL}
};
}
line=0;
- while((fgets(buffer,sizeof(buffer),fp))) {
- buffer[sizeof(buffer)-1]=0;
- if (buffer[0]) buffer[strlen(buffer)-1]=0;
+ while((GETLINE(buffer, fp))) {
p=buffer;
line++;
}
}
+#ifdef WITH_MISDN
/*
* defaults of ports if not specified by config
*/
-static void set_defaults(struct interface_port *ifport)
+static void set_mISDN_defaults(struct interface_port *ifport)
{
/* default channel selection list */
if (!ifport->out_channel)
default_out_channel(ifport);
if (!ifport->in_channel)
default_in_channel(ifport);
+ /* must force the channel on PTMP/NT ports */
+ if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode)
+ ifport->channel_force = 1;
/* default is_tones */
if (ifport->interface->is_tones)
ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
else
- ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
+ ifport->mISDNport->tones = (ifport->mISDNport->ntmode || ifport->mISDNport->ss5)?1:0;
/* default is_earlyb */
if (ifport->interface->is_earlyb)
ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
else
- ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
+ ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode && !ifport->mISDNport->ss5)?0:1;
/* set locally flag */
if (ifport->interface->extension)
ifport->mISDNport->locally = 1;
else
ifport->mISDNport->locally = 0;
}
+#endif
/*
*/
void relink_interfaces(void)
{
+#ifdef WITH_MISDN
struct mISDNport *mISDNport;
- struct interface *interface;
struct interface_port *ifport;
+#endif
+ struct interface *interface, *temp;
+ int found;
+
+ interface = interface_first;
+ while(interface) {
+ found = 0;
+ temp = interface_newlist;
+ while(temp) {
+ if (!strcmp(temp->name, interface->name))
+ found = 1;
+ temp = temp->next;
+ }
+ if (!found) {
+#ifdef WITH_GSM_MS
+ if (interface->gsm_ms)
+ gsm_ms_delete(interface->gsm_ms_name);
+#endif
+#ifdef WITH_GSM_BS
+ if (interface->gsm_bs)
+ gsm_bs_exit(0);
+#endif
+#ifdef WITH_SIP
+ if (interface->sip)
+ sip_exit_inst(interface);
+#endif
+ }
+ interface = interface->next;
+ }
+
+ interface = interface_newlist;
+ while(interface) {
+ found = 0;
+ temp = interface_first;
+ while(temp) {
+ if (!strcmp(temp->name, interface->name))
+ found = 1;
+ temp = temp->next;
+ }
+ if (!found) {
+#ifdef WITH_GSM_MS
+ if (interface->gsm_ms)
+ gsm_ms_new(interface);
+#endif
+#ifdef WITH_GSM_BS
+ if (interface->gsm_bs)
+ gsm_bs_init(interface);
+#endif
+#ifdef WITH_SIP
+ if (interface->sip)
+ sip_init_inst(interface);
+#endif
+ }
+ interface = interface->next;
+ }
+#ifdef WITH_MISDN
/* unlink all mISDNports */
mISDNport = mISDNport_first;
while(mISDNport) {
if (!strcmp(mISDNport->name, ifport->portname))
ifport->portnum = mISDNport->portnum; /* same name, so we use same number */
if (mISDNport->portnum == ifport->portnum) {
- PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", mISDNport->portnum);
+ PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", ifport->portnum, ifport->portname);
ifport->mISDNport = mISDNport;
mISDNport->ifport = ifport;
- set_defaults(ifport);
+ set_mISDN_defaults(ifport);
}
mISDNport = mISDNport->next;
}
while(mISDNport) {
if (mISDNport->ifport == NULL) {
PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
- /* remove all port objects and destroy port */
+ /* destroy port */
mISDNport_close(mISDNport);
goto closeagain;
}
ifport = interface->ifport;
while(ifport) {
if (!ifport->mISDNport) {
- load_port(ifport);
+ if (!interface->shutdown) {
+ load_mISDN_port(ifport);
+ } else {
+ ifport->block = 2;
+ }
}
ifport = ifport->next;
}
interface = interface->next;
}
-
+#endif
}
+#ifdef WITH_MISDN
/*
* load port
*/
-void load_port(struct interface_port *ifport)
+void load_mISDN_port(struct interface_port *ifport)
{
struct mISDNport *mISDNport;
/* open new port */
- mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm);
+ mISDNport = mISDNport_open(ifport);
if (mISDNport) {
/* link port */
ifport->mISDNport = mISDNport;
ifport->portnum = mISDNport->portnum;
SCPY(ifport->portname, mISDNport->name);
/* set defaults */
- set_defaults(ifport);
+ set_mISDN_defaults(ifport);
+ /* load static port instances */
+ mISDNport_static(mISDNport);
} else {
ifport->block = 2; /* not available */
}
}
+#endif
/*
* give summary of interface syntax
/* screen caller id
* out==0: incoming caller id, out==1: outgoing caller id
*/
-void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
+void do_screen(int out, char *id, int idsize, int *type, int *present, const char *interface_name)
{
char *msn1;
struct interface_msn *ifmsn;
struct interface_screen *ifscreen;
char suffix[64];
+ struct interface *interface = interface_first;
+
+ interface = getinterfacebyname(interface_name);
+ if (!interface)
+ return;
/* screen incoming caller id */
if (!out) {
}
}
+struct interface *getinterfacebyname(const char *name)
+{
+ struct interface *interface = interface_first;
+
+ while (interface) {
+ if (!strcmp(interface->name, name))
+ return interface;
+ interface = interface->next;
+ }
+
+ return NULL;
+}
+