X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=gsm_bs.cpp;h=d281bc962d67747311c680d7de9c9040b788feda;hp=710c2370c4bf690c64448a5078af5308c33bd5ca;hb=41a0668da1dbd5644a50036eaa26c8ba85201ffd;hpb=d40eedaf166b92a428c01088ce05079f93d590bf diff --git a/gsm_bs.cpp b/gsm_bs.cpp index 710c237..d281bc9 100644 --- a/gsm_bs.cpp +++ b/gsm_bs.cpp @@ -10,21 +10,9 @@ \*****************************************************************************/ #include "main.h" -#include "config.h" +#include "mncc.h" -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -extern "C" { -#include -#include - -#include -#include - -#include -#include -} +struct lcr_gsm *gsm_bs = NULL; /* * DTMF stuff @@ -59,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; @@ -91,8 +79,9 @@ void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct add_trace("keypad", NULL, "%c", mncc->keypad); end_trace(); 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 */ @@ -140,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; @@ -165,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; } } @@ -197,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; } } @@ -239,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; @@ -260,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; @@ -332,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; @@ -364,9 +353,10 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref); mode->lchan_mode = 0x01; /* GSM V1 */ + mode->lchan_type = 0x02; 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); @@ -381,7 +371,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); @@ -389,7 +379,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; } @@ -410,7 +400,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; @@ -479,7 +469,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 */ @@ -561,6 +551,20 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo)); memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo)); + /* no GSM MNCC connection */ + 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 = 41; // temp. failure. + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + new_state(PORT_STATE_RELEASE); + trigger_work(&p_m_g_delete); + return; + } + /* no number */ if (!p_dialinginfo.id[0]) { gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); @@ -745,7 +749,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); @@ -779,184 +783,38 @@ int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parame int gsm_bs_exit(int rc) { -#if 0 /* free gsm instance */ - if (gsm) { - /* shutdown network */ - if (gsm->network) - bsc_shutdown_net((struct gsm_network *)gsm->network); - /* free network */ -// if (gsm->network) { -// free((struct gsm_network *)gsm->network); /* TBD */ -// } - } -#endif - 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); + if (gsm_bs) { + if (gsm_bs->mncc_lfd.fd > -1) { + close(gsm_bs->mncc_lfd.fd); + unregister_fd(&gsm_bs->mncc_lfd); + } - /* 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; + del_timer(&gsm_bs->socket_retry); + free(gsm_bs); + gsm_bs = NULL; } - 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 = 33; - break; - default: - len = sizeof(struct gsm_mncc); - break; - } - - return mncc_q_enqueue((struct gsm_mncc *)data, len); + return(rc); } -} // extern "C" - -/* close MNCC socket */ -static int mncc_fd_close(struct lcr_fd *lfd) +int gsm_bs_init(void) { - close(lfd->fd); - unregister_fd(lfd); - lfd->fd = -1; + /* create gsm instance */ + gsm_bs = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm)); - /* flush the queue */ - while (mncc_q_dequeue()) - ; + gsm_bs->type = LCR_GSM_TYPE_NETWORK; + gsm_bs->sun.sun_family = AF_UNIX; + SCPY(gsm_bs->sun.sun_path, "/tmp/bsc_mncc"); - /* FIXME: free all the calls that were running through the MNCC interface */ + memset(&gsm_bs->socket_retry, 0, sizeof(gsm_bs->socket_retry)); + add_timer(&gsm_bs->socket_retry, mncc_socket_retry_cb, gsm_bs, 0); - /* FIXME: start a re-connect timer */ + /* do the initial connect */ + mncc_socket_retry_cb(&gsm_bs->socket_retry, gsm_bs, 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 < 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; -} - -int gsm_bs_init(void) -{ - struct sockaddr_un sun; - int rc; - - rc = socket(PF_UNIX, SOCK_SEQPACKET, 0); - if (rc < 0) - return rc; - - gsm->mncc_lfd.fd = rc; - - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, "/tmp/bsc_mncc"); - rc = connect(rc, (struct sockaddr *)&sun, sizeof(sun)); - if (rc < 0) - return rc; - - rc = register_fd(&gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, NULL, 0); - - return rc; -}