diff --git a/include/osmocom/pcu/pcuif_proto.h b/include/osmocom/pcu/pcuif_proto.h index 693a1d53..1dda160d 100644 --- a/include/osmocom/pcu/pcuif_proto.h +++ b/include/osmocom/pcu/pcuif_proto.h @@ -3,10 +3,12 @@ #include #include +#include +#include #define PCU_SOCK_DEFAULT "/tmp/pcu_bts" -#define PCU_IF_VERSION 0x0a +#define PCU_IF_VERSION 0x0b #define TXT_MAX_LEN 128 /* msg_type */ @@ -269,6 +271,17 @@ struct gsm_pcu_if_neigh_addr_cnf { } cgi_ps; } __attribute__ ((packed)); +/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via PCH. The struct is sent as a data request + * (data_req) under SAPI PCU_IF_SAPI_PCH_DT. */ +struct gsm_pcu_if_pch_dt { + /* TLLI as reference for confirmation */ + uint32_t tlli; + /* IMSI (to derive paging group) */ + char imsi[OSMO_IMSI_BUF_SIZE]; + /* GSM mac-block (with immediate assignment message) */ + uint8_t data[GSM_MACBLOCK_LEN]; +} __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 33ad4a6e..504ba27d 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -1103,7 +1103,6 @@ int bts_rcv_ptcch_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, const struct gprs_rlcmac_dl_tbf *tbf) { - uint16_t pgroup = ms_paging_group(tbf_ms(tbf)); int plen; const struct gprs_rlcmac_pdch *pdch; @@ -1129,7 +1128,10 @@ 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); - pcu_l1if_tx_pch(bts, immediate_assignment, plen, pgroup); + if (the_pcu->pcu_if_version >= 0x0b) + pcu_l1if_tx_pch_dt(bts, immediate_assignment, plen, tbf->imsi(), tbf->tlli()); + else + pcu_l1if_tx_pch(bts, immediate_assignment, plen, ms_paging_group(tbf_ms(tbf))); } bitvec_free(immediate_assignment); diff --git a/src/gprs_pcu.h b/src/gprs_pcu.h index a9e40ea6..ca52c30a 100644 --- a/src/gprs_pcu.h +++ b/src/gprs_pcu.h @@ -134,6 +134,8 @@ struct gprs_pcu { struct si_cache *si_cache; /* ARFC+BSIC -> CGI PS cache */ struct osmo_timer_list update_stats_timer; /* Used to update some time_cc stats periodically */ + + uint8_t pcu_if_version; }; diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 6c4ed22f..14cc7783 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -294,6 +294,24 @@ void pcu_l1if_tx_pch(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, uint1 pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, sizeof(data)); } +/* Send a block via the paging channel and require a confirmation by the receiving end */ +void pcu_l1if_tx_pch_dt(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, const char *imsi, uint32_t tlli) +{ + /* NOTE: This is in practice only used to transmit IMMEDIATE ASSIGNMENT messages through the paging channel and + * it is not guaranteed to work with other message types. The prepended TLLI will be used as an identifier in + * the confirmation message. */ + + struct gsm_pcu_if_pch_dt pch_dt; + + pch_dt.tlli = tlli; + strcpy(pch_dt.imsi, imsi); + + pch_dt.data[0] = (plen << 2) | 0x01; + bitvec_pack(block, pch_dt.data + 1); + + pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH_DT, 0, 0, 0, (uint8_t*)&pch_dt, sizeof(pch_dt)); +} + int pcu_tx_neigh_addr_res_req(struct gprs_rlcmac_bts *bts, const struct neigh_cache_entry_key *neigh_key) { struct msgb *msg; @@ -734,14 +752,22 @@ static int pcu_rx_info_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_ if (llist_count(&the_pcu->bts_list) > 1) LOGP(DL1IF, LOGL_ERROR, "more than one BTS regsitered at this PCU. This PCU has only been tested with one BTS! OS#5930\n"); - if (info_ind->version != PCU_IF_VERSION) { - fprintf(stderr, "PCU interface version number of BTS (%u) is " - "different (%u).\nPlease re-compile!\n", + LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n"); + + /* NOTE: The classic way to confirm an IMMEDIATE assignment is to send the whole MAC block payload back to the + * PCU. So it is the MAC block itsself that serves a reference for the confirmation. This method has certain + * disadvantages so it was replaced with a method that uses the TLLI as a reference ("Direct TLLI"). This new + * method will replace the old one. The code that handles the old method will be removed in the foreseeable + * future. (see also OS#5927) */ + if (info_ind->version == 0x0a) { + LOGP(DL1IF, LOGL_NOTICE, "PCUIF version 10 is deprecated. OS#5927\n"); + } else if (info_ind->version != PCU_IF_VERSION) { + fprintf(stderr, "PCU interface version number of BTS/BSC (%u) is different (%u).\nPlease use a BTS/BSC with a compatble interface!\n", info_ind->version, PCU_IF_VERSION); exit(-1); } - LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n"); + the_pcu->pcu_if_version = info_ind->version; if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) { LOGP(DL1IF, LOGL_NOTICE, "BTS not available\n"); diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index e7080d5a..1827d84c 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -149,6 +149,7 @@ void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts, void pcu_l1if_tx_agch(struct gprs_rlcmac_bts *bts, bitvec *block, int len); void pcu_l1if_tx_pch(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, uint16_t pgroup); +void pcu_l1if_tx_pch_dt(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, const char *imsi, uint32_t tlli); #endif #ifdef __cplusplus