/* BTS support code common to all supported BTS models */ /* (C) 2011 by Andreas Eversberg * (C) 2011 by Harald Welte * * 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 * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct gsm_network bts_gsmnet = { .bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list }, .num_bts = 0, }; /* Table 3.1 TS 04.08: Values of parameter S */ static const uint8_t tx_integer[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 25, 32, 50, }; static const uint8_t s_values[][2] = { { 55, 41 }, { 76, 52 }, { 109, 58 }, { 163, 86 }, { 217, 115 }, }; void *tall_bts_ctx; int bts_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; struct gsm_bts_trx *trx; int rc; /* add to list of BTSs */ llist_add_tail(&bts->list, &bts_gsmnet.bts_list); bts->band = GSM_BAND_1800; bts->role = btsb = talloc_zero(bts, struct gsm_bts_role_bts); INIT_LLIST_HEAD(&btsb->agch_queue); /* configurable via VTY */ btsb->paging_state = paging_init(btsb, 200, 0); /* configurable via OML */ btsb->load.ccch.load_ind_period = 112; load_timer_start(bts); btsb->rtp_jitter_buf_ms = 100; btsb->max_ta = 63; btsb->ny1 = 4; btsb->t3105_ms = 300; /* default RADIO_LINK_TIMEOUT */ btsb->radio_link_timeout = 32; /* set BTS to dependency */ oml_mo_state_init(&bts->mo, -1, NM_AVSTATE_DEPENDENCY); oml_mo_state_init(&bts->gprs.nse.mo, -1, NM_AVSTATE_DEPENDENCY); oml_mo_state_init(&bts->gprs.cell.mo, -1, NM_AVSTATE_DEPENDENCY); oml_mo_state_init(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_DEPENDENCY); oml_mo_state_init(&bts->gprs.nsvc[1].mo, -1, NM_AVSTATE_DEPENDENCY); /* initialize bts data structure */ llist_for_each_entry(trx, &bts->trx_list, list) { int i; for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { struct gsm_bts_trx_ts *ts = &trx->ts[i]; int k; for (k = 0; k < ARRAY_SIZE(ts->lchan); k++) { struct gsm_lchan *lchan = &ts->lchan[k]; INIT_LLIST_HEAD(&lchan->dl_tch_queue); } } } osmo_rtp_init(tall_bts_ctx); rc = bts_model_init(bts); if (rc < 0) { llist_del(&bts->list); return rc; } bts_gsmnet.num_bts++; return rc; } static void shutdown_timer_cb(void *data) { fprintf(stderr, "Shutdown timer expired\n"); exit(42); } static struct osmo_timer_list shutdown_timer = { .cb = &shutdown_timer_cb, }; void bts_shutdown(struct gsm_bts *bts, const char *reason) { struct gsm_bts_trx *trx; if (osmo_timer_pending(&shutdown_timer)) { LOGP(DOML, LOGL_NOTICE, "BTS is already being shutdown.\n"); return; } LOGP(DOML, LOGL_NOTICE, "Shutting down BTS %u, Reason %s\n", bts->nr, reason); llist_for_each_entry(trx, &bts->trx_list, list) { bts_model_trx_deact_rf(trx); bts_model_trx_close(trx); } /* shedule a timer to make sure select loop logic can run again * to dispatch any pending primitives */ osmo_timer_schedule(&shutdown_timer, 3, 0); } /* main link is established, send status report */ int bts_link_estab(struct gsm_bts *bts) { int i, j; LOGP(DSUM, LOGL_INFO, "Main link established, sending Status'.\n"); /* BTS and SITE MGR are EAABLED, BTS is DEPENDENCY */ oml_tx_state_changed(&bts->site_mgr.mo); oml_tx_state_changed(&bts->mo); /* those should all be in DEPENDENCY */ oml_tx_state_changed(&bts->gprs.nse.mo); oml_tx_state_changed(&bts->gprs.cell.mo); oml_tx_state_changed(&bts->gprs.nsvc[0].mo); oml_tx_state_changed(&bts->gprs.nsvc[1].mo); /* All other objects start off-line until the BTS Model code says otherwise */ for (i = 0; i < bts->num_trx; i++) { struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i); oml_tx_state_changed(&trx->mo); oml_tx_state_changed(&trx->bb_transc.mo); for (j = 0; j < ARRAY_SIZE(trx->ts); j++) { struct gsm_bts_trx_ts *ts = &trx->ts[j]; oml_tx_state_changed(&ts->mo); } } return bts_model_oml_estab(bts); } /* RSL link is established, send status report */ int trx_link_estab(struct gsm_bts_trx *trx) { struct e1inp_sign_link *link = trx->rsl_link; uint8_t radio_state = link ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED; LOGP(DSUM, LOGL_INFO, "RSL link (TRX %02x) state changed to %s, sending Status'.\n", trx->nr, link ? "up" : "down"); oml_mo_state_chg(&trx->mo, radio_state, NM_AVSTATE_OK); if (link) rsl_tx_rf_res(trx); else bts_model_trx_deact_rf(trx); return 0; } int lchan_init_lapdm(struct gsm_lchan *lchan) { struct lapdm_channel *lc = &lchan->lapdm_ch; lapdm_channel_init(lc, LAPDM_MODE_BTS); lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY); lapdm_channel_set_l1(lc, NULL, lchan); lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan); return 0; } int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm48_system_information_type_3 *si3; uint8_t T, S, agch_num, i; uint8_t T_group = 0; uint8_t ccch_comb = 0; /* calculate length of agch queue agch_queue_len = ( min( T3126 ) / 51 ) * bs_ag_blks_res min(T3126) = T + 2*S defined in 04.08 11.1.1 S and T are defined in 04.08 3.3.1.1.2 */ si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3); T = si3->rach_control.tx_integer; for (i = 0; i < 15; i++) { if (tx_integer[i] == T) { T_group = i % 5; break; } } if (si3->control_channel_desc.ccch_conf == 1) { ccch_comb = 1; } S = s_values[T_group][ccch_comb]; agch_num = si3->control_channel_desc.bs_ag_blks_res; btsb->agch_queue_len = ((T + 2 * S) / 51) * agch_num; if (btsb->agch_queue_count >= btsb->agch_queue_len) { LOGP(DRSL, LOGL_NOTICE, "AGCH enqueue count = %d >= %d (drop message)\n", btsb->agch_queue_count, btsb->agch_queue_len); return -ENOMEM; } msgb_enqueue(&btsb->agch_queue, msg); btsb->agch_queue_count++; return 0; } struct msgb *bts_agch_dequeue(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct msgb *msg = msgb_dequeue(&btsb->agch_queue); if (msg) btsb->agch_queue_count--; return msg; } int bts_supports_cipher(struct gsm_bts_role_bts *bts, int rsl_cipher) { int sup; if (rsl_cipher < 1 || rsl_cipher > 8) return -ENOTSUP; /* No encryption is always supported */ if (rsl_cipher == 1) return 1; sup = (1 << (rsl_cipher - 2)) & bts->support.ciphers; return sup > 0; } struct gsm_time *get_time(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts->role; return &btsb->gsm_time; }