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