[layer23] CM service is now accepted when ciphering has started
[osmocom-bb.git] / src / host / layer23 / src / mobile / gsm48_rr.c
index 5c39d77..e2418cc 100644 (file)
@@ -45,7 +45,7 @@
  * When enabled, the starting time will be set by given frames in the future.
  * If a starting time is given by the network, this time is ignored.
  */
-//#define TEST_STARTING_TIMER 40
+//#define TEST_STARTING_TIMER 140
 
 /* Testing if frequency modification works correctly "after time".
  *
@@ -106,6 +106,17 @@ int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
        return 0;
 }
 
+int gsm48_encode_lai(struct gsm48_loc_area_id *lai, uint16_t mcc,
+       uint16_t mnc, uint16_t lac)
+{
+       lai->digits[0] = (mcc >> 8) | (mcc & 0xf0);
+       lai->digits[1] = (mcc & 0x0f) | (mnc << 4);
+       lai->digits[2] = (mnc >> 8) | (mnc & 0xf0);
+       lai->lac = htons(lac);
+
+       return 0;
+}
+
 static int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc, 
        uint16_t *arfcn)
 {
@@ -789,6 +800,7 @@ static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr)
        struct gsm_settings *set = &ms->settings;
        struct msgb *nmsg;
        struct gsm48_hdr *gh;
+       struct gsm48_rr_hdr *nrrh;
        uint8_t buf[11], *tlv;
 
        LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMPLETE (cr %d)\n", cr);
@@ -804,17 +816,28 @@ static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr)
        /* MI */
        if (cr) {
                gsm48_generate_mid_from_imsi(buf, set->imeisv);
+               /* alter MI type */
+               buf[2] = (buf[2] & ~GSM_MI_TYPE_MASK) | GSM_MI_TYPE_IMEISV;
                tlv = msgb_put(nmsg, 2 + buf[1]);
                memcpy(tlv, buf, 2 + buf[1]);
        }
 
-       return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+       gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+
+       /* send RR_SYNC_IND(ciphering) */
+       nmsg = gsm48_rr_msgb_alloc(GSM48_RR_SYNC_IND);
+       if (!nmsg)
+               return -ENOMEM;
+       nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+       nrrh->cause = RR_SYNC_CAUSE_CIPHERING;
+       return gsm48_rr_upmsg(ms, nmsg);
 }
 
 /* receive ciphering mode command */
 static int gsm48_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm48_rrlayer *rr = &ms->rrlayer;
+       struct gsm_subscriber *subscr = &ms->subscr;
        struct gsm_support *sup = &ms->support;
        struct gsm48_hdr *gh = msgb_l3(msg);
        struct gsm48_cip_mode_cmd *cm = (struct gsm48_cip_mode_cmd *)gh->data;
@@ -834,36 +857,48 @@ static int gsm48_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg)
        /* cipher mode response */
        cr = cm->cr;
 
