diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 2f6ae98df..cb5433b41 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -29,6 +29,7 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp); int bts_model_rsl_chan_rel(struct gsm_lchan *lchan); +int bts_model_rsl_chan_mod(struct gsm_lchan *lchan); int bts_model_rsl_deact_sacch(struct gsm_lchan *lchan); int bts_model_rsl_mode_modify(struct gsm_lchan *lchan); diff --git a/include/osmo-bts/handover.h b/include/osmo-bts/handover.h index 1cf5d6969..35d5c6901 100644 --- a/include/osmo-bts/handover.h +++ b/include/osmo-bts/handover.h @@ -6,5 +6,7 @@ enum { HANDOVER_WAIT_FRAME, }; +void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay); +void handover_frame(struct gsm_lchan *lchan); void handover_reset(struct gsm_lchan *lchan); diff --git a/src/common/handover.c b/src/common/handover.c index c40219db9..ab3cbcf8a 100644 --- a/src/common/handover.c +++ b/src/common/handover.c @@ -34,6 +34,118 @@ #include #include +/* Transmit a handover related PHYS INFO on given lchan */ +static int ho_tx_phys_info(struct gsm_lchan *lchan) +{ + struct msgb *msg = msgb_alloc_headroom(1024, 128, "PHYS INFO"); + struct gsm48_hdr *gh; + + if (!msg) + return -ENOMEM; + + LOGP(DHO, LOGL_INFO, + "%s Sending PHYSICAL INFORMATION to MS.\n", + gsm_lchan_name(lchan)); + + /* Build RSL UNITDATA REQUEST message with 04.08 PHYS INFO */ + msg->l3h = msg->data; + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_HANDO_INFO; + msgb_put_u8(msg, lchan->rqd_ta); + + rsl_rll_push_l3(msg, RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan), + 0x00, 0); + + lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch); + return 0; +} + +/* timer call-back for T3105 (handover PHYS INFO re-transmit) */ +static void ho_t3105_cb(void *data) +{ + struct gsm_lchan *lchan = data; + struct gsm_bts *bts = lchan->ts->trx->bts; + struct gsm_bts_role_bts *btsb = bts->role; + + LOGP(DHO, LOGL_INFO, "%s T3105 timeout (%d resends left)\n", + gsm_lchan_name(lchan), btsb->ny1 - lchan->ho.phys_info_count); + + if (lchan->state != LCHAN_S_ACTIVE) { + LOGP(DHO, LOGL_NOTICE, + "%s is in not active. It is in state %s. Ignoring\n", + gsm_lchan_name(lchan), gsm_lchans_name(lchan->state)); + return; + } + + if (lchan->ho.phys_info_count >= btsb->ny1) { + /* HO Abort */ + LOGP(DHO, LOGL_NOTICE, "%s NY1 reached, sending CONNection " + "FAILure to BSC.\n", gsm_lchan_name(lchan)); + rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL); + return; + } + + ho_tx_phys_info(lchan); + lchan->ho.phys_info_count++; + osmo_timer_schedule(&lchan->ho.t3105, 0, btsb->t3105_ms * 1000); +} + +/* received random access on dedicated channel */ +void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay) +{ + struct gsm_bts *bts = lchan->ts->trx->bts; + struct gsm_bts_role_bts *btsb = bts->role; + + /* Ignore invalid handover ref */ + if (lchan->ho.ref != ra) { + LOGP(DHO, LOGL_INFO, "%s RACH on dedicated channel received, but " + "ra=0x%02x != expected ref=0x%02x. (This is no bug)\n", + gsm_lchan_name(lchan), ra, lchan->ho.ref); + return; + } + + LOGP(DHO, LOGL_NOTICE, + "%s RACH on dedicated channel received with TA=%u\n", + gsm_lchan_name(lchan), acc_delay); + + /* Set timing advance */ + lchan->rqd_ta = acc_delay; + + /* Stop handover detection, wait for valid frame */ + lchan->ho.active = HANDOVER_WAIT_FRAME; + if (bts_model_rsl_chan_mod(lchan) != 0) { + LOGP(DHO, LOGL_ERROR, + "%s failed to modify channel after handover\n", + gsm_lchan_name(lchan)); + rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL); + return; + } + + /* Send HANDover DETect to BSC */ + rsl_tx_hando_det(lchan, &lchan->rqd_ta); + + /* Send PHYS INFO */ + lchan->ho.phys_info_count = 1; + ho_tx_phys_info(lchan); + + /* Start T3105 */ + LOGP(DHO, LOGL_DEBUG, + "%s Starting T3105 with %u ms\n", + gsm_lchan_name(lchan), btsb->t3105_ms); + lchan->ho.t3105.cb = ho_t3105_cb; + lchan->ho.t3105.data = lchan; + osmo_timer_schedule(&lchan->ho.t3105, 0, btsb->t3105_ms * 1000); +} + +/* received frist valid data frame on dedicated channel */ +void handover_frame(struct gsm_lchan *lchan) +{ + LOGP(DHO, LOGL_INFO, + "%s First valid frame detected\n", gsm_lchan_name(lchan)); + handover_frame(lchan); +} + /* release handover state */ void handover_reset(struct gsm_lchan *lchan) { diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 11222b183..53ad45bac 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -1577,6 +1577,15 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) return 0; } +/** + * Modify the given lchan in the handover scenario. This is a lot like + * second channel activation but with some additional activation. + */ +int bts_model_rsl_chan_mod(struct gsm_lchan *lchan) +{ + return -1; +} + int bts_model_rsl_chan_rel(struct gsm_lchan *lchan) { /* A duplicate RF Release Request, ignore it */ diff --git a/tests/stubs.c b/tests/stubs.c index c0955f3a0..53aa434ea 100644 --- a/tests/stubs.c +++ b/tests/stubs.c @@ -37,6 +37,8 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) { return 0; } int bts_model_rsl_mode_modify(struct gsm_lchan *lchan) { return 0; } +int bts_model_rsl_chan_mod(struct gsm_lchan *lchan) +{ return 0; } void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, unsigned int rtp_pl_len) {}