src: use new libosmogsm and include/osmocom/[gsm|core] path to headers
[osmocom-bb.git] / src / host / layer23 / src / misc / app_ccch_scan.c
index 237b990..913ceca 100644 (file)
 #include <errno.h>
 #include <stdio.h>
 
-#include <osmocore/msgb.h>
-#include <osmocore/rsl.h>
-#include <osmocore/tlv.h>
-#include <osmocore/gsm48_ie.h>
-#include <osmocore/protocol/gsm_04_08.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm48_ie.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
 
 #include <osmocom/bb/common/logging.h>
 #include <osmocom/bb/common/lapdm.h>
@@ -36,6 +38,7 @@
 #include <osmocom/bb/misc/layer3.h>
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/l23_app.h>
 
 static struct {
        int has_si1;
@@ -54,35 +57,33 @@ static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
        /* GSM 05.02 ยง6.3.1.3 Mapping of BCCH data */
        switch (si_hdr->system_information) {
        case GSM48_MT_RR_SYSINFO_1:
-               fprintf(stderr, "\tSI1");
 #ifdef BCCH_TC_CHECK
                if (tc != 0)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI1 on the wrong TC: %d\n", tc);
 #endif
                if (!app_state.has_si1) {
                        struct gsm48_system_information_type_1 *si1 =
                                (struct gsm48_system_information_type_1 *)data;
 
-                       gsm48_decode_freq_list(&app_state.cell_arfcns,
+                       gsm48_decode_freq_list(app_state.cell_arfcns,
                                               si1->cell_channel_description,
                                               sizeof(si1->cell_channel_description),
                                               0xff, 0x01);
 
                        app_state.has_si1 = 1;
+                       LOGP(DRR, LOGL_ERROR, "SI1 received.\n");
                }
                break;
        case GSM48_MT_RR_SYSINFO_2:
-               fprintf(stderr, "\tSI2");
 #ifdef BCCH_TC_CHECK
                if (tc != 1)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI2 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_3:
-               fprintf(stderr, "\tSI3");
 #ifdef BCCH_TC_CHECK
                if (tc != 2 && tc != 6)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI3 on the wrong TC: %d\n", tc);
 #endif
                if (app_state.ccch_mode == CCCH_MODE_NONE) {
                        struct gsm48_system_information_type_3 *si3 =
@@ -97,118 +98,83 @@ static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
                }
                break;
        case GSM48_MT_RR_SYSINFO_4:
-               fprintf(stderr, "\tSI4");
 #ifdef BCCH_TC_CHECK
                if (tc != 3 && tc != 7)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI4 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_5:
-               fprintf(stderr, "\tSI5");
                break;
        case GSM48_MT_RR_SYSINFO_6:
-               fprintf(stderr, "\tSI6");
                break;
        case GSM48_MT_RR_SYSINFO_7:
-               fprintf(stderr, "\tSI7");
 #ifdef BCCH_TC_CHECK
                if (tc != 7)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI7 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_8:
-               fprintf(stderr, "\tSI8");
 #ifdef BCCH_TC_CHECK
                if (tc != 3)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI8 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_9:
-               fprintf(stderr, "\tSI9");
 #ifdef BCCH_TC_CHECK
                if (tc != 4)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI9 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_13:
-               fprintf(stderr, "\tSI13");
 #ifdef BCCH_TC_CHECK
                if (tc != 4 && tc != 0)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI13 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_16:
-               fprintf(stderr, "\tSI16");
 #ifdef BCCH_TC_CHECK
                if (tc != 6)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI16 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_17:
-               fprintf(stderr, "\tSI17");
 #ifdef BCCH_TC_CHECK
                if (tc != 2)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI17 on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_2bis:
-               fprintf(stderr, "\tSI2bis");
 #ifdef BCCH_TC_CHECK
                if (tc != 5)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI2bis on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_2ter:
-               fprintf(stderr, "\tSI2ter");
 #ifdef BCCH_TC_CHECK
                if (tc != 5 && tc != 4)
-                       fprintf(stderr, " on wrong TC");
+                       LOGP(DRR, LOGL_ERROR, "SI2ter on the wrong TC: %d\n", tc);
 #endif
                break;
        case GSM48_MT_RR_SYSINFO_5bis:
-               fprintf(stderr, "\tSI5bis");
                break;
        case GSM48_MT_RR_SYSINFO_5ter:
-               fprintf(stderr, "\tSI5ter");
                break;
        default:
                fprintf(stderr, "\tUnknown SI");
                break;
        };
-
-       fprintf(stderr, "\n");
 }
 
 
-/* send location updating request * (as part of RSLms EST IND /
-   LAPDm SABME) */
-static int gsm48_tx_loc_upd_req(struct osmocom_ms *ms, uint8_t chan_nr)
-{
-       struct msgb *msg = msgb_alloc_headroom(256, 16, "loc_upd_req");
-       struct gsm48_hdr *gh;
-       struct gsm48_loc_upd_req *lu_r;
-
-       DEBUGP(DMM, "chan_nr=%u\n", chan_nr);
-
-       msg->l3h = msgb_put(msg, sizeof(*gh));
-       gh = (struct gsm48_hdr *) msg->l3h;
-       gh->proto_discr = GSM48_PDISC_MM;
-       gh->msg_type = GSM48_MT_MM_LOC_UPD_REQUEST;
-       lu_r = (struct gsm48_loc_upd_req *) msgb_put(msg, sizeof(*lu_r));
-       lu_r->type = GSM48_LUPD_IMSI_ATT;
-       lu_r->key_seq = 0;
-       /* FIXME: set LAI and CM1 */
-       /* FIXME: set MI */
-       lu_r->mi_len = 0;
-
-       return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, chan_nr, 0, msg);
-}
-
+/**
+ * This method used to send a l1ctl_tx_dm_est_req_h0 or
+ * a l1ctl_tx_dm_est_req_h1 to the layer1 to follow this
+ * assignment. The code has been removed.
+ */
 static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
 {
        struct gsm48_imm_ass *ia = msgb_l3(msg);
        uint8_t ch_type, ch_subch, ch_ts;
-       int rv;
 
        /* Discard packet TBF assignement */
        if (ia->page_mode & 0xf0)
@@ -224,15 +190,11 @@ static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
 
                arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
 
-               DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+               LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
                        "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
                        ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
                        ia->chan_desc.h0.tsc);
 
