fixup sip
[lcr.git] / interface.c
index 3fc0a79..02e1531 100644 (file)
@@ -880,18 +880,12 @@ static int inter_dialmax(struct interface *interface, char *filename, int line,
 }
 static int inter_tones_dir(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);
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing tones directory.\n", filename, line);
                return(-1);
        }
-       /* goto end of chain */
-       ifport = interface->ifport;
-       while(ifport->next)
-               ifport = ifport->next;
-       SCPY(ifport->tones_dir, value);
+       SCPY(interface->tones_dir, value);
+
        return(0);
 }
 static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
@@ -907,18 +901,23 @@ static int inter_gsm_bs(struct interface *interface, char *filename, int line, c
 #else
        struct interface *searchif;
 
+       interface->gsm_bs = 1;
+
+       if (!value)
+               interface->gsm_bs_name[0] = '\0';
+       else
+               SCPY(interface->gsm_bs_name, value);
+
+       /* check if name is used multiple times */
        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);
+               if (searchif != interface && searchif->gsm_bs && !strcmp(searchif->gsm_bs_name, interface->gsm_bs_name)) {
+                       SPRINT(interface_error, "Error in %s (line %d): network '%s' already uses the given MS name '%s', choose a different one.\n", filename, line, interface->gsm_bs_name, searchif->gsm_bs_name);
                        return(-1);
                }
                searchif = searchif->next;
        }
 
-       /* goto end of chain again to set gsmflag */
-       interface->gsm_bs = 1;
-
        return(0);
 #endif
 }
@@ -953,7 +952,7 @@ static int inter_gsm_ms(struct interface *interface, char *filename, int line, c
        /* check if name is used multiple times */
        searchif = interface_newlist;
        while(searchif) {
-               if (searchif != interface && !strcmp(searchif->gsm_ms_name, interface->gsm_ms_name)) {
+               if (searchif != interface && searchif->gsm_bs && !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);
                }
@@ -975,16 +974,204 @@ static int inter_sip(struct interface *interface, char *filename, int line, char
 
        /* copy values */
        if (!value || !value[0]) {
-               SPRINT(interface_error, "Error in %s (line %d): Missing SIP local IP.\n", filename, line);
+               SPRINT(interface_error, "Error in %s (line %d): Missing SIP local peer.\n", filename, line);
+               return(-1);
+       }
+       p = get_seperated(value);
+       SCPY(interface->sip_local_peer, value);
+       SCPY(interface->sip_remote_peer, p);
+
+       return(0);
+#endif
+}
+static int inter_authenticate(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, *q;
+
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
+               return(-1);
+       }
+
+       /* copy values */
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing SIP user.\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);
+               SPRINT(interface_error, "Error in %s (line %d): Missing SIP password.\n", filename, line);
+               return(-1);
+       }
+       q = get_seperated(p);
+       SCPY(interface->sip_auth_user, value);
+       SCPY(interface->sip_auth_password, p);
+       if (q[0])
+               SCPY(interface->sip_auth_realm, q);
+
+       return(0);
+#endif
+}
+static int options_interval(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
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
+               return(-1);
+       }
+
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing options interval.\n", filename, line);
+               return(-1);
+       }
+       interface->sip_options_interval = atoi(value);
+
+       return(0);
+#endif
+}
+static int options_asserted_id(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
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
                return(-1);
        }
