[GSM] Replaced strcpy by required macro name.
[lcr.git] / gsm_bs.cpp
index 710c237..e25732a 100644 (file)
@@ -26,6 +26,8 @@ extern "C" {
 #include <openbsc/trau_frame.h>
 }
 
+#define SOCKET_RETRY_TIMER     5
+
 /*
  * DTMF stuff
  */
@@ -91,6 +93,7 @@ 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);
 
@@ -561,6 +564,20 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame
        memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
        memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
 
+       /* no GSM MNCC connection */
+       if (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.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);
@@ -815,6 +832,7 @@ static int mncc_q_enqueue(struct gsm_mncc *mncc, unsigned int len)
        } else {
                /* append to tail of list */
                gsm->mncc_q_tail->next = qe;
+               gsm->mncc_q_tail = qe;
        }
 
        gsm->mncc_lfd.when |= LCR_FD_WRITE;
@@ -846,7 +864,7 @@ int mncc_send(struct gsm_network *instance, int msg_type, void *data)
        /* FIXME: the caller should provide this */
        switch (msg_type) {
        case GSM_TCHF_FRAME:
-               len = 33;
+               len = sizeof(struct gsm_data_frame) + 33;
                break;
        default:
                len = sizeof(struct gsm_mncc);
@@ -861,17 +879,36 @@ int mncc_send(struct gsm_network *instance, int msg_type, void *data)
 /* 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);
+               }
+               port = port->next;
+       }
+
        /* flush the queue */
        while (mncc_q_dequeue())
                ;
 
-       /* FIXME: free all the calls that were running through the MNCC interface */
-
-       /* FIXME: start a re-connect timer */
+       /* start the re-connect timer */
+       schedule_timer(&gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
 
        generate_dtmf();
 
@@ -895,7 +932,7 @@ static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
                        return mncc_fd_close(lfd);
                if (rc < 0)
                        return rc;
-               if (rc < qe->len)
+               if (rc < (int)qe->len)
                        return -1;
                /* dequeue the successfully sent message */
                qe2 = mncc_q_dequeue();
@@ -939,24 +976,42 @@ static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *instance, int
        return rc;
 }
 
-int gsm_bs_init(void)
+static int socket_retry_cb(struct lcr_timer *timer, void *instance, int index)
 {
-       struct sockaddr_un sun;
-       int rc;
+       int fd, rc;
 
-       rc = socket(PF_UNIX, SOCK_SEQPACKET, 0);
-       if (rc < 0)
-               return rc;
+       fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
+       if (fd < 0) {
+               PERROR("Cannot create SEQPACKET socket, giving up!\n");
+               return fd;
+       }
 
-       gsm->mncc_lfd.fd = rc;
+       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);
+       }
 
-       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;
+       return 0;
+}
+
+int gsm_bs_init(void)
+{
+       gsm->sun.sun_family = AF_UNIX;
+       SCPY(gsm->sun.sun_path, "/tmp/bsc_mncc");
 
-       rc = register_fd(&gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, NULL, 0);
+       memset(&gsm->socket_retry, 0, sizeof(gsm->socket_retry));
+       add_timer(&gsm->socket_retry, socket_retry_cb, NULL, 0);
 
-       return rc;
+       /* do the initial connect */
+       socket_retry_cb(&gsm->socket_retry, NULL, 0);
+
+       return 0;
 }