-       if (sc)
-               LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMMAND (sc=%u, cr=%u)",
+       if (!sc)
+               LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMMAND (sc=%u, cr=%u)\n",
                        sc, cr);
        else
                LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMMAND (sc=%u, "
-                       "algo=A5/%d cr=%u)", sc, alg_id + 1, cr);
+                       "algo=A5/%d cr=%u)\n", sc, alg_id + 1, cr);
 
        /* 3.4.7.2 */
        if (rr->cipher_on && sc) {
-               LOGP(DRR, LOGL_NOTICE, "chiphering already applied.\n");
+               LOGP(DRR, LOGL_NOTICE, "chiphering already applied\n");
                return gsm48_rr_tx_rr_status(ms,
                        GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
        }
 
        /* check if we actually support this cipher */
-       if ((alg_id == GSM_CIPHER_A5_1 && !sup->a5_1)
-        || (alg_id == GSM_CIPHER_A5_2 && !sup->a5_2)
-        || (alg_id == GSM_CIPHER_A5_3 && !sup->a5_3)
-        || (alg_id == GSM_CIPHER_A5_4 && !sup->a5_4)
-        || (alg_id == GSM_CIPHER_A5_5 && !sup->a5_5)
-        || (alg_id == GSM_CIPHER_A5_6 && !sup->a5_6)
-        || (alg_id == GSM_CIPHER_A5_7 && !sup->a5_7))
+       if (sc && ((alg_id == GSM_CIPHER_A5_1 && !sup->a5_1)
+               || (alg_id == GSM_CIPHER_A5_2 && !sup->a5_2)
+               || (alg_id == GSM_CIPHER_A5_3 && !sup->a5_3)
+               || (alg_id == GSM_CIPHER_A5_4 && !sup->a5_4)
+               || (alg_id == GSM_CIPHER_A5_5 && !sup->a5_5)
+               || (alg_id == GSM_CIPHER_A5_6 && !sup->a5_6)
+               || (alg_id == GSM_CIPHER_A5_7 && !sup->a5_7))) {
+               LOGP(DRR, LOGL_NOTICE, "algo not supported\n");
                return gsm48_rr_tx_rr_status(ms,
                        GSM48_RR_CAUSE_CHAN_MODE_UNACCT);
+       }
+
+       /* check if we have no key */
+       if (sc && subscr->key_seq == 7) {
+               LOGP(DRR, LOGL_NOTICE, "no key available\n");
+               return gsm48_rr_tx_rr_status(ms,
+                       GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+       }
 
        /* change to ciphering */
-#warning FIXME: cyphering command
        rr->cipher_on = sc, rr->cipher_type = alg_id;
+       if (sc)
+               l1ctl_tx_crypto_req(ms, alg_id + 1, subscr->key, 8);
+       else
+               l1ctl_tx_crypto_req(ms, 0, NULL, 0);
 
-       /* response */
+       /* response (using the new mode) */
        return gsm48_rr_tx_cip_mode_cpl(ms, cr);
 }
 
@@ -994,7 +1029,7 @@ int gsm48_rr_enc_cm2(struct osmocom_ms *ms, struct gsm48_classmark2 *cm)
                cm->pwr_lev = sup->pwr_lev_1800;
        else
                cm->pwr_lev = sup->pwr_lev_900;
-       cm->a5_1 = sup->a5_1;
+       cm->a5_1 = !sup->a5_1;
        cm->es_ind = sup->es_ind;
        cm->rev_lev = sup->rev_lev;
        cm->fc = (sup->r_gsm || sup->e_gsm);
@@ -2156,6 +2191,7 @@ static int gsm48_rr_chan2cause[4] = {
 /* given LV of mobile identity is checked agains ms */
 static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi)
 {
+       struct gsm322_cellsel *cs = &ms->cellsel;
        char imsi[16];
        uint32_t tmsi;
        uint8_t mi_type;
@@ -2169,7 +2205,9 @@ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi)
                        return 0;
                memcpy(&tmsi, mi+2, 4);
                if (ms->subscr.tmsi == ntohl(tmsi)
-                && ms->subscr.tmsi_valid) {
+                && ms->subscr.mcc == cs->sel_mcc
+                && ms->subscr.mnc == cs->sel_mnc
+                && ms->subscr.lac == cs->sel_lac) {
                        LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n",
                                ntohl(tmsi));
 
@@ -2284,7 +2322,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg)
        chan_2 = pa->cneed2;
        /* first MI */
        if (ms->subscr.tmsi == ntohl(pa->tmsi1)
-        && ms->subscr.tmsi_valid) {
+        && ms->subscr.mcc == cs->sel_mcc
+        && ms->subscr.mnc == cs->sel_mnc
+        && ms->subscr.lac == cs->sel_lac) {
                LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1));
                return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
        } else
@@ -2292,7 +2332,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg)
                        ntohl(pa->tmsi1));
        /* second MI */
        if (ms->subscr.tmsi == ntohl(pa->tmsi2)
-        && ms->subscr.tmsi_valid) {
+        && ms->subscr.mcc == cs->sel_mcc
+        && ms->subscr.mnc == cs->sel_mnc
+        && ms->subscr.lac == cs->sel_lac) {
                LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2));
                return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
        } else
@@ -2346,7 +2388,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
        chan_4 = pa->cneed4;
        /* first MI */
        if (ms->subscr.tmsi == ntohl(pa->tmsi1)
-        && ms->subscr.tmsi_valid) {
+        && ms->subscr.mcc == cs->sel_mcc
+        && ms->subscr.mnc == cs->sel_mnc
+        && ms->subscr.lac == cs->sel_lac) {
                LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1));
                return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
        } else
@@ -2354,7 +2398,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
                        ntohl(pa->tmsi1));
        /* second MI */
        if (ms->subscr.tmsi == ntohl(pa->tmsi2)
-        && ms->subscr.tmsi_valid) {
+        && ms->subscr.mcc == cs->sel_mcc
+        && ms->subscr.mnc == cs->sel_mnc
+        && ms->subscr.lac == cs->sel_lac) {
                LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2));
                return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
        } else
@@ -2362,7 +2408,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
                        ntohl(pa->tmsi2));
        /* thrid MI */
        if (ms->subscr.tmsi == ntohl(pa->tmsi3)
-        && ms->subscr.tmsi_valid) {
+        && ms->subscr.mcc == cs->sel_mcc
+        && ms->subscr.mnc == cs->sel_mnc
+        && ms->subscr.lac == cs->sel_lac) {
                LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi3));
                return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
        } else