-               /* request L1 to go to dedicated mode on assigned channel */
-               rv = l1ctl_tx_dm_est_req_h0(ms,
-                       arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,
-                       GSM48_CMODE_SIGN);
        } else {
                /* Hopping */
                uint8_t maio, hsn, ma_len;
@@ -242,7 +204,7 @@ static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
                hsn = ia->chan_desc.h1.hsn;
                maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
 
-               DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+               LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
                        "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
                        ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
                        ia->chan_desc.h1.tsc);
@@ -259,19 +221,161 @@ static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
                                j++;
                        }
                }
+       }
+
+       LOGPC(DRR, LOGL_NOTICE, "\n");
+       return 0;
+}
+
+static const char *pag_print_mode(int mode)
+{
+       switch (mode) {
+       case 0:
+               return "Normal paging";
+       case 1:
+               return "Extended paging";
+       case 2:
+               return "Paging reorganization";
+       case 3:
+               return "Same as before";
+       default:
+               return "invalid";
+       }
+}
+
+static char *chan_need(int need)
+{
+       switch (need) {
+       case 0:
+               return "any";
+       case 1:
+               return "sdch";
+       case 2:
+               return "tch/f";
+       case 3:
+               return "tch/h";
+       default:
+               return "invalid";
+       }
+}
+
+static char *mi_type_to_string(int type)
+{
+       switch (type) {
+       case GSM_MI_TYPE_NONE:
+               return "none";
+       case GSM_MI_TYPE_IMSI:
+               return "imsi";
+       case GSM_MI_TYPE_IMEI:
+               return "imei";
+       case GSM_MI_TYPE_IMEISV:
+               return "imeisv";
+       case GSM_MI_TYPE_TMSI:
+               return "tmsi";
+       default:
+               return "invalid";
+       }
+}
+
+/**
+ * This can contain two MIs. The size checking is a bit of a mess.
+ */
+static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms)
+{
+       struct gsm48_paging1 *pag;
+       int len1, len2, mi_type, tag;
+       char mi_string[GSM48_MI_SIZE];
+
+       /* is there enough room for the header + LV? */
+       if (msgb_l3len(msg) < sizeof(*pag) + 2) {
+               LOGP(DRR, LOGL_ERROR, "PagingRequest is too short.\n");
+               return -1;
+       }
+
+       pag = msgb_l3(msg);
+       len1 = pag->data[0];
+       mi_type = pag->data[1] & GSM_MI_TYPE_MASK;
+
+       if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1) {
+               LOGP(DRR, LOGL_ERROR, "PagingRequest with wrong MI\n");
+               return -1;
+       }
+
+       if (mi_type != GSM_MI_TYPE_NONE) {
+               gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[1], len1);
+               LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to %s M(%s) \n",
+                    pag_print_mode(pag->pag_mode),
+                    chan_need(pag->cneed1),
+                    mi_type_to_string(mi_type),
+                    mi_string);
+       }
+
+       /* check if we have a MI type in here */
+       if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3)
+               return 0;
+
+       tag = pag->data[2 + len1 + 0];
+       len2 = pag->data[2 + len1 + 1];
+       mi_type = pag->data[2 + len1 + 2] & GSM_MI_TYPE_MASK;
+       if (tag == GSM48_IE_MOBILE_ID && mi_type != GSM_MI_TYPE_NONE) {
+               if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3 + len2) {
+                       LOGP(DRR, LOGL_ERROR, "Optional MI does not fit here.\n");
+                       return -1;
+               }
 
