summaryrefslogtreecommitdiffstats
path: root/gsm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gsm.cpp')
-rw-r--r--gsm.cpp366
1 files changed, 233 insertions, 133 deletions
diff --git a/gsm.cpp b/gsm.cpp
index 14f534c..9236ed2 100644
--- a/gsm.cpp
+++ b/gsm.cpp
@@ -4,12 +4,14 @@
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
+** MNCC-Interface: Harald Welte **
** **
** mISDN gsm **
** **
\*****************************************************************************/
#include "main.h"
+#include "mncc.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
@@ -19,8 +21,11 @@ extern "C" {
}
#include <mISDN/mISDNcompat.h>
+#include <assert.h>
-struct lcr_gsm *gsm = NULL;
+#define SOCKET_RETRY_TIMER 5
+
+//struct lcr_gsm *gsm = NULL;
int new_callref = 1;
@@ -29,147 +34,53 @@ static const struct _value_string {
int msg_type;
const char *name;
} mncc_names[] = {
-#if defined(MNCC_SETUP_REQ)
{ MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
-#endif
-#if defined(MNCC_SETUP_IND)
{ MNCC_SETUP_IND, "MNCC_SETUP_IND" },
-#endif
-#if defined(MNCC_SETUP_RSP)
{ MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
-#endif
-#if defined(MNCC_SETUP_CNF)
{ MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
-#endif
-#if defined(MNCC_SETUP_COMPL_REQ)
{ MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
-#endif
-#if defined(MNCC_SETUP_COMPL_IND)
{ MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
-#endif
-#if defined(MNCC_CALL_CONF_IND)
{ MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
-#endif
-#if defined(MNCC_CALL_PROC_REQ)
{ MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
-#endif
-#if defined(MNCC_PROGRESS_REQ)
{ MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
-#endif
-#if defined(MNCC_ALERT_REQ)
{ MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
-#endif
-#if defined(MNCC_ALERT_IND)
{ MNCC_ALERT_IND, "MNCC_ALERT_IND" },
-#endif
-#if defined(MNCC_NOTIFY_REQ)
{ MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
-#endif
-#if defined(MNCC_NOTIFY_IND)
{ MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
-#endif
-#if defined(MNCC_DISC_REQ)
{ MNCC_DISC_REQ, "MNCC_DISC_REQ" },
-#endif
-#if defined(MNCC_DISC_IND)
{ MNCC_DISC_IND, "MNCC_DISC_IND" },
-#endif
-#if defined(MNCC_REL_REQ)
{ MNCC_REL_REQ, "MNCC_REL_REQ" },
-#endif
-#if defined(MNCC_REL_IND)
{ MNCC_REL_IND, "MNCC_REL_IND" },
-#endif
-#if defined(MNCC_REL_CNF)
{ MNCC_REL_CNF, "MNCC_REL_CNF" },
-#endif
-#if defined(MNCC_FACILITY_REQ)
{ MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
-#endif
-#if defined(MNCC_FACILITY_IND)
{ MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
-#endif
-#if defined(MNCC_START_DTMF_IND)
{ MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
-#endif
-#if defined(MNCC_START_DTMF_RSP)
{ MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
-#endif
-#if defined(MNCC_START_DTMF_REJ)
{ MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
-#endif
-#if defined(MNCC_STOP_DTMF_IND)
{ MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
-#endif
-#if defined(MNCC_STOP_DTMF_RSP)
{ MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
-#endif
-#if defined(MNCC_MODIFY_REQ)
{ MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
-#endif
-#if defined(MNCC_MODIFY_IND)
{ MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
-#endif
-#if defined(MNCC_MODIFY_RSP)
{ MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
-#endif
-#if defined(MNCC_MODIFY_CNF)
{ MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
-#endif
-#if defined(MNCC_MODIFY_REJ)
{ MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
-#endif
-#if defined(MNCC_HOLD_IND)
{ MNCC_HOLD_IND, "MNCC_HOLD_IND" },
-#endif
-#if defined(MNCC_HOLD_CNF)
{ MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
-#endif
-#if defined(MNCC_HOLD_REJ)
{ MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
-#endif
-#if defined(MNCC_RETRIEVE_IND)
{ MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
-#endif
-#if defined(MNCC_RETRIEVE_CNF)
{ MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
-#endif
-#if defined(MNCC_RETRIEVE_REJ)
{ MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
-#endif
-#if defined(MNCC_USERINFO_REQ)
{ MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
-#endif
-#if defined(MNCC_USERINFO_IND)
{ MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
-#endif
-#if defined(MNCC_REJ_REQ)
{ MNCC_REJ_REQ, "MNCC_REJ_REQ" },
-#endif
-#if defined(MNCC_REJ_IND)
{ MNCC_REJ_IND, "MNCC_REJ_IND" },
-#endif
-#if defined(MNCC_PROGRESS_IND)
{ MNCC_PROGRESS_IND, "MNCC_PROGRESS_IND" },
-#endif
-#if defined(MNCC_CALL_PROC_IND)
{ MNCC_CALL_PROC_IND, "MNCC_CALL_PROC_IND" },
-#endif
-#if defined(MNCC_CALL_CONF_REQ)
{ MNCC_CALL_CONF_REQ, "MNCC_CALL_CONF_REQ" },
-#endif
-#if defined(MNCC_START_DTMF_REQ)
{ MNCC_START_DTMF_REQ, "MNCC_START_DTMF_REQ" },
-#endif
-#if defined(MNCC_STOP_DTMF_REQ)
{ MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
-#endif
-#if defined(MNCC_HOLD_REQ)
{ MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
-#endif
-#if defined(MNCC_RETRIEVE_REQ)
{ MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
-#endif
{ 0, NULL }
};
@@ -185,6 +96,8 @@ const char *mncc_name(int value)
return "unknown";
}
+static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
+
/*
* create and send mncc message
*/
@@ -197,17 +110,12 @@ struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
mncc->callref = callref;
return (mncc);
}
-int send_and_free_mncc(void *instance, unsigned int msg_type, void *data)
+int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
{
int ret = 0;
- if (instance) {
-#ifdef WITH_GSM_BS
- ret = mncc_send((struct gsm_network *)instance, msg_type, data);
-#endif
-#ifdef WITH_GSM_MS
- ret = mncc_send((struct osmocom_ms *)instance, msg_type, data);
-#endif
+ if (lcr_gsm) {
+ ret = mncc_send(lcr_gsm, msg_type, data);
}
free(data);
@@ -224,7 +132,7 @@ Pgsm::Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_se
p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
memset(&p_m_g_delete, 0, sizeof(p_m_g_delete));
add_work(&p_m_g_delete, delete_event, this, 0);
- p_m_g_instance = NULL;
+ p_m_g_lcr_gsm = NULL;
p_m_g_callref = 0;
p_m_g_mode = 0;
p_m_g_gsm_b_sock = -1;
@@ -385,12 +293,10 @@ void Pgsm::frame_send(void *_frame)
frame->msg_type = GSM_TCHF_FRAME;
frame->callref = p_m_g_callref;
memcpy(frame->data, _frame, 33);
-#ifdef WITH_GSM_BS
- mncc_send((struct gsm_network *)p_m_g_instance, frame->msg_type, frame);
-#endif
-#ifdef WITH_GSM_MS
- mncc_send((struct osmocom_ms *)p_m_g_instance, frame->msg_type, frame);
-#endif
+
+ if (p_m_g_lcr_gsm) {
+ mncc_send(p_m_g_lcr_gsm, frame->msg_type, frame);
+ }
}
@@ -479,7 +385,7 @@ void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm
mode->lchan_mode = 0x01; /* GSM V1 */
add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
end_trace();
- send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
+ send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode);
}
@@ -501,7 +407,7 @@ void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
end_trace();
frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
- send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
+ send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
p_m_g_tch_connected = 1;
}
}
@@ -524,7 +430,7 @@ void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mnc
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
end_trace();
frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
- send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
+ send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
p_m_g_tch_connected = 1;
}
}
@@ -556,7 +462,7 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc
gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
end_trace();
- send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
+ send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp);
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
@@ -568,7 +474,7 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
end_trace();
frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
- send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
+ send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
p_m_g_tch_connected = 1;
}
}
@@ -587,7 +493,7 @@ void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct g
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
end_trace();
frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
- send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
+ send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
p_m_g_tch_connected = 1;
}
}
@@ -622,7 +528,7 @@ void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc
add_trace("cause", "value", "%d", resp->cause.value);
#endif
end_trace();
- send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
+ send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp);
/* sending release to endpoint */
while(p_epointlist) {
@@ -702,7 +608,7 @@ void Pgsm::message_notify(unsigned int epoint_id, int message_id, union paramete
end_trace();
mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
mncc->notify = notify;
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
}
}
}
@@ -725,7 +631,7 @@ void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parame
add_trace("progress", "descr", "%d", mncc->progress.descr);
}
end_trace();
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
new_state(PORT_STATE_IN_ALERTING);
@@ -733,7 +639,7 @@ void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parame
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
end_trace();
mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
p_m_g_tch_connected = 1;
}
}
@@ -799,7 +705,7 @@ void Pgsm::message_connect(unsigned int epoint_id, int message_id, union paramet
add_trace("connected", "number", "%s", mncc->connected.number);
}
end_trace();
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
new_state(PORT_STATE_CONNECT_WAITING);
}
@@ -829,7 +735,7 @@ void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union para
add_trace("cause", "location", "%d", mncc->cause.location);
add_trace("cause", "value", "%d", mncc->cause.value);
end_trace();
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
new_state(PORT_STATE_OUT_DISCONNECT);
@@ -837,7 +743,7 @@ void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union para
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
end_trace();
mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
p_m_g_tch_connected = 1;
}
}
@@ -859,7 +765,7 @@ void Pgsm::message_release(unsigned int epoint_id, int message_id, union paramet
add_trace("cause", "location", "%d", mncc->cause.location);
add_trace("cause", "value", "%d", mncc->cause.value);
end_trace();
- send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
+ send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
new_state(PORT_STATE_RELEASE);
trigger_work(&p_m_g_delete);
@@ -985,12 +891,6 @@ static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int i
int gsm_exit(int rc)
{
- /* free gsm instance */
- if (gsm) {
- free(gsm);
- gsm = NULL;
- }
-
return(rc);
}
@@ -999,14 +899,214 @@ int gsm_init(void)
/* seed the PRNG */
srand(time(NULL));
- /* create gsm instance */
- gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
+ return 0;
+}
+
+/*
+ * MNCC interface
+ */
+
+static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
+{
+ struct mncc_q_entry *qe;
+
+ qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
+ if (!qe)
+ return -ENOMEM;
+
+ qe->next = NULL;
+ qe->len = len;
+ memcpy(qe->data, mncc, len);
+
+ /* in case of empty list ... */
+ if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
+ /* the list head and tail both point to the new qe */
+ lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
+ } else {
+ /* append to tail of list */
+ lcr_gsm->mncc_q_tail->next = qe;
+ lcr_gsm->mncc_q_tail = qe;
+ }
+
+ lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
return 0;
}
-int handle_gsm(void)
+static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
+{
+ struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
+ if (!qe)
+ return NULL;
+
+ /* dequeue the successfully sent message */
+ lcr_gsm->mncc_q_hd = qe->next;
+ if (!qe)
+ return NULL;
+ if (qe == lcr_gsm->mncc_q_tail)
+ lcr_gsm->mncc_q_tail = NULL;
+
+ return qe;
+}
+
+/* routine called by LCR code if it wants to send a message to OpenBSC */
+static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
+{
+ int len = 0;
+
+ /* FIXME: the caller should provide this */
+ switch (msg_type) {
+ case GSM_TCHF_FRAME:
+ len = sizeof(struct gsm_data_frame) + 33;
+ break;
+ default:
+ len = sizeof(struct gsm_mncc);
+ break;
+ }
+
+ return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
+}
+
+/* close MNCC socket */
+static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
{
+ class Port *port;
+ class Pgsm *pgsm = NULL;
+ struct lcr_msg *message;
+
+ PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
+ close(lfd->fd);
+ unregister_fd(lfd);
+ lfd->fd = -1;
+
+ /* free all the calls that were running through the MNCC interface */
+ port = port_first;
+ while(port) {
+ if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
+ pgsm = (class Pgsm *)port;
+ if (pgsm->p_m_g_lcr_gsm == lcr_gsm) {
+ message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 27; // temp. unavail.
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ pgsm->new_state(PORT_STATE_RELEASE);
+ trigger_work(&pgsm->p_m_g_delete);
+ }
+ }
+ port = port->next;
+ }
+
+ /* flush the queue */
+ while (mncc_q_dequeue(lcr_gsm))
+ ;
+
+ /* start the re-connect timer */
+ schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
+
+ return 0;
+}
+
+/* write to OpenBSC via MNCC socket */
+static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
+{
+ struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
+ struct mncc_q_entry *qe, *qe2;
+ int rc;
+
+ while (1) {
+ qe = lcr_gsm->mncc_q_hd;
+ if (!qe) {
+ lfd->when &= ~LCR_FD_WRITE;
+ break;
+ }
+ rc = write(lfd->fd, qe->data, qe->len);
+ if (rc == 0)
+ return mncc_fd_close(lcr_gsm, lfd);
+ if (rc < 0)
+ return rc;
+ if (rc < (int)qe->len)
+ return -1;
+ /* dequeue the successfully sent message */
+ qe2 = mncc_q_dequeue(lcr_gsm);
+ assert(qe == qe2);
+ free(qe);
+ }
+ return 0;
+}
+
+/* read from OpenBSC via MNCC socket */
+static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
+{
+ struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
+ int rc;
+ static char buf[sizeof(struct gsm_mncc)+1024];
+ struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
+
+ memset(buf, 0, sizeof(buf));
+ rc = recv(lfd->fd, buf, sizeof(buf), 0);
+ if (rc == 0)
+ return mncc_fd_close(lcr_gsm, lfd);
+ if (rc < 0)
+ return rc;
+
+ /* Hand the MNCC message into LCR */
+ switch (lcr_gsm->type) {
+#ifdef WITH_GSM_BS
+ case LCR_GSM_TYPE_NETWORK:
+ return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
+#endif
+#ifdef WITH_GSM_MS
+ case LCR_GSM_TYPE_MS:
+ return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
+#endif
+ default:
+ return 0;
+ }
+}
+
+/* file descriptor callback if we can read or write form MNCC socket */
+static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
+{
+ int rc = 0;
+
+ if (what & LCR_FD_READ)
+ rc = mncc_fd_read(lfd, inst, idx);
+ if (rc < 0)
+ return rc;
+
+ if (what & LCR_FD_WRITE)
+ rc = mncc_fd_write(lfd, inst, idx);
+
+ return rc;
+}
+
+int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
+{
+ struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
+ int fd, rc;
+
+ lcr_gsm->mncc_lfd.fd = -1;
+
+ fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
+ if (fd < 0) {
+ PERROR("Cannot create SEQPACKET socket, giving up!\n");
+ return fd;
+ }
+
+ rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
+ sizeof(lcr_gsm->sun));
+ if (rc < 0) {
+ PERROR("Could not connect to MNCC socket %s, "
+ "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
+ SOCKET_RETRY_TIMER);
+ close(fd);
+ schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
+ } else {
+ PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
+ lcr_gsm->mncc_lfd.fd = fd;
+ register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);
+ }
+
return 0;
}