diff options
Diffstat (limited to 'src/osmo-bsc/pcu_sock.c')
-rw-r--r-- | src/osmo-bsc/pcu_sock.c | 447 |
1 files changed, 358 insertions, 89 deletions
diff --git a/src/osmo-bsc/pcu_sock.c b/src/osmo-bsc/pcu_sock.c index a1a1cfc18..a0c9827dd 100644 --- a/src/osmo-bsc/pcu_sock.c +++ b/src/osmo-bsc/pcu_sock.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdio.h> @@ -37,6 +33,7 @@ #include <osmocom/core/logging.h> #include <osmocom/gsm/l1sap.h> #include <osmocom/gsm/gsm0502.h> +#include <osmocom/bsc/abis_nm.h> #include <osmocom/bsc/gsm_data.h> #include <osmocom/bsc/pcu_if.h> @@ -46,10 +43,9 @@ #include <osmocom/bsc/abis_rsl.h> #include <osmocom/bsc/gsm_04_08_rr.h> #include <osmocom/bsc/bts.h> +#include <osmocom/bsc/bts_sm.h> static int pcu_sock_send(struct gsm_bts *bts, struct msgb *msg); -uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx); -int pcu_direct = 1; static const char *sapi_string[] = { [PCU_IF_SAPI_RACH] = "RACH", @@ -58,8 +54,8 @@ static const char *sapi_string[] = { [PCU_IF_SAPI_BCCH] = "BCCH", [PCU_IF_SAPI_PDTCH] = "PDTCH", [PCU_IF_SAPI_PRACH] = "PRACH", - [PCU_IF_SAPI_PTCCH] = "PTCCH", - [PCU_IF_SAPI_AGCH_DT] = "AGCH_DT", + [PCU_IF_SAPI_PTCCH] = "PTCCH", + [PCU_IF_SAPI_PCH_DT] = "PCH_DT", }; /* Check if BTS has a PCU connection */ @@ -96,6 +92,33 @@ struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr) return msg; } +/* Check if the timeslot can be utilized as PDCH now + * (PDCH is currently active on BTS) */ +static bool ts_now_usable_as_pdch(const struct gsm_bts_trx_ts *ts) +{ + switch (ts->pchan_is) { + case GSM_PCHAN_PDCH: + /* NOTE: We currently only support Ericsson RBS as a BSC + * co-located BTS. This BTS only supports dynamic channels. */ + return true; + default: + return false; + } +} + +/* Check if it is possible to use the TS as PDCH (not now, but maybe later) */ +static bool ts_usable_as_pdch(const struct gsm_bts_trx_ts *ts) +{ + switch (ts->pchan_from_config) { + case GSM_PCHAN_TCH_F_PDCH: + case GSM_PCHAN_OSMO_DYN: + case GSM_PCHAN_PDCH: + return true; + default: + return false; + } +} + /* Fill the frequency hopping parameter */ static void info_ind_fill_fhp(struct gsm_pcu_if_info_trx_ts *ts_info, const struct gsm_bts_trx_ts *ts) @@ -108,6 +131,48 @@ static void info_ind_fill_fhp(struct gsm_pcu_if_info_trx_ts *ts_info, ts_info->ma_bit_len = ts->hopping.ma_len * 8 - ts->hopping.ma.cur_bit; } +/* Fill the TRX parameter */ +static void info_ind_fill_trx(struct gsm_pcu_if_info_trx *trx_info, const struct gsm_bts_trx *trx) +{ + unsigned int tn; + const struct gsm_bts_trx_ts *ts; + + trx_info->hlayer1 = 0x2342; + trx_info->pdch_mask = 0; + trx_info->arfcn = trx->arfcn; + + if (trx->mo.nm_state.operational != NM_OPSTATE_ENABLED || + trx->mo.nm_state.administrative != NM_STATE_UNLOCKED) { + LOG_TRX(trx, DPCU, LOGL_INFO, "unavailable for PCU (op=%s adm=%s)\n", + abis_nm_opstate_name(trx->mo.nm_state.operational), + abis_nm_admin_name(trx->mo.nm_state.administrative)); + return; + } + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) { + ts = &trx->ts[tn]; + if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED) + continue; + if (!ts_now_usable_as_pdch(ts)) + continue; + + trx_info->pdch_mask |= (1 << tn); + trx_info->ts[tn].tsc = + (ts->tsc >= 0) ? ts->tsc : trx->bts->bsic & 7; + + if (ts->hopping.enabled) + info_ind_fill_fhp(&trx_info->ts[tn], ts); + + LOG_TRX(trx, DPCU, LOGL_INFO, "PDCH on ts=%u is available (tsc=%u ", ts->nr, + trx_info->ts[tn].tsc); + if (ts->hopping.enabled) + LOGPC(DPCU, LOGL_INFO, "hopping=yes hsn=%u maio=%u ma_bit_len=%u)\n", + ts->hopping.hsn, ts->hopping.maio, trx_info->ts[tn].ma_bit_len); + else + LOGPC(DPCU, LOGL_INFO, "hopping=no arfcn=%u)\n", trx->arfcn); + } +} + /* Send BTS properties to the PCU */ static int pcu_tx_info_ind(struct gsm_bts *bts) { @@ -115,15 +180,14 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) struct gsm_pcu_if *pcu_prim; struct gsm_pcu_if_info_ind *info_ind; struct gprs_rlc_cfg *rlcc; - struct gsm_bts_gprs_nsvc *nsvc; + struct gsm_bts_sm *bts_sm; + struct gsm_gprs_nsvc *nsvc; struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - int i, tn; + int i; - OSMO_ASSERT(bts); - OSMO_ASSERT(bts->network); + bts_sm = bts->site_mgr; - LOGP(DPCU, LOGL_INFO, "Sending info for BTS %d\n",bts->nr); + LOGP(DPCU, LOGL_INFO, "Sending info for BTS %d\n", bts->nr); rlcc = &bts->gprs.cell.rlc_cfg; @@ -135,9 +199,8 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) info_ind = &pcu_prim->u.info_ind; info_ind->version = PCU_IF_VERSION; info_ind->flags |= PCU_IF_FLAG_ACTIVE; - - if (pcu_direct) - info_ind->flags |= PCU_IF_FLAG_SYSMO; + info_ind->flags |= PCU_IF_FLAG_SYSMO; + info_ind->flags |= PCU_IF_FLAG_DT; /* RAI */ info_ind->mcc = bts->network->plmn.mcc; @@ -147,11 +210,12 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) info_ind->rac = bts->gprs.rac; /* NSE */ - info_ind->nsei = bts->gprs.nse.nsei; - memcpy(info_ind->nse_timer, bts->gprs.nse.timer, 7); + info_ind->nsei = bts_sm->gprs.nse.nsei; + memcpy(info_ind->nse_timer, bts_sm->gprs.nse.timer, 7); memcpy(info_ind->cell_timer, bts->gprs.cell.timer, 11); /* cell attributes */ + info_ind->bsic = bts->bsic; info_ind->cell_id = bts->cell_identity; info_ind->repeat_time = rlcc->paging.repeat_time; info_ind->repeat_count = rlcc->paging.repeat_count; @@ -193,16 +257,16 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) if (rlcc->cs_mask & (1 << GPRS_MCS9)) info_ind->flags |= PCU_IF_FLAG_MCS9; } -#warning "isn't dl_tbf_ext wrong?: * 10 and no ntohs" + /* TODO: isn't dl_tbf_ext wrong?: * 10 and no ntohs */ info_ind->dl_tbf_ext = rlcc->parameter[T_DL_TBF_EXT]; -#warning "isn't ul_tbf_ext wrong?: * 10 and no ntohs" + /* TODO: isn't ul_tbf_ext wrong?: * 10 and no ntohs */ info_ind->ul_tbf_ext = rlcc->parameter[T_UL_TBF_EXT]; info_ind->initial_cs = rlcc->initial_cs; info_ind->initial_mcs = rlcc->initial_mcs; /* NSVC */ for (i = 0; i < ARRAY_SIZE(info_ind->nsvci); i++) { - nsvc = &bts->gprs.nsvc[i]; + nsvc = &bts->site_mgr->gprs.nsvc[i]; info_ind->nsvci[i] = nsvc->nsvci; info_ind->local_port[i] = nsvc->local_port; @@ -210,14 +274,14 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) case AF_INET: info_ind->address_type[i] = PCU_IF_ADDR_TYPE_IPV4; info_ind->remote_ip[i].v4 = nsvc->remote.u.sin.sin_addr; - info_ind->remote_port[i] = nsvc->remote.u.sin.sin_port; + info_ind->remote_port[i] = ntohs(nsvc->remote.u.sin.sin_port); break; case AF_INET6: info_ind->address_type[i] = PCU_IF_ADDR_TYPE_IPV6; memcpy(&info_ind->remote_ip[i].v6, &nsvc->remote.u.sin6.sin6_addr, sizeof(struct in6_addr)); - info_ind->remote_port[i] = nsvc->remote.u.sin6.sin6_port; + info_ind->remote_port[i] = ntohs(nsvc->remote.u.sin6.sin6_port); break; default: info_ind->address_type[i] = PCU_IF_ADDR_TYPE_UNSPEC; @@ -229,39 +293,114 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) trx = gsm_bts_trx_num(bts, i); if (!trx) continue; - info_ind->trx[i].hlayer1 = 0x2342; - info_ind->trx[i].pdch_mask = 0; - info_ind->trx[i].arfcn = trx->arfcn; - for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) { - ts = &trx->ts[tn]; - if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED || - ts->pchan_is != GSM_PCHAN_PDCH) - continue; + if (trx->nr >= ARRAY_SIZE(info_ind->trx)) { + LOG_TRX(trx, DPCU, LOGL_NOTICE, "PCU interface (version %u) " + "cannot handle more than %zu transceivers => skipped\n", + PCU_IF_VERSION, ARRAY_SIZE(info_ind->trx)); + break; + } + info_ind_fill_trx(&info_ind->trx[trx->nr], trx); + } + + return pcu_sock_send(bts, msg); +} - info_ind->trx[i].pdch_mask |= (1 << tn); - info_ind->trx[i].ts[tn].tsc = - (ts->tsc >= 0) ? ts->tsc : bts->bsic & 7; +static int pcu_tx_e1_ccu_ind(struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; - if (ts->hopping.enabled) - info_ind_fill_fhp(&info_ind->trx[i].ts[tn], ts); + llist_for_each_entry(trx, &bts->trx_list, list) { + struct gsm_pcu_if_e1_ccu_ind *e1_ccu_ind; + int i; - LOGP(DPCU, LOGL_INFO, "trx=%d ts=%d: PDCH is available " - "(tsc=%u ", trx->nr, ts->nr, info_ind->trx[i].ts[tn].tsc); - if (ts->hopping.enabled) - LOGPC(DPCU, LOGL_INFO, "hopping=yes hsn=%u maio=%u ma_bit_len=%u)\n", - ts->hopping.hsn, ts->hopping.maio, trx->ts[tn].hopping.ma.data_len - trx->ts[tn].hopping.ma.cur_bit); - else - LOGPC(DPCU, LOGL_INFO, "hopping=no arfcn=%u)\n", trx->arfcn); + if (trx->nr >= PCU_IF_NUM_TRX) { + LOG_TRX(trx, DPCU, LOGL_NOTICE, "PCU interface (version %u) " + "cannot handle more than %u transceivers => skipped\n", + PCU_IF_VERSION, PCU_IF_NUM_TRX); + continue; + } + + for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { + struct gsm_pcu_if *pcu_prim; + struct gsm_bts_trx_ts *ts; + struct msgb *msg; + int rc; + + ts = &trx->ts[i]; + + if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED) + continue; + if (!ts_usable_as_pdch(ts)) + continue; + + msg = pcu_msgb_alloc(PCU_IF_MSG_E1_CCU_IND, bts->nr); + if (!msg) + return -ENOMEM; + pcu_prim = (struct gsm_pcu_if *)msg->data; + e1_ccu_ind = &pcu_prim->u.e1_ccu_ind; + e1_ccu_ind->ts_nr = ts->nr; + e1_ccu_ind->trx_nr = trx->nr; + e1_ccu_ind->e1_nr = ts->e1_link.e1_nr; + e1_ccu_ind->e1_ts = ts->e1_link.e1_ts; + e1_ccu_ind->e1_ts_ss = ts->e1_link.e1_ts_ss; + + LOG_TRX(trx, DPCU, LOGL_INFO, "Sending E1 CCU info for TS %d\n", e1_ccu_ind->ts_nr); + rc = pcu_sock_send(bts, msg); + if (rc < 0) + return -EINVAL; } } - return pcu_sock_send(bts, msg); + return 0; } -void pcu_info_update(struct gsm_bts *bts) +/* Allow test to overwrite it */ +__attribute__((weak)) void pcu_info_update(struct gsm_bts *bts) { - if (pcu_connected(bts)) + if (pcu_connected(bts)) { + /* In cases where the CCU is connected via an E1 line, we transmit the connection parameters for the + * PDCH before we announce the other BTS related parameters. At the moment Ericsson RBS is the only + * E1 BTS we support. */ + if (is_ericsson_bts(bts)) + pcu_tx_e1_ccu_ind(bts); + pcu_tx_info_ind(bts); + } +} + +static int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t sapi, uint32_t fn, + uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len, + int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual) +{ + struct msgb *msg; + struct gsm_pcu_if *pcu_prim; + struct gsm_pcu_if_data *data_ind; + struct gsm_bts *bts = ts->trx->bts; + + LOGP(DPCU, LOGL_DEBUG, "Sending data indication: sapi=%s arfcn=%d block=%d data=%s\n", + sapi_string[sapi], arfcn, block_nr, osmo_hexdump(data, len)); + + msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_IND, bts->nr); + if (!msg) + return -ENOMEM; + pcu_prim = (struct gsm_pcu_if *) msg->data; + data_ind = &pcu_prim->u.data_ind; + + data_ind->sapi = sapi; + data_ind->rssi = rssi; + data_ind->fn = fn; + data_ind->arfcn = arfcn; + data_ind->trx_nr = ts->trx->nr; + data_ind->ts_nr = ts->nr; + data_ind->block_nr = block_nr; + data_ind->ber10k = ber10k; + data_ind->ta_offs_qbits = bto; + data_ind->lqual_cb = lqual; + if (len) + memcpy(data_ind->data, data, len); + data_ind->len = len; + + return pcu_sock_send(bts, msg); } /* Forward rach indication to PCU */ @@ -368,11 +507,31 @@ static int pcu_rx_rr_paging(struct gsm_bts *bts, uint8_t paging_group, return rc; } +/* Helper function for pcu_rx_data_req() to extract paging group info (3 byte) */ +static uint8_t extract_paging_group(struct gsm_bts *bts, uint8_t *data) +{ + char imsi_digit_buf[4]; + uint8_t pag_grp; + + /* the first three bytes are the last three digits of the IMSI, which we need to compute the paging group */ + imsi_digit_buf[0] = data[0]; + imsi_digit_buf[1] = data[1]; + imsi_digit_buf[2] = data[2]; + imsi_digit_buf[3] = '\0'; + + pag_grp = gsm0502_calc_paging_group(&bts->si_common.chan_desc, + str_to_imsi(imsi_digit_buf)); + + LOGP(DPCU, LOGL_DEBUG, "Calculating paging group: imsi_digit_buf=%s ==> pag_grp=0x%02x\n", + imsi_digit_buf, pag_grp); + + return pag_grp; +} + static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, struct gsm_pcu_if_data *data_req) { struct msgb *msg; - char imsi_digit_buf[4]; uint32_t tlli = -1; uint8_t pag_grp; int rc = 0; @@ -384,15 +543,8 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, switch (data_req->sapi) { case PCU_IF_SAPI_PCH: - /* the first three bytes are the last three digits of - * the IMSI, which we need to compute the paging group */ - imsi_digit_buf[0] = data_req->data[0]; - imsi_digit_buf[1] = data_req->data[1]; - imsi_digit_buf[2] = data_req->data[2]; - imsi_digit_buf[3] = '\0'; - LOGP(DPCU, LOGL_DEBUG, "SAPI PCH imsi %s\n", imsi_digit_buf); - pag_grp = gsm0502_calc_paging_group(&bts->si_common.chan_desc, - str_to_imsi(imsi_digit_buf)); + /* Extract 3 byte paging group */ + pag_grp = extract_paging_group(bts, data_req->data); pcu_rx_rr_paging(bts, pag_grp, data_req->data+3); break; case PCU_IF_SAPI_AGCH: @@ -409,28 +561,42 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, rc = -EIO; } break; - case PCU_IF_SAPI_AGCH_DT: - /* DT = direct tlli. A tlli is prefixed */ + case PCU_IF_SAPI_PCH_DT: + /* DT = direct TLLI. A tlli is prefixed so that the BSC/BTS can confirm the sending of the downlink + * IMMEDIATE ASSIGNMENT towards the PCU using this TLLI as a reference. */ - if (data_req->len < 5) { - LOGP(DPCU, LOGL_ERROR, "Received PCU data request with " - "invalid/small length %d\n", data_req->len); + if (data_req->len < 8) { + LOGP(DPCU, LOGL_ERROR, "Received PCU data request with invalid/small length %d\n", + data_req->len); break; } + + /* Extract 4 byte TLLI */ memcpy(&tlli, data_req->data, 4); - msg = msgb_alloc(data_req->len - 4, "pcu_agch"); + /* Extract 3 byte paging group */ + pag_grp = extract_paging_group(bts, data_req->data + 4); + + LOGP(DPCU, LOGL_DEBUG, "PCU Sends immediate assignment via PCH (tlli=0x%08x, pag_grp=0x%02x)\n", + tlli, pag_grp); + msg = msgb_alloc(data_req->len - 7, "pcu_pch"); if (!msg) { rc = -ENOMEM; break; } - msg->l3h = msgb_put(msg, data_req->len - 4); - memcpy(msg->l3h, data_req->data + 4, data_req->len - 4); - - if (bts->type == GSM_BTS_TYPE_RBS2000) - rc = rsl_ericsson_imm_assign_cmd(bts, tlli, msg->len, msg->data); - else - rc = rsl_imm_assign_cmd(bts, msg->len, msg->data); + msg->l3h = msgb_put(msg, data_req->len - 7); + memcpy(msg->l3h, data_req->data + 7, data_req->len - 7); + + /* NOTE: Sending an IMMEDIATE ASSIGNMENT via PCH became necessary with GPRS in order to be able to + * assign downlink TBFs directly through the paging channel. However, this method never became part + * of the RSL specs. This means that each BTS vendor has to come up with a proprietary method. At + * the moment we only support Ericsson RBS here. */ + if (bts->type == GSM_BTS_TYPE_RBS2000) { + rc = rsl_ericsson_imm_assign_cmd(bts, tlli, msg->len, msg->data, pag_grp); + } else { + LOGP(DPCU, LOGL_ERROR, "BTS model does not support sending immediate assignment via PCH!\n"); + rc = -ENOTSUP; + } if (rc) { msgb_free(msg); @@ -446,8 +612,103 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, return rc; } +static int pcu_tx_si(const struct gsm_bts *bts, enum osmo_sysinfo_type si_type, bool enable) +{ + /* the SI is per-BTS so it doesn't matter which TRX we use */ + struct gsm_bts_trx *trx = bts->c0; + + uint8_t si_buf[GSM_MACBLOCK_LEN]; + uint8_t len; + int rc; + + if (enable) { + memcpy(si_buf, GSM_BTS_SI(bts, si_type), GSM_MACBLOCK_LEN); + len = GSM_MACBLOCK_LEN; + LOGP(DPCU, LOGL_DEBUG, "Updating SI%s to PCU: %s\n", + get_value_string(osmo_sitype_strs, si_type), + osmo_hexdump_nospc(si_buf, GSM_MACBLOCK_LEN)); + } else { + si_buf[0] = si_type; + len = 1; + + /* Note: SI13 is the only system information type that is revked + * by just sending a completely empty message. This is due to + * historical reasons */ + if (si_type != SYSINFO_TYPE_13) + len = 0; + + LOGP(DPCU, LOGL_DEBUG, "Revoking SI%s from PCU\n", + get_value_string(osmo_sitype_strs, si_buf[0])); + } + + /* The low-level data like FN, ARFCN etc will be ignored but we have to + * set lqual high enough to bypass the check at lower levels */ + rc = pcu_tx_data_ind(&trx->ts[0], PCU_IF_SAPI_BCCH, 0, 0, 0, si_buf, len, + 0, 0, 0, INT16_MAX); + if (rc < 0) + LOGP(DPCU, LOGL_NOTICE, "Failed to send SI%s to PCU: rc=%d\n", + get_value_string(osmo_sitype_strs, si_type), rc); + + return rc; +} + +static int pcu_tx_si_all(struct gsm_bts *bts) +{ + const enum osmo_sysinfo_type si_types[] = { SYSINFO_TYPE_1, SYSINFO_TYPE_2, SYSINFO_TYPE_3, SYSINFO_TYPE_13 }; + unsigned int i; + int rc = 0; + + for (i = 0; i < ARRAY_SIZE(si_types); i++) { + if (GSM_BTS_HAS_SI(bts, si_types[i])) { + rc = pcu_tx_si(bts, si_types[i], true); + if (rc < 0) + return rc; + } else { + LOGP(DPCU, LOGL_INFO, + "SI%s is not available on PCU connection\n", + get_value_string(osmo_sitype_strs, si_types[i])); + } + } + + return 0; +} + +static int pcu_rx_txt_ind(struct gsm_bts *bts, + const struct gsm_pcu_if_txt_ind *txt) +{ + int rc; + + switch (txt->type) { + case PCU_VERSION: + LOGP(DPCU, LOGL_INFO, "OsmoPCU version %s connected\n", + txt->text); + rc = pcu_tx_si_all(bts); + if (rc < 0) + return -EINVAL; + break; + case PCU_OML_ALERT: + LOG_BTS(bts, DPCU, LOGL_ERROR, "PCU external alarm: %s\n", txt->text); + break; + default: + LOGP(DPCU, LOGL_ERROR, "Unknown TXT_IND type %u received\n", + txt->type); + return -EINVAL; + } + + return 0; +} + +#define CHECK_IF_MSG_SIZE(prim_len, prim_msg) \ + do { \ + size_t _len = PCUIF_HDR_SIZE + sizeof(prim_msg); \ + if (prim_len < _len) { \ + LOGP(DPCU, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive %s " \ + "size is %zu, discarding\n", prim_len, #prim_msg, _len); \ + return -EINVAL; \ + } \ + } while (0) static int pcu_rx(struct gsm_network *net, uint8_t msg_type, - struct gsm_pcu_if *pcu_prim) + struct gsm_pcu_if *pcu_prim, size_t prim_len) { int rc = 0; struct gsm_bts *bts; @@ -458,8 +719,13 @@ static int pcu_rx(struct gsm_network *net, uint8_t msg_type, switch (msg_type) { case PCU_IF_MSG_DATA_REQ: case PCU_IF_MSG_PAG_REQ: + CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.data_req); rc = pcu_rx_data_req(bts, msg_type, &pcu_prim->u.data_req); break; + case PCU_IF_MSG_TXT_IND: + CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.txt_ind); + rc = pcu_rx_txt_ind(bts, &pcu_prim->u.txt_ind); + break; default: LOGP(DPCU, LOGL_ERROR, "Received unknown PCU msg type %d\n", msg_type); @@ -495,7 +761,7 @@ static int pcu_sock_send(struct gsm_bts *bts, struct msgb *msg) return -EIO; } msgb_enqueue(&state->upqueue, msg); - conn_bfd->when |= OSMO_FD_WRITE; + osmo_fd_write_enable(conn_bfd); return 0; } @@ -518,7 +784,7 @@ static void pcu_sock_close(struct pcu_sock_state *state) osmo_fd_unregister(bfd); /* re-enable the generation of ACCEPT for new connections */ - state->listen_bfd.when |= OSMO_FD_READ; + osmo_fd_read_enable(&state->listen_bfd); #if 0 /* remove si13, ... */ @@ -554,7 +820,7 @@ static int pcu_sock_read(struct osmo_fd *bfd) struct msgb *msg; int rc; - msg = msgb_alloc(sizeof(*pcu_prim), "pcu_sock_rx"); + msg = msgb_alloc(sizeof(*pcu_prim) + 1000, "pcu_sock_rx"); if (!msg) return -ENOMEM; @@ -565,12 +831,21 @@ static int pcu_sock_read(struct osmo_fd *bfd) goto close; if (rc < 0) { - if (errno == EAGAIN) + if (errno == EAGAIN) { + msgb_free(msg); return 0; + } goto close; } - rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim); + if (rc < PCUIF_HDR_SIZE) { + LOGP(DPCU, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive hdr size " + "is %zu, discarding\n", rc, PCUIF_HDR_SIZE); + msgb_free(msg); + return 0; + } + + rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim, rc); /* as we always synchronously process the message in pcu_rx() and * its callbacks, we can free the message here. */ @@ -597,7 +872,7 @@ static int pcu_sock_write(struct osmo_fd *bfd) msg = llist_entry(state->upqueue.next, struct msgb, list); pcu_prim = (struct gsm_pcu_if *)msg->data; - bfd->when &= ~OSMO_FD_WRITE; + osmo_fd_write_disable(bfd); /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */ if (!msgb_length(msg)) { @@ -612,7 +887,7 @@ static int pcu_sock_write(struct osmo_fd *bfd) goto close; if (rc < 0) { if (errno == EAGAIN) { - bfd->when |= OSMO_FD_WRITE; + osmo_fd_write_enable(bfd); break; } goto close; @@ -667,15 +942,12 @@ static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags) LOGP(DPCU, LOGL_NOTICE, "PCU connects but we already have " "another active connection ?!?\n"); /* We already have one PCU connected, this is all we support */ - state->listen_bfd.when &= ~OSMO_FD_READ; + osmo_fd_read_disable(&state->listen_bfd); close(rc); return 0; } - conn_bfd->fd = rc; - conn_bfd->when = OSMO_FD_READ; - conn_bfd->cb = pcu_sock_cb; - conn_bfd->data = state; + osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, pcu_sock_cb, state, 0); if (osmo_fd_register(conn_bfd) != 0) { LOGP(DPCU, LOGL_ERROR, "Failed to register new connection " @@ -707,18 +979,15 @@ int pcu_sock_init(const char *path, struct gsm_bts *bts) bfd = &state->listen_bfd; - bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, - OSMO_SOCK_F_BIND); - if (bfd->fd < 0) { + rc = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, OSMO_SOCK_F_BIND); + if (rc < 0) { LOGP(DPCU, LOGL_ERROR, "Could not create unix socket: %s\n", strerror(errno)); talloc_free(state); return -1; } - bfd->when = OSMO_FD_READ; - bfd->cb = pcu_sock_accept; - bfd->data = state; + osmo_fd_setup(bfd, rc, OSMO_FD_READ, pcu_sock_accept, state, 0); rc = osmo_fd_register(bfd); if (rc < 0) { |