@@ -2370,7 +2418,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
                        ntohl(pa->tmsi3));
        /* fourth MI */
        if (ms->subscr.tmsi == ntohl(pa->tmsi4)
-        && ms->subscr.tmsi_valid) {
+        && ms->subscr.mcc == cs->sel_mcc
+        && ms->subscr.mnc == cs->sel_mnc
+        && ms->subscr.lac == cs->sel_lac) {
                LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi4));
                return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1);
        } else
@@ -3033,6 +3083,7 @@ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd,
 static int gsm48_rr_dl_est(struct osmocom_ms *ms)
 {
        struct gsm48_rrlayer *rr = &ms->rrlayer;
+       struct gsm322_cellsel *cs = &ms->cellsel;
        struct gsm_subscriber *subscr = &ms->subscr;
        struct msgb *nmsg;
        struct gsm48_hdr *gh;
@@ -3111,7 +3162,10 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
                pr->cm2_len = sizeof(pr->cm2);
                gsm48_rr_enc_cm2(ms, &pr->cm2);
                /* mobile identity */
-               if (ms->subscr.tmsi_valid) {
+               if (ms->subscr.tmsi != 0xffffffff
+                && ms->subscr.mcc == cs->sel_mcc
+                && ms->subscr.mnc == cs->sel_mnc
+                && ms->subscr.lac == cs->sel_lac) {
                        gsm48_generate_mid_from_tmsi(mi, subscr->tmsi);
                        LOGP(DRR, LOGL_INFO, "sending paging response with "
                                "TMSI\n");
@@ -3263,6 +3317,8 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg)
 /* 9.1.13 FREQUENCY REDEFINITION is received */
 static int gsm48_rr_rx_frq_redef(struct osmocom_ms *ms, struct msgb *msg)
 {
+#warning disabled, until added to libosmocore
+#if 0
        struct gsm48_rrlayer *rr = &ms->rrlayer;
        struct gsm48_frq_redef *fr = msgb_l3(msg);
        int mob_al_len = msgb_l3len(msg) - sizeof(*fr);
@@ -3336,6 +3392,7 @@ static int gsm48_rr_rx_frq_redef(struct osmocom_ms *ms, struct msgb *msg)
 
        rr->cd_now.start = 0;
 
+#endif
        return 0;
 }
 
@@ -3776,6 +3833,8 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
 /* 9.1.16 sending HANDOVER COMPLETE */
 static int gsm48_rr_tx_hando_cpl(struct osmocom_ms *ms, uint8_t cause)
 {
+#warning disabled, until added to libosmocore
+#if 0
        struct msgb *nmsg;
        struct gsm48_hdr *gh;
        struct gsm48_ho_cpl *hc;
@@ -3797,11 +3856,14 @@ static int gsm48_rr_tx_hando_cpl(struct osmocom_ms *ms, uint8_t cause)
        // FIXME: mobile observed time
 
        return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+#endif
 }
 
 /* 9.1.4 sending HANDOVER FAILURE */
 static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause)
 {
+#warning disabled, until added to libosmocore
+#if 0
        struct msgb *nmsg;
        struct gsm48_hdr *gh;
        struct gsm48_ho_fail *hf;
@@ -3821,6 +3883,7 @@ static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause)
        hf->rr_cause = cause;
 
        return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+#endif
 }
 
 /* receiving HANDOVER COMMAND message (9.1.15) */
@@ -4197,12 +4260,11 @@ static int gsm48_rr_susp_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
                uint16_t ma[64];
                uint8_t ma_len;
 
-               LOGP(DRR, LOGL_INFO, "suspend complete, request resume of "
-                       "data link\n");
-
                /* deactivating dedicated mode */
-               LOGP(DRR, LOGL_INFO, "leaving dedicated mode\n");
-               l1ctl_tx_dm_rel_req(rr->ms);
+               LOGP(DRR, LOGL_INFO, "suspension coplete, leaving dedicated "
+                       "mode\n");
+               l1ctl_tx_dm_rel_req(ms);
+               l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
 
                /* store current channel descriptions */
                memcpy(&rr->cd_last, &rr->cd_now, sizeof(rr->cd_last));
@@ -4728,7 +4790,8 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
        gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
 
        /* deactivate channel */
-       l1ctl_tx_dm_rel_req(rr->ms);
+       l1ctl_tx_dm_rel_req(ms);
+       l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
 
        switch (rr->modify_state) {
        case GSM48_RR_MOD_ASSIGN: