diff --git a/include/osmocom/pcu/pcuif_proto.h b/include/osmocom/pcu/pcuif_proto.h index aa22447e..cd2a2983 100644 --- a/include/osmocom/pcu/pcuif_proto.h +++ b/include/osmocom/pcu/pcuif_proto.h @@ -42,6 +42,7 @@ #define PCU_IF_SAPI_PRACH 0x06 /* packet random access channel */ #define PCU_IF_SAPI_PTCCH 0x07 /* packet TA control channel */ #define PCU_IF_SAPI_PCH_2 0x08 /* assignment on PCH (confirmed using message id) */ +#define PCU_IF_SAPI_AGCH_2 0x09 /* assignment on AGCH (confirmed using message id) */ /* flags */ #define PCU_IF_FLAG_ACTIVE (1 << 0)/* BTS is active */ @@ -276,6 +277,18 @@ struct gsm_pcu_if_pch { bool confirm; } __attribute__((packed)); +/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via AGCH. The struct is sent as a data request + * (data_req) under SAPI PCU_IF_SAPI_AGCH_2. */ +struct gsm_pcu_if_agch { + /* message id as reference for confirmation */ + uint32_t msg_id; + /* GSM mac-block (with immediate assignment message) */ + uint8_t data[GSM_MACBLOCK_LEN]; + /* Set to true in case the receiving end must send a confirmation + * when the MAC block (data) has been sent. */ + bool confirm; +} __attribute__((packed)); + struct gsm_pcu_if { /* context based information */ uint8_t msg_type; /* message type */ diff --git a/src/bts.cpp b/src/bts.cpp index 5c483d5c..c86c3dc5 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -1033,7 +1033,10 @@ int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip) rip->burst_type); bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF); if (plen >= 0) { - pcu_l1if_tx_agch(bts, bv, plen); + if (the_pcu->pcu_if_version >= 0x0b) + pcu_l1if_tx_agch2(bts, bv, plen, GSM_RESERVED_TMSI, false); + else + pcu_l1if_tx_agch(bts, bv, plen); rc = 0; } else { rc = plen; @@ -1047,8 +1050,12 @@ send_imm_ass_rej: bv, rip->ra, rip->rfn, rip->burst_type, (uint8_t)osmo_tdef_get(bts->T_defs_bts, 3142, OSMO_TDEF_S, -1)); bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_REJ); - if (plen >= 0) - pcu_l1if_tx_agch(bts, bv, plen); + if (plen >= 0) { + if (the_pcu->pcu_if_version >= 0x0b) + pcu_l1if_tx_agch2(bts, bv, plen, GSM_RESERVED_TMSI, false); + else + pcu_l1if_tx_agch(bts, bv, plen); + } bitvec_free(bv); /* rc was already properly set before goto */ return rc; @@ -1128,10 +1135,26 @@ void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, const struct gprs_rlcmac_dl_tbf GSM_L1_BURST_TYPE_ACCESS_0); if (plen >= 0) { bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_DL_TBF); - if (the_pcu->pcu_if_version >= 0x0b) - pcu_l1if_tx_pch2(bts, immediate_assignment, plen, true, tbf->imsi(), tbf->tlli()); - else + + if (the_pcu->pcu_if_version >= 0x0b) { + if (ms_imsi_is_valid(tbf->ms())) { + pcu_l1if_tx_pch2(bts, immediate_assignment, plen, true, tbf->imsi(), tbf->tlli()); + } else { + /* During GMM ATTACH REQUEST, the IMSI is not yet known to the PCU or SGSN. (It is requested + * after the GMM ATTACH REQUEST with the GMM IDENTITY REQUEST.) When the PCU has to assign a + * DL TBF but the IMSI is not known, then the IMMEDIATE ASSIGNMENT is sent on the AGCH. The + * reason for this is that without an IMSI we can not calculate the paging group, which would + * be necessary for transmission on PCH. Since the IMSI is usually only unknown during the GMM + * ATTACH REQUEST, we may assume that the MS is in non-DRX mode and hence it is listening on + * all CCCH blocks, including AGCH. + * + * See also: 3gpp TS 44.060, section 5.5.1.5 + * 3gpp TS 45.002, section 6.5.3, 6.5.6 */ + pcu_l1if_tx_agch2(bts, immediate_assignment, plen, true, tbf->tlli()); + } + } else { pcu_l1if_tx_pch(bts, immediate_assignment, plen, tbf->imsi()); + } } bitvec_free(immediate_assignment); diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index f92f08ea..7bc4cb9c 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -251,6 +251,8 @@ void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts, void pcu_l1if_tx_agch(struct gprs_rlcmac_bts *bts, bitvec *block, int plen) { + /* TODO: When PCUIF v.11 has become mainline, we will use pcu_l1if_tx_agch2() exclusively. + * This will make this function obsolote, so we can remove it. */ uint8_t data[GSM_MACBLOCK_LEN]; /* prefix PLEN */ /* FIXME: why does OpenBTS has no PLEN and no fill in message? */ @@ -263,10 +265,31 @@ void pcu_l1if_tx_agch(struct gprs_rlcmac_bts *bts, bitvec *block, int plen) pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, sizeof(data)); } +/* Send a MAC block via the access grant channel. This will (obviously) only work for MAC blocks that contain + * an IMMEDIATE ASSIGNMENT. In case the MAC block contains an IMMEDIATE ASSIGNMENT message, the receiving end + * is required to confirm when the IMMEDIATE ASSIGNMENT has been sent. */ +void pcu_l1if_tx_agch2(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, bool confirm, uint32_t msg_id) +{ + struct gsm_pcu_if_agch agch = { 0 }; + + agch.confirm = confirm; + agch.msg_id = msg_id; + agch.data[0] = (plen << 2) | 0x01; + bitvec_pack(block, agch.data + 1); + + if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_AGCH)) + gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_AGCH, 0, 0, 0, 0, agch.data, GSM_MACBLOCK_LEN); + + pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_AGCH_2, 0, 0, 0, (uint8_t*)&agch, sizeof(agch)); +} + #define IMSI_DIGITS_FOR_PAGING 3 /* Send a MAC block via the paging channel. (See also comment below) */ void pcu_l1if_tx_pch(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, const char *imsi) { + /* TODO: When PCUIF v.11 has become mainline, we will use pcu_l1if_tx_pch2() exclusively. + * This will make this function obsolote, so we can remove it. */ + uint8_t data[IMSI_DIGITS_FOR_PAGING + GSM_MACBLOCK_LEN]; /* prepend last three IMSI digits (if present) from which BTS/BSC will calculate the paging group */ @@ -561,6 +584,7 @@ static int pcu_rx_data_cnf2(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data_ switch (data_cnf->sapi) { case PCU_IF_SAPI_PCH_2: + case PCU_IF_SAPI_AGCH_2: bts_rcv_imm_ass_cnf(bts, NULL, data_cnf->msg_id); break; default: diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index 138636d3..b6da337b 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -147,6 +147,7 @@ void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts, uint32_t fn, uint8_t block_nr, uint8_t *data, size_t data_len); void pcu_l1if_tx_agch(struct gprs_rlcmac_bts *bts, bitvec *block, int len); +void pcu_l1if_tx_agch2(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, bool confirm, uint32_t msg_id); #endif #ifdef __cplusplus