2014-01-23 15:00:11 +00:00
|
|
|
/* Paging message encoding + queue management */
|
|
|
|
|
|
|
|
/* (C) 2012-2013 by Harald Welte <laforge@gnumonks.org>
|
|
|
|
* Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* (C) 2014 by Holger Hans Peter Freyther
|
|
|
|
*
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2024-02-17 09:17:14 +00:00
|
|
|
* GNU Affero General Public License for more details.
|
2014-01-23 15:00:11 +00:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
|
|
|
#include <osmocom/gsm/rsl.h>
|
|
|
|
|
|
|
|
#include <osmo-bts/bts.h>
|
|
|
|
#include <osmo-bts/bts_model.h>
|
|
|
|
#include <osmo-bts/rsl.h>
|
|
|
|
#include <osmo-bts/logging.h>
|
|
|
|
#include <osmo-bts/handover.h>
|
2013-09-01 07:19:45 +00:00
|
|
|
#include <osmo-bts/l1sap.h>
|
2014-01-23 15:00:11 +00:00
|
|
|
|
2014-01-23 15:12:04 +00:00
|
|
|
/* 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;
|
|
|
|
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_INFO, "Sending PHYSICAL INFORMATION to MS.\n");
|
2014-01-23 15:12:04 +00:00
|
|
|
|
|
|
|
/* 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;
|
2021-09-09 14:38:07 +00:00
|
|
|
msgb_put_u8(msg, lchan->ta_ctrl.current);
|
2014-01-23 15:12:04 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_INFO, "T3105 timeout (%d resends left)\n",
|
|
|
|
bts->ny1 - lchan->ho.phys_info_count);
|
2014-01-23 15:12:04 +00:00
|
|
|
|
|
|
|
if (lchan->state != LCHAN_S_ACTIVE) {
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_NOTICE, "is in not active. It is in state %s. Ignoring\n",
|
|
|
|
gsm_lchans_name(lchan->state));
|
2014-01-23 15:12:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-17 11:22:40 +00:00
|
|
|
if (lchan->ho.phys_info_count >= bts->ny1) {
|
2014-01-23 15:12:04 +00:00
|
|
|
/* HO Abort */
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_NOTICE, "NY1 reached, sending CONNection FAILure to BSC.\n");
|
2014-01-23 15:12:04 +00:00
|
|
|
rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ho_tx_phys_info(lchan);
|
|
|
|
lchan->ho.phys_info_count++;
|
2018-03-17 11:22:40 +00:00
|
|
|
osmo_timer_schedule(&lchan->ho.t3105, 0, bts->t3105_ms * 1000);
|
2014-01-23 15:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
/* Ignore invalid handover ref */
|
|
|
|
if (lchan->ho.ref != ra) {
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_INFO, "RACH on dedicated channel received, but "
|
|
|
|
"ra=0x%02x != expected ref=0x%02x. (This is no bug)\n", ra, lchan->ho.ref);
|
2014-01-23 15:12:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-01 16:47:45 +00:00
|
|
|
/* Ignore handover on channels other than DCCH and SACCH */
|
|
|
|
if (lchan->type != GSM_LCHAN_SDCCH && lchan->type != GSM_LCHAN_TCH_H &&
|
|
|
|
lchan->type != GSM_LCHAN_TCH_F) {
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_ERROR, "handover RACH received on %s?!\n",
|
|
|
|
gsm_lchant_name(lchan->type));
|
2017-03-01 16:47:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_NOTICE, "RACH on dedicated channel type %s received with "
|
|
|
|
"TA=%u, ref=%u\n", gsm_lchant_name(lchan->type), acc_delay, ra);
|
2014-01-23 15:12:04 +00:00
|
|
|
|
|
|
|
/* Set timing advance */
|
2021-09-09 14:38:07 +00:00
|
|
|
lchan->ta_ctrl.current = acc_delay;
|
2020-11-04 13:31:41 +00:00
|
|
|
lchan->want_dl_sacch_active = true;
|
2014-01-23 15:12:04 +00:00
|
|
|
|
|
|
|
/* Stop handover detection, wait for valid frame */
|
|
|
|
lchan->ho.active = HANDOVER_WAIT_FRAME;
|
2013-09-01 07:19:45 +00:00
|
|
|
if (l1sap_chan_modify(lchan->ts->trx, gsm_lchan2chan_nr(lchan)) != 0) {
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_ERROR, "failed to modify channel after handover\n");
|
2014-01-23 15:12:04 +00:00
|
|
|
rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send HANDover DETect to BSC */
|
2021-09-09 14:38:07 +00:00
|
|
|
rsl_tx_hando_det(lchan, &lchan->ta_ctrl.current);
|
2014-01-23 15:12:04 +00:00
|
|
|
|
|
|
|
/* Send PHYS INFO */
|
|
|
|
lchan->ho.phys_info_count = 1;
|
|
|
|
ho_tx_phys_info(lchan);
|
|
|
|
|
|
|
|
/* Start T3105 */
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_DEBUG, "Starting T3105 with %u ms\n", bts->t3105_ms);
|
2014-01-23 15:12:04 +00:00
|
|
|
lchan->ho.t3105.cb = ho_t3105_cb;
|
|
|
|
lchan->ho.t3105.data = lchan;
|
2018-03-17 11:22:40 +00:00
|
|
|
osmo_timer_schedule(&lchan->ho.t3105, 0, bts->t3105_ms * 1000);
|
2014-01-23 15:12:04 +00:00
|
|
|
}
|
|
|
|
|
2019-10-13 17:09:39 +00:00
|
|
|
/* received first valid data frame on dedicated channel */
|
2014-01-23 15:12:04 +00:00
|
|
|
void handover_frame(struct gsm_lchan *lchan)
|
|
|
|
{
|
2019-05-20 23:14:24 +00:00
|
|
|
LOGPLCHAN(lchan, DHO, LOGL_INFO, "First valid frame detected\n");
|
2014-04-19 17:22:22 +00:00
|
|
|
handover_reset(lchan);
|
2014-01-23 15:12:04 +00:00
|
|
|
}
|
|
|
|
|
2014-01-23 15:00:11 +00:00
|
|
|
/* release handover state */
|
|
|
|
void handover_reset(struct gsm_lchan *lchan)
|
|
|
|
{
|
|
|
|
/* Stop T3105 */
|
|
|
|
osmo_timer_del(&lchan->ho.t3105);
|
|
|
|
|
|
|
|
/* Handover process is done */
|
|
|
|
lchan->ho.active = HANDOVER_NONE;
|
|
|
|
}
|