summaryrefslogtreecommitdiffstats
path: root/gsm.cpp
diff options
context:
space:
mode:
authorAndreas Eversberg2011-09-02 11:08:56 +0200
committerAndreas Eversberg2011-09-02 11:08:56 +0200
commit97aa0881beacf536e3a2296381c055887583db8f (patch)
tree70ea6d838cbe6b788761d61adca7215bc0c268b8 /gsm.cpp
parentFixed broken timeout condition (diff)
downloadlcr-97aa0881beacf536e3a2296381c055887583db8f.tar.gz
lcr-97aa0881beacf536e3a2296381c055887583db8f.tar.xz
lcr-97aa0881beacf536e3a2296381c055887583db8f.zip
Support of GSM uses socket interface for both network and mobileHEADmaster
There is no linking of any osmocomBB source code required. In order to use osmocomBB or OpenBSC, just enable the interface, as described in defaults/interface.conf. At osmocomBB/mobile or at OpenBSC, just use the option "-m" to enable the socket interface. Enable GSM at LCR with "./configure --with-gsm-ms --with-gsm-bs".
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;
}