-       SCPY(interface->sip_local_peer, value);
-       SCPY(interface->sip_remote_peer, p);
+
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing asserted caller ID.\n", filename, line);
+               return(-1);
+       }
+       SCPY(interface->sip_asserted_id, value);
+
+       return(0);
+#endif
+}
+static int options_public(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
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
+               return(-1);
+       }
+       if (interface->sip_stun_server[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Don't specify STUN, if you want to define public IP.\n", filename, line);
+               return(-1);
+       }
+
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing public IP.\n", filename, line);
+               return(-1);
+       }
+       SCPY(interface->sip_public_ip, value);
+
+       return(0);
+#endif
+}
+static int options_stun(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;
+
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
+               return(-1);
+       }
+       if (interface->sip_public_ip[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Don't specify public IP, if you want to define STUN.\n", filename, line);
+               return(-1);
+       }
+
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing STUN server.\n", filename, line);
+               return(-1);
+       }
+       p = get_seperated(value);
+       if (!p[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing STUN timer.\n", filename, line);
+               return(-1);
+       }
+       SCPY(interface->sip_stun_server, value);
+       interface->sip_stun_interval = atoi(p);
+
+       return(0);
+#endif
+}
+static int inter_rtp_ports(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;
+
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
+               return(-1);
+       }
+
+       /* copy values */
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing 'from' port.\n", filename, line);
+               return(-1);
+       }
+       p = get_seperated(value);
+       if (!p[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing 'to' port.\n", filename, line);
+               return(-1);
+       }
+       interface->rtp_port_from = atoi(value);
+       interface->rtp_port_to = atoi(p);
+
+       return(0);
+#endif
+}
+static int inter_register(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, *q;
+
+       if (!interface->sip) {
+               SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
+               return(-1);
+       }
+
+       /* copy values */
+       if (!value || !value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing SIP user.\n", filename, line);
+               return(-1);
+       }
+       p = get_seperated(value);
+       if (!p[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing SIP host\n", filename, line);
+               return(-1);
+       }
+       q = get_seperated(p);
+       if (!q[0])
+               interface->sip_register_interval = 0;
+       else
+               interface->sip_register_interval = atoi(q);
+       interface->sip_register = 1;
+       SCPY(interface->sip_register_user, value);
+       SCPY(interface->sip_register_host, p);
 
        return(0);
 #endif
@@ -1100,9 +1287,11 @@ static int inter_ss5(struct interface *interface, char *filename, int line, char
                if (!strcasecmp(element, "release"))
                        ifport->ss5 |= SS5_FEATURE_RELEASE;
                else
-               if (!strcasecmp(element, "suppress")
-                || !strcasecmp(element, "mute"))
-                       ifport->ss5 |= SS5_FEATURE_MUTE;
+               if (!strcasecmp(element, "mute-rx"))
+                       ifport->ss5 |= SS5_FEATURE_MUTE_RX;
+               else
+               if (!strcasecmp(element, "mute-tx"))
+                       ifport->ss5 |= SS5_FEATURE_MUTE_TX;
                else
                if (!strcasecmp(element, "quality"))
                        ifport->ss5 |= SS5_FEATURE_QUALITY;
@@ -1306,7 +1495,7 @@ struct interface_param interface_param[] = {
        {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
        "Timeout values for call states. They are both for incoming and outgoing states.\n"
        "The default is 120 seconds for all states. Use 0 to disable.\n"
-       "This parameter must follow a 'port' parameter.\n"},
+       "This parameter must follow a 'port' parameter."},
 
        {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
        "Incoming caller ID is checked against given MSN numbers.\n"
@@ -1344,39 +1533,62 @@ struct interface_param interface_param[] = {
        {"dialmax", &inter_dialmax, "<digits>",
        "Limits the number of digits in setup/information message."},
 
-       {"tones_dir", &inter_tones_dir, "<path>",
+       {"tones-dir", &inter_tones_dir, "<path>",
        "Overrides the given tone_dir in options.conf.\n"
        "To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
+       {"tones_dir", &inter_tones_dir, "<path>",
+       "Same as tones-dir"},
 
        {"gsm", &inter_gsm, "",
        ""},
-       {"gsm-bs", &inter_gsm_bs, "",
-       "Sets up GSM base station interface for using OpenBSC."},
+       {"gsm-bs", &inter_gsm_bs, "[<socket name>]",
+       "Sets up GSM base station interface for using OpenBSC.\n"
+       "The socket is /tmp/bsc_mncc by default. If socket name is given, the socket will be\n"
+       "extended to /tmp/bsc_mncc_<socket name>."},
        {"hr", &inter_gsm_bs_hr, "",
        "Enable and prefer half rate for mobile terminating calls."},
-       {"gsm-ms", &inter_gsm_ms, "<socket>",
+       {"gsm-ms", &inter_gsm_ms, "<socket name>",
        "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>",
+       "The socket will be /tmp/ms_mncc_<socket name>."},
+
+       {"sip", &inter_sip, "<local IP/host>[:port] [<remote IP/host>[port]]",
        "Sets up SIP interface that represents one SIP endpoint.\n"
-       "Give SIP configuration file."},
+       "If the remote IP/host is omitted, a client must register first to us."},
+       {"register", &inter_register, "<user> <host> [options-interval]",
+       "Registers to given SIP registrar.\n"
+       "Optionally give SIP timer to send OPTIONS messages to keepalive REGISTER sessions."},
+       {"authenticate", &inter_authenticate, "<user> <password> [realm]",
+       "Defines SIP user and password for authentication.\n"
+       "If no remote IP was give, we are SIP gateway, so realm must be given also."},
+       {"options-interval", &options_interval, "<interval> | 0",
+       "Defines SIP timer to send OPTIONS messages to keepalive INVITE sessions."},
+       {"asserted-id", &options_asserted_id, "<caller-id>",
+       "Defines SIP's asserted-id in INVITE message."},
+       {"public", &options_public, "<server> <interval>",
+       "Defines public IP, if this endpoint is behind NAT firewall."},
+       {"stun", &options_stun, "<server> <interval>",
+       "Defines STUN server to resolv real local IP.\n"
+       "The interval is used to check if IP has changed. (use 300)"},
+       {"rtp-ports", &inter_rtp_ports, "<port from> <port to>",
+       "Defines the range of ports to be used for RTP. This overrides the default."},
+
        {"rtp-bridge", &inter_rtp_bridge, "",
        "Enables RTP bridging directly from this interface.\n"
        "This only works if both bridged interfaces use RTP, e.g. between gsm-bs and sip.\n"
-       "This parameter must follow a 'bridge' parameter.\n"},
+       "This parameter must follow a 'bridge' parameter."},
 #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"},
+       "If none are defined, GSM fullrate V1 (type 3) is assumed."},
 #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"
@@ -1394,8 +1606,9 @@ struct interface_param interface_param[] = {
        " 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."},
+       " release - Pulse dialing a star (11 pulses per digit) clears current call.\n"
+       " mutes-rx - Mute received 2600 and 2400 Hz tones when detected. (more realistic)\n"
+       " mutes-tx - Mute received 2600 and 2400 Hz tones while transmitting reply tone. (more hackable)"},
 #endif
 
        {"remote", &inter_remote, "<application>",
@@ -1407,17 +1620,17 @@ struct interface_param interface_param[] = {
        {"pots-flash", &inter_pots_flash, "",
        "Allow flash button to hold an active call and setup a new call.\n"
        "Ihis parameter only appies to POTS type of interfaces\n"
-       "This parameter must follow a 'port' parameter.\n"},
+       "This parameter must follow a 'port' parameter."},
        {"pots-ring-after-hangup", &inter_pots_ring, "",
        "Allow ringing of last hold call after hangup. Other calls on hold will not be\n"
        "released.\n"
        "Ihis parameter only appies to POTS type of interfaces\n"
-       "This parameter must follow a 'port' parameter.\n"},
+       "This parameter must follow a 'port' parameter."},
        {"pots-transfer-after-hangup", &inter_pots_transfer, "",
        "If two calls on hold, both are connected after hangup.\n"
        "If one call is on hold and another one alerting, call on hold is tranfered.\n"
        "Ihis parameter only appies to POTS type of interfaces\n"
-       "This parameter must follow a 'port' parameter.\n"},
+       "This parameter must follow a 'port' parameter."},
 
        {"shutdown", &inter_shutdown, "",
        "Interface will not be loaded when processing interface.conf"},
@@ -1694,7 +1907,7 @@ void relink_interfaces(void)
 #endif
 #ifdef WITH_GSM_BS
                        if (interface->gsm_bs)
-                               gsm_bs_exit(0);
+                               gsm_bs_delete(interface->gsm_bs_name);
 #endif
 #ifdef WITH_SIP
                        if (interface->sip)
@@ -1729,7 +1942,7 @@ void relink_interfaces(void)
 #endif
 #ifdef WITH_GSM_BS
                        if (interface->gsm_bs)
-                               gsm_bs_init(interface);
+                               gsm_bs_new(interface);
 #endif
 #ifdef WITH_SIP
                        if (interface->sip)