GSM: A breakdown of MNCC socket causes all calls to be released correctly
[lcr.git] / gsm.cpp
diff --git a/gsm.cpp b/gsm.cpp
index 50ca2ea..5ed0f89 100644 (file)
--- a/gsm.cpp
+++ b/gsm.cpp
@@ -412,6 +412,11 @@ bfi:
 /* send traffic to gsm */
 int Pgsm::bridge_rx(unsigned char *data, int len)
 {
+       int ret;
+
+       if ((ret = Port::bridge_rx(data, len)))
+               return ret;
+
        if (p_tone_name[0])
                return -EINVAL;
 
@@ -1275,11 +1280,11 @@ static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
        /* 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) {
+               if ((port->p_type & PORT_CLASS_MASK) == PORT_CLASS_GSM) {
                        pgsm = (class Pgsm *)port;
                        if (pgsm->p_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.cause = 41; // temp. fail.
                                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                                message_put(message);
                                pgsm->new_state(PORT_STATE_RELEASE);
@@ -1334,6 +1339,7 @@ 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;
+       struct gsm_mncc_hello *hello = (struct gsm_mncc_hello *) buf;
 
        memset(buf, 0, sizeof(buf));
        rc = recv(lfd->fd, buf, sizeof(buf), 0);
@@ -1342,6 +1348,45 @@ static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
        if (rc < 0)
                return rc;
 
+       /* TODO: size check? */
+       switch (mncc_prim->msg_type) {
+       case MNCC_SOCKET_HELLO:
+               if (hello->version != MNCC_SOCK_VERSION) {
+                       PERROR("MNCC version different. BSC version is %u\n", hello->version);
+                       mncc_fd_close(lcr_gsm, lfd);
+                       return 0;
+               }
+               if (hello->mncc_size != sizeof(struct gsm_mncc)) {
+                       PERROR("MNCC gsm_mncc size differs: %u %u\n",
+                               hello->mncc_size, sizeof(struct gsm_mncc));
+                       mncc_fd_close(lcr_gsm, lfd);
+                       return 0;
+               }
+               if (hello->data_frame_size != sizeof(struct gsm_data_frame)) {
+                       PERROR("MNCC gsm_mncc size differs: %u %u\n",
+                               hello->data_frame_size, sizeof(struct gsm_data_frame));
+                       mncc_fd_close(lcr_gsm, lfd);
+                       return 0;
+               }
+
+#define CHECK_OFFSET(hello, field, lcr_gsm, lfd)       \
+               if (hello->field ##_offset != __builtin_offsetof(struct gsm_mncc, field)) {     \
+                       PERROR("MNCC gsm_mncc offset of %s is %u %u\n",                         \
+                               #field, hello->field ##_offset,                                 \
+                               __builtin_offsetof(struct gsm_mncc, field));                    \
+                       mncc_fd_close(lcr_gsm, lfd);                                            \
+                       return 0;                                                               \
+               }
+
+               CHECK_OFFSET(hello, called, lcr_gsm, lfd);
+               CHECK_OFFSET(hello, signal, lcr_gsm, lfd);
+               CHECK_OFFSET(hello, emergency, lcr_gsm, lfd);
+               CHECK_OFFSET(hello, lchan_type, lcr_gsm, lfd);
+#undef CHECK_OFFSET
+
+               break;
+       }
+
        /* Hand the MNCC message into LCR */
        switch (lcr_gsm->type) {
 #ifdef WITH_GSM_BS