From 57c5a884937098116d1ca0188a10b15ccca0ea52 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 30 May 2013 11:31:40 +0200 Subject: HO: Move handover config from GSMNET to BTS node This is required for individual BTS configuration. --- include/osmocom/bsc/gsm_data.h | 17 --- include/osmocom/bsc/gsm_data_shared.h | 18 +++ src/libbsc/bsc_vty.c | 233 +++++++++++++++++----------------- src/libbsc/handover_decision.c | 16 +-- src/libbsc/handover_logic.c | 4 +- src/libcommon/gsm_data.c | 8 -- src/libcommon/gsm_data_shared.c | 10 ++ src/libmsc/mncc_builtin.c | 23 ++-- 8 files changed, 163 insertions(+), 166 deletions(-) diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 874150535..de31e37a9 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -130,7 +130,6 @@ struct gsm_subscriber_connection { /* for assignment handling */ struct osmo_timer_list T10; struct gsm_lchan *secondary_lchan; - }; @@ -212,22 +211,6 @@ struct gsm_network { int a5_encryption; int neci; int send_mm_info; - struct { - int active; - /* Window RXLEV averaging */ - unsigned int win_rxlev_avg; /* number of SACCH frames */ - /* Window RXQUAL averaging */ - unsigned int win_rxqual_avg; /* number of SACCH frames */ - /* Window RXLEV neighbouring cells averaging */ - unsigned int win_rxlev_avg_neigh; /* number of SACCH frames */ - - /* how often should we check for power budget HO */ - unsigned int pwr_interval; /* SACCH frames */ - /* how much better does a neighbor cell have to be ? */ - unsigned int pwr_hysteresis; /* dBm */ - /* maximum distacne before we try a handover */ - unsigned int max_distance; /* TA values */ - } handover; struct gsmnet_stats stats; diff --git a/include/osmocom/bsc/gsm_data_shared.h b/include/osmocom/bsc/gsm_data_shared.h index 07fa9823d..0639c81e0 100644 --- a/include/osmocom/bsc/gsm_data_shared.h +++ b/include/osmocom/bsc/gsm_data_shared.h @@ -720,6 +720,24 @@ struct gsm_bts { /* full and half rate multirate config */ struct amr_multirate_conf mr_full; struct amr_multirate_conf mr_half; + + /* handover config */ + struct { + int active; + /* Window RXLEV averaging */ + unsigned int win_rxlev_avg; /* number of SACCH frames */ + /* Window RXQUAL averaging */ + unsigned int win_rxqual_avg; /* number of SACCH frames */ + /* Window RXLEV neighbouring cells averaging */ + unsigned int win_rxlev_avg_neigh; /* number of SACCH frames */ + + /* how often should we check for power budget HO */ + unsigned int pwr_interval; /* SACCH frames */ + /* how much better does a neighbor cell have to be ? */ + unsigned int pwr_hysteresis; /* dBm */ + /* maximum distacne before we try a handover */ + unsigned int max_distance; /* TA values */ + } handover; #endif /* ROLE_BSC */ void *role; }; diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c index e41d4de4c..8fbe7e502 100644 --- a/src/libbsc/bsc_vty.c +++ b/src/libbsc/bsc_vty.c @@ -199,8 +199,6 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off", VTY_NEWLINE); - vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off", - VTY_NEWLINE); network_chan_load(&pl, net); vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE); dump_pchan_load_vty(vty, " ", &pl); @@ -301,6 +299,8 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); e1isl_dump_vty(vty, bts->oml_link); } + vty_out(vty, " Handover: %s%s", bts->handover.active ? "On" : "Off", + VTY_NEWLINE); /* FIXME: chan_desc */ memset(&pl, 0, sizeof(pl)); @@ -711,6 +711,20 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, "auto%s", VTY_NEWLINE); } + vty_out(vty, " handover %u%s", bts->handover.active, VTY_NEWLINE); + vty_out(vty, " handover window rxlev averaging %u%s", + bts->handover.win_rxlev_avg, VTY_NEWLINE); + vty_out(vty, " handover window rxqual averaging %u%s", + bts->handover.win_rxqual_avg, VTY_NEWLINE); + vty_out(vty, " handover window rxlev neighbor averaging %u%s", + bts->handover.win_rxlev_avg_neigh, VTY_NEWLINE); + vty_out(vty, " handover power budget interval %u%s", + bts->handover.pwr_interval, VTY_NEWLINE); + vty_out(vty, " handover power budget hysteresis %u%s", + bts->handover.pwr_hysteresis, VTY_NEWLINE); + vty_out(vty, " handover maximum distance %u%s", + bts->handover.max_distance, VTY_NEWLINE); + config_write_bts_gprs(vty, bts); if (bts->excl_from_rf_lock) @@ -752,19 +766,6 @@ static int config_write_net(struct vty *vty) vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), VTY_NEWLINE); vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); - vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE); - vty_out(vty, " handover window rxlev averaging %u%s", - gsmnet->handover.win_rxlev_avg, VTY_NEWLINE); - vty_out(vty, " handover window rxqual averaging %u%s", - gsmnet->handover.win_rxqual_avg, VTY_NEWLINE); - vty_out(vty, " handover window rxlev neighbor averaging %u%s", - gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE); - vty_out(vty, " handover power budget interval %u%s", - gsmnet->handover.pwr_interval, VTY_NEWLINE); - vty_out(vty, " handover power budget hysteresis %u%s", - gsmnet->handover.pwr_hysteresis, VTY_NEWLINE); - vty_out(vty, " handover maximum distance %u%s", - gsmnet->handover.max_distance, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -1392,100 +1393,6 @@ DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd, return CMD_SUCCESS; } -#define HANDOVER_STR "Handover Options\n" - -DEFUN(cfg_net_handover, cfg_net_handover_cmd, - "handover (0|1)", - HANDOVER_STR - "Don't perform in-call handover\n" - "Perform in-call handover\n") -{ - int enable = atoi(argv[0]); - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - - if (enable && ipacc_rtp_direct) { - vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode " - "is enabled by using the -P command line option%s", - VTY_NEWLINE); - return CMD_WARNING; - } - gsmnet->handover.active = enable; - - return CMD_SUCCESS; -} - -#define HO_WIN_STR HANDOVER_STR "Measurement Window\n" -#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n" -#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n" -#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n" -#define HO_AVG_COUNT_STR "Amount to use for Averaging\n" - -DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd, - "handover window rxlev averaging <1-10>", - HO_WIN_RXLEV_STR - "How many RxLev measurements are used for averaging\n" - HO_AVG_COUNT_STR) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.win_rxlev_avg = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd, - "handover window rxqual averaging <1-10>", - HO_WIN_RXQUAL_STR - "How many RxQual measurements are used for averaging\n" - HO_AVG_COUNT_STR) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.win_rxqual_avg = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd, - "handover window rxlev neighbor averaging <1-10>", - HO_WIN_RXLEV_STR "Neighbor\n" - "How many RxQual measurements are used for averaging\n" - HO_AVG_COUNT_STR) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd, - "handover power budget interval <1-99>", - HO_PBUDGET_STR - "How often to check if we have a better cell (SACCH frames)\n" - "Interval\n" "Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.pwr_interval = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd, - "handover power budget hysteresis <0-999>", - HO_PBUDGET_STR - "How many dB does a neighbor to be stronger to become a HO candidate\n" - "Hysteresis\n" "Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.pwr_hysteresis = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, - "handover maximum distance <0-9999>", - HANDOVER_STR - "How big is the maximum timing advance before HO is forced\n" - "Distance\n" "Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.max_distance = atoi(argv[0]); - return CMD_SUCCESS; -} - DEFUN(cfg_net_pag_any_tch, cfg_net_pag_any_tch_cmd, "paging any use tch (0|1)", @@ -3273,6 +3180,100 @@ DEFUN(cfg_bts_amr_hr_hyst3, cfg_bts_amr_hr_hyst3_cmd, return CMD_SUCCESS; } +#define HANDOVER_STR "Handover Options\n" + +DEFUN(cfg_bts_handover, cfg_bts_handover_cmd, + "handover (0|1)", + HANDOVER_STR + "Don't perform in-call handover\n" + "Perform in-call handover\n") +{ + int enable = atoi(argv[0]); + struct gsm_bts *bts = vty->index; + + if (enable && ipacc_rtp_direct) { + vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode " + "is enabled by using the -P command line option%s", + VTY_NEWLINE); + return CMD_WARNING; + } + bts->handover.active = enable; + + return CMD_SUCCESS; +} + +#define HO_WIN_STR HANDOVER_STR "Measurement Window\n" +#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n" +#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n" +#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n" +#define HO_AVG_COUNT_STR "Amount to use for Averaging\n" + +DEFUN(cfg_bts_ho_win_rxlev_avg, cfg_bts_ho_win_rxlev_avg_cmd, + "handover window rxlev averaging <1-10>", + HO_WIN_RXLEV_STR + "How many RxLev measurements are used for averaging\n" + HO_AVG_COUNT_STR) +{ + struct gsm_bts *bts = vty->index; + bts->handover.win_rxlev_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_win_rxqual_avg, cfg_bts_ho_win_rxqual_avg_cmd, + "handover window rxqual averaging <1-10>", + HO_WIN_RXQUAL_STR + "How many RxQual measurements are used for averaging\n" + HO_AVG_COUNT_STR) +{ + struct gsm_bts *bts = vty->index; + bts->handover.win_rxqual_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_win_rxlev_neigh_avg, cfg_bts_ho_win_rxlev_avg_neigh_cmd, + "handover window rxlev neighbor averaging <1-10>", + HO_WIN_RXLEV_STR "Neighbor\n" + "How many RxQual measurements are used for averaging\n" + HO_AVG_COUNT_STR) +{ + struct gsm_bts *bts = vty->index; + bts->handover.win_rxlev_avg_neigh = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_pwr_interval, cfg_bts_ho_pwr_interval_cmd, + "handover power budget interval <1-99>", + HO_PBUDGET_STR + "How often to check if we have a better cell (SACCH frames)\n" + "Interval\n" "Number\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.pwr_interval = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_pwr_hysteresis, cfg_bts_ho_pwr_hysteresis_cmd, + "handover power budget hysteresis <0-999>", + HO_PBUDGET_STR + "How many dB does a neighbor to be stronger to become a HO candidate\n" + "Hysteresis\n" "Number\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.pwr_hysteresis = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_ho_max_distance, cfg_bts_ho_max_distance_cmd, + "handover maximum distance <0-9999>", + HANDOVER_STR + "How big is the maximum timing advance before HO is forced\n" + "Distance\n" "Number\n") +{ + struct gsm_bts *bts = vty->index; + bts->handover.max_distance = atoi(argv[0]); + return CMD_SUCCESS; +} + #define TRX_TEXT "Radio Transceiver\n" /* per TRX configuration */ @@ -3786,13 +3787,6 @@ int bsc_vty_init(const struct log_info *cat) install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); - install_element(GSMNET_NODE, &cfg_net_handover_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); @@ -3898,6 +3892,13 @@ int bsc_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_amr_hr_hyst2_cmd); install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd); install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd); + install_element(BTS_NODE, &cfg_bts_handover_cmd); + install_element(BTS_NODE, &cfg_bts_ho_win_rxlev_avg_cmd); + install_element(BTS_NODE, &cfg_bts_ho_win_rxqual_avg_cmd); + install_element(BTS_NODE, &cfg_bts_ho_win_rxlev_avg_neigh_cmd); + install_element(BTS_NODE, &cfg_bts_ho_pwr_interval_cmd); + install_element(BTS_NODE, &cfg_bts_ho_pwr_hysteresis_cmd); + install_element(BTS_NODE, &cfg_bts_ho_max_distance_cmd); install_element(BTS_NODE, &cfg_trx_cmd); install_node(&trx_node, dummy_config_write); diff --git a/src/libbsc/handover_decision.c b/src/libbsc/handover_decision.c index 24c0f79cb..81e8b6e55 100644 --- a/src/libbsc/handover_decision.c +++ b/src/libbsc/handover_decision.c @@ -166,7 +166,7 @@ static void process_meas_neigh(struct gsm_meas_rep *mr) /* attempt to do a handover */ static int attempt_handover(struct gsm_meas_rep *mr) { - struct gsm_network *net = mr->lchan->ts->trx->bts->network; + struct gsm_bts *bts = mr->lchan->ts->trx->bts; struct neigh_meas_proc *best_cell = NULL; unsigned int best_better_db = 0; int i, rc; @@ -183,10 +183,10 @@ static int attempt_handover(struct gsm_meas_rep *mr) continue; /* caculate average rxlev for this cell over the window */ - avg = neigh_meas_avg(nmp, net->handover.win_rxlev_avg_neigh); + avg = neigh_meas_avg(nmp, bts->handover.win_rxlev_avg_neigh); /* check if hysteresis is fulfilled */ - if (avg < mr->dl.full.rx_lev + net->handover.pwr_hysteresis) + if (avg < mr->dl.full.rx_lev + bts->handover.pwr_hysteresis) continue; better = avg - mr->dl.full.rx_lev; @@ -201,7 +201,7 @@ static int attempt_handover(struct gsm_meas_rep *mr) LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ", gsm_ts_name(mr->lchan->ts), best_cell->arfcn); - if (!net->handover.active) { + if (!bts->handover.active) { LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); return 0; } @@ -227,7 +227,7 @@ static int attempt_handover(struct gsm_meas_rep *mr) * attempt a handover */ static int process_meas_rep(struct gsm_meas_rep *mr) { - struct gsm_network *net = mr->lchan->ts->trx->bts->network; + struct gsm_bts *bts = mr->lchan->ts->trx->bts; int av_rxlev; /* we currently only do handover for TCH channels */ @@ -244,7 +244,7 @@ static int process_meas_rep(struct gsm_meas_rep *mr) process_meas_neigh(mr); av_rxlev = get_meas_rep_avg(mr->lchan, MEAS_REP_DL_RXLEV_FULL, - net->handover.win_rxlev_avg); + bts->handover.win_rxlev_avg); /* Interference HO */ if (rxlev2dbm(av_rxlev) > -85 && @@ -262,11 +262,11 @@ static int process_meas_rep(struct gsm_meas_rep *mr) return attempt_handover(mr); /* Distance */ - if (mr->ms_l1.ta > net->handover.max_distance) + if (mr->ms_l1.ta > bts->handover.max_distance) return attempt_handover(mr); /* Power Budget AKA Better Cell */ - if ((mr->nr % net->handover.pwr_interval) == 0) + if ((mr->nr % bts->handover.pwr_interval) == 0) return attempt_handover(mr); return 0; diff --git a/src/libbsc/handover_logic.c b/src/libbsc/handover_logic.c index c040c13aa..338b8bb81 100644 --- a/src/libbsc/handover_logic.c +++ b/src/libbsc/handover_logic.c @@ -87,7 +87,7 @@ int bsc_ho_count(struct gsm_bts *bts) llist_for_each_entry(ho, &bsc_handovers, list) { if (!ho->ho_async) continue; - if (ho->new_lchan->bts == bts) + if (ho->new_lchan->ts->trx->bts == bts) count++; } @@ -134,7 +134,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) } ho->old_lchan = old_lchan; ho->new_lchan = new_lchan; - if (old_lchan->bts != bts) { + if (old_lchan->ts->trx->bts != bts) { ho->ho_ref = ho_ref++; ho->ho_async = 1; } diff --git a/src/libcommon/gsm_data.c b/src/libcommon/gsm_data.c index 79a514d14..b1b1ca30c 100644 --- a/src/libcommon/gsm_data.c +++ b/src/libcommon/gsm_data.c @@ -100,14 +100,6 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod net->T3122 = GSM_T3122_DEFAULT; /* FIXME: initialize all other timers! */ - /* default set of handover parameters */ - net->handover.win_rxlev_avg = 10; - net->handover.win_rxqual_avg = 1; - net->handover.win_rxlev_avg_neigh = 10; - net->handover.pwr_interval = 6; - net->handover.pwr_hysteresis = 3; - net->handover.max_distance = 9999; - INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); diff --git a/src/libcommon/gsm_data_shared.c b/src/libcommon/gsm_data_shared.c index 1b0814c49..616b58e7d 100644 --- a/src/libcommon/gsm_data_shared.c +++ b/src/libcommon/gsm_data_shared.c @@ -261,6 +261,16 @@ struct gsm_bts *gsm_bts_alloc(void *ctx) bts->rach_ldavg_slots = -1; bts->paging.free_chans_need = -1; +#ifdef ROLE_BSC + /* default set of handover parameters */ + bts->handover.win_rxlev_avg = 10; + bts->handover.win_rxqual_avg = 1; + bts->handover.win_rxlev_avg_neigh = 10; + bts->handover.pwr_interval = 6; + bts->handover.pwr_hysteresis = 3; + bts->handover.max_distance = 9999; +#endif + return bts; } diff --git a/src/libmsc/mncc_builtin.c b/src/libmsc/mncc_builtin.c index d20f41046..8dc482dc9 100644 --- a/src/libmsc/mncc_builtin.c +++ b/src/libmsc/mncc_builtin.c @@ -249,7 +249,6 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *connect) { struct gsm_mncc connect_ack, frame_recv; - struct gsm_network *net = call->net; struct gsm_call *remote; uint32_t refs[2]; @@ -276,20 +275,14 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type, return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs); /* proxy mode */ - if (!net->handover.active) { - /* in the no-handover case, we can bridge, i.e. use - * the old RTP proxy code */ - return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs); - } else { - /* in case of handover, we need to re-write the RTP - * SSRC, sequence and timestamp values and thus - * need to enable RTP receive for both directions */ - memset(&frame_recv, 0, sizeof(struct gsm_mncc)); - frame_recv.callref = call->callref; - mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv); - frame_recv.callref = call->remote_ref; - return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv); - } + /* in case of handover, we need to re-write the RTP + * SSRC, sequence and timestamp values and thus + * need to enable RTP receive for both directions */ + memset(&frame_recv, 0, sizeof(struct gsm_mncc)); + frame_recv.callref = call->callref; + mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv); + frame_recv.callref = call->remote_ref; + return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv); } static int mncc_disc_ind(struct gsm_call *call, int msg_type, -- cgit v1.2.3