-               /* request L1 to go to dedicated mode on assigned channel */
-               rv = l1ctl_tx_dm_est_req_h1(ms,
-                       maio, hsn, ma, ma_len,
-                       ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,
-                       GSM48_CMODE_SIGN);
+               gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2 + len1 + 2], len2);
+               LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to %s M(%s) \n",
+                    pag_print_mode(pag->pag_mode),
+                    chan_need(pag->cneed2),
+                    mi_type_to_string(mi_type),
+                    mi_string);
        }
+       return 0;
+}
+
+static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
+{
+       struct gsm48_paging2 *pag;
+       int tag, len, mi_type;
+       char mi_string[GSM48_MI_SIZE];
+
+       if (msgb_l3len(msg) < sizeof(*pag)) {
+               LOGP(DRR, LOGL_ERROR, "Paging2 message is too small.\n");
+               return -1;
+       }
+
+       pag = msgb_l3(msg);
+       LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
+                    pag_print_mode(pag->pag_mode),
+                    chan_need(pag->cneed1), pag->tmsi1);
+       LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
+                    pag_print_mode(pag->pag_mode),
+                    chan_need(pag->cneed1), pag->tmsi2);
+
+       /* no optional element */
+       if (msgb_l3len(msg) < sizeof(*pag) + 3)
+               return 0;
+
+       tag = pag->data[0];
+       len = pag->data[1];
+       mi_type = pag->data[2] & GSM_MI_TYPE_MASK;
 
-       DEBUGPC(DRR, "\n");
+       if (tag != GSM48_IE_MOBILE_ID)
+               return 0;
+
+       if (msgb_l3len(msg) < sizeof(*pag) + 3 + len) {
+               LOGP(DRR, LOGL_ERROR, "Optional MI does not fit in here\n");
+               return -1;
+       }
 
-       rv = gsm48_tx_loc_upd_req(ms, ia->chan_desc.chan_nr);
+       gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2], len);
+       LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to %s M(%s) \n",
+            pag_print_mode(pag->pag_mode),
+            "n/a ",
+            mi_type_to_string(mi_type),
+            mi_string);
 
-       return rv;
+       return 0;
 }
 
 int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
@@ -284,12 +388,22 @@ int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
 
        switch (sih->system_information) {
        case GSM48_MT_RR_PAG_REQ_1:
+               gsm48_rx_paging_p1(msg, ms);
+               break;
        case GSM48_MT_RR_PAG_REQ_2:
+               gsm48_rx_paging_p2(msg, ms);
+               break;
        case GSM48_MT_RR_PAG_REQ_3:
-               /* FIXME: implement decoding of paging request */
+               LOGP(DRR, LOGL_ERROR, "PAGING of type 3 is not implemented.\n");
                break;
        case GSM48_MT_RR_IMM_ASS:
-               rc = gsm48_rx_imm_ass(msg, ms);
+               gsm48_rx_imm_ass(msg, ms);
+               break;
+       case GSM48_MT_RR_NOTIF_NCH:
+               /* notification for voice call groups and such */
+               break;
+       case 0x07:
+               /* wireshark know that this is SI2 quater and for 3G interop */
                break;
        default:
                LOGP(DRR, LOGL_NOTICE, "unknown PCH/AGCH type 0x%02x\n",
@@ -327,3 +441,41 @@ void layer3_app_reset(void)
 
        memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns));
 }
+
+static int signal_cb(unsigned int subsys, unsigned int signal,
+                    void *handler_data, void *signal_data)
+{
+       struct osmocom_ms *ms;
+
+       if (subsys != SS_L1CTL)
+               return 0;
+
+       switch (signal) {
+       case S_L1CTL_RESET:
+               ms = signal_data;
+               layer3_app_reset();
+               return l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
+                                        L1CTL_FBSB_F_FB01SB, 100, 0,
+                                        CCCH_MODE_NONE);
+               break;
+       }
+       return 0;
+}
+
+
+int l23_app_init(struct osmocom_ms *ms)
+{
+       register_signal_handler(SS_L1CTL, &signal_cb, NULL);
+       l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
+       return layer3_init(ms);
+}
+
+static struct l23_app_info info = {
+       .copyright      = "Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>\n",
+       .contribution   = "Contributions by Holger Hans Peter Freyther\n",
+};
+
+struct l23_app_info *l23_app_info()
+{
+       return &info;
+}