summaryrefslogtreecommitdiffstats
path: root/gsm_bs.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_bs.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_bs.cpp')
-rw-r--r--gsm_bs.cpp269
1 files changed, 39 insertions, 230 deletions
diff --git a/gsm_bs.cpp b/gsm_bs.cpp
index 2da06c7..285c88f 100644
--- a/gsm_bs.cpp
+++ b/gsm_bs.cpp
@@ -10,23 +10,9 @@
\*****************************************************************************/
#include "main.h"
-#include "config.h"
+#include "mncc.h"
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-extern "C" {
-#include <assert.h>
-#include <getopt.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <openbsc/mncc.h>
-#include <openbsc/trau_frame.h>
-}
-
-#define SOCKET_RETRY_TIMER 5
+struct lcr_gsm *gsm_bs = NULL;
/*
* DTMF stuff
@@ -61,7 +47,7 @@ void generate_dtmf(void)
*/
Pgsm_bs::Pgsm_bs(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Pgsm(type, mISDNport, portname, settings, channel, exclusive, mode)
{
- p_m_g_instance = gsm->network;
+ p_m_g_lcr_gsm = gsm_bs;
p_m_g_dtmf = NULL;
p_m_g_dtmf_index = 0;
@@ -95,7 +81,7 @@ void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct
resp = create_mncc(MNCC_START_DTMF_RSP, p_m_g_callref);
resp->fields |= MNCC_F_KEYPAD;
resp->keypad = mncc->keypad;
- 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);
#if 0
/* send dialing information */
@@ -143,7 +129,7 @@ void Pgsm_bs::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct
end_trace();
resp = create_mncc(MNCC_STOP_DTMF_RSP, p_m_g_callref);
resp->keypad = mncc->keypad;
- 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);
/* stop DTMF */
p_m_g_dtmf = NULL;
@@ -168,14 +154,14 @@ void Pgsm_bs::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_m
gsm_trace_header(p_m_mISDNport, this, MNCC_HOLD_CNF, DIRECTION_OUT);
end_trace();
resp = create_mncc(MNCC_HOLD_CNF, p_m_g_callref);
- 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);
/* disable audio */
if (p_m_g_tch_connected) { /* it should be true */
gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_DROP, DIRECTION_OUT);
end_trace();
frame = create_mncc(MNCC_FRAME_DROP, 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 = 0;
}
}
@@ -200,14 +186,14 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m
gsm_trace_header(p_m_mISDNport, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT);
end_trace();
resp = create_mncc(MNCC_RETRIEVE_CNF, p_m_g_callref);
- 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);
/* enable audio */
if (!p_m_g_tch_connected) { /* it should be true */
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;
}
}
@@ -242,7 +228,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
add_trace("cause", "value", "%d", mncc->cause.value);
add_trace("reason", NULL, "callref already in use");
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);
return;
@@ -263,7 +249,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
add_trace("cause", "value", "%d", mncc->cause.value);
add_trace("reason", NULL, "port is blocked");
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);
return;
@@ -335,7 +321,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
add_trace("cause", "value", "%d", mncc->cause.value);
add_trace("reason", NULL, "no channel");
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);
return;
@@ -369,7 +355,7 @@ void Pgsm_bs::setup_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);
/* send call proceeding */
gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
@@ -384,7 +370,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
add_trace("progress", "descr", "%d", proceeding->progress.descr);
}
end_trace();
- send_and_free_mncc(p_m_g_instance, proceeding->msg_type, proceeding);
+ send_and_free_mncc(p_m_g_lcr_gsm, proceeding->msg_type, proceeding);
new_state(PORT_STATE_IN_PROCEEDING);
@@ -392,7 +378,7 @@ void Pgsm_bs::setup_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;
}
@@ -413,7 +399,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
/*
* BSC sends message to port
*/
-static int message_bsc(struct gsm_network *net, int msg_type, void *arg)
+int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg)
{
struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
unsigned int callref = mncc->callref;
@@ -482,7 +468,7 @@ static int message_bsc(struct gsm_network *net, int msg_type, void *arg)
add_trace("cause", "location", "%d", rej->cause.location);
add_trace("cause", "value", "%d", rej->cause.value);
end_trace();
- send_and_free_mncc(gsm->network, rej->msg_type, rej);
+ send_and_free_mncc(lcr_gsm, rej->msg_type, rej);
return 0;
}
/* creating port object, transparent until setup with hdlc */
@@ -565,12 +551,12 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame
memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
/* no GSM MNCC connection */
- if (gsm->mncc_lfd.fd < 0) {
+ if (p_m_g_lcr_gsm->mncc_lfd.fd < 0) {
gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
add_trace("failure", NULL, "No MNCC connection.");
end_trace();
message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
- message->param.disconnectinfo.cause = 27; // temp. unavail.
+ message->param.disconnectinfo.cause = 41; // temp. failure.
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
@@ -762,7 +748,7 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame
//todo
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_SETUP);
@@ -796,215 +782,38 @@ int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parame
int gsm_bs_exit(int rc)
{
- gsm->network = NULL;
-
- return(rc);
-}
-
-extern "C" {
-
-static int mncc_q_enqueue(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 (!gsm->mncc_q_hd && !gsm->mncc_q_tail) {
- /* the list head and tail both point to the new qe */
- gsm->mncc_q_hd = gsm->mncc_q_tail = qe;
- } else {
- /* append to tail of list */
- gsm->mncc_q_tail->next = qe;
- gsm->mncc_q_tail = qe;
- }
-
- gsm->mncc_lfd.when |= LCR_FD_WRITE;
-
- return 0;
-}
-
-static struct mncc_q_entry *mncc_q_dequeue(void)
-{
- struct mncc_q_entry *qe = gsm->mncc_q_hd;
- if (!qe)
- return NULL;
-
- /* dequeue the successfully sent message */
- gsm->mncc_q_hd = qe->next;
- if (!qe)
- return NULL;
- if (qe == gsm->mncc_q_tail)
- gsm->mncc_q_tail = NULL;
-
- return qe;
-}
-
-/* routine called by LCR code if it wants to send a message to OpenBSC */
-int mncc_send(struct gsm_network *instance, 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((struct gsm_mncc *)data, len);
-}
-
-} // extern "C"
-
-/* close MNCC socket */
-static int mncc_fd_close(struct lcr_fd *lfd)
-{
- class Port *port;
- class Pgsm_bs *pgsm_bs = 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_GSM_MASK) == PORT_CLASS_GSM_BS) {
- pgsm_bs = (class Pgsm_bs *)port;
- message = message_create(pgsm_bs->p_serial, ACTIVE_EPOINT(pgsm_bs->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_bs->new_state(PORT_STATE_RELEASE);
- trigger_work(&pgsm_bs->p_m_g_delete);
+ /* free gsm instance */
+ if (gsm_bs) {
+ if (gsm_bs->mncc_lfd.fd > -1) {
+ close(gsm_bs->mncc_lfd.fd);
+ unregister_fd(&gsm_bs->mncc_lfd);
}
- port = port->next;
- }
-
- /* flush the queue */
- while (mncc_q_dequeue())
- ;
-
- /* start the re-connect timer */
- schedule_timer(&gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
-
- generate_dtmf();
-
- return 0;
-}
-
-/* read from OpenBSC via MNCC socket */
-static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
-{
- struct mncc_q_entry *qe, *qe2;
- int rc;
-
- while (1) {
- qe = 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(lfd);
- if (rc < 0)
- return rc;
- if (rc < (int)qe->len)
- return -1;
- /* dequeue the successfully sent message */
- qe2 = mncc_q_dequeue();
- 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)
-{
- 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(lfd);
- if (rc < 0)
- return rc;
-
- /* Hand the MNCC message into LCR */
- return message_bsc(NULL, mncc_prim->msg_type, mncc_prim);
-}
-/* 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 *instance, int idx)
-{
- int rc = 0;
-
- if (what & LCR_FD_READ)
- rc = mncc_fd_read(lfd, instance, idx);
- if (rc < 0)
- return rc;
-
- if (what & LCR_FD_WRITE)
- rc = mncc_fd_write(lfd, instance, idx);
-
- return rc;
-}
-
-static int socket_retry_cb(struct lcr_timer *timer, void *instance, int index)
-{
- int fd, rc;
-
- fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
- if (fd < 0) {
- PERROR("Cannot create SEQPACKET socket, giving up!\n");
- return fd;
+ del_timer(&gsm_bs->socket_retry);
+ free(gsm_bs);
+ gsm_bs = NULL;
}
- rc = connect(fd, (struct sockaddr *) &gsm->sun,
- sizeof(gsm->sun));
- if (rc < 0) {
- PERROR("Could not connect to MNCC socket, "
- "retrying in %u seconds\n", SOCKET_RETRY_TIMER);
- close(fd);
- schedule_timer(&gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
- } else {
- PDEBUG(DEBUG_GSM, "Connected to MNCC socket!\n");
- gsm->mncc_lfd.fd = fd;
- register_fd(&gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, NULL, 0);
- }
- return 0;
+ return(rc);
}
int gsm_bs_init(void)
{
- gsm->sun.sun_family = AF_UNIX;
- SCPY(gsm->sun.sun_path, "/tmp/bsc_mncc");
+ /* create gsm instance */
+ gsm_bs = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
- memset(&gsm->socket_retry, 0, sizeof(gsm->socket_retry));
- add_timer(&gsm->socket_retry, socket_retry_cb, NULL, 0);
+ gsm_bs->type = LCR_GSM_TYPE_NETWORK;
+ gsm_bs->sun.sun_family = AF_UNIX;
+ SCPY(gsm_bs->sun.sun_path, "/tmp/bsc_mncc");
+
+ memset(&gsm_bs->socket_retry, 0, sizeof(gsm_bs->socket_retry));
+ add_timer(&gsm_bs->socket_retry, mncc_socket_retry_cb, gsm_bs, 0);
/* do the initial connect */
- socket_retry_cb(&gsm->socket_retry, NULL, 0);
+ mncc_socket_retry_cb(&gsm_bs->socket_retry, gsm_bs, 0);
- /* dummy instance */
- gsm->network = (void *)1;
+ generate_dtmf();
return 0;
}