+ 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;
+}
+
+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);