blob: 4eccff0df812b1cb64459d91ab3c92fd6ec9688b [file] [log] [blame]
Harald Welte8470bf22008-12-25 23:28:35 +00001/* GSM Channel allocation routines
2 *
3 * (C) 2008 by Harald Welte <laforge@gnumonks.org>
Holger Freythere64a7a32009-02-06 21:55:37 +00004 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte8470bf22008-12-25 23:28:35 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte8470bf22008-12-25 23:28:35 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte8470bf22008-12-25 23:28:35 +000020 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <errno.h>
Stefan Sperling5b6aa652018-04-09 13:31:51 +020027#include <inttypes.h>
Harald Welte8470bf22008-12-25 23:28:35 +000028
Neels Hofmeyrc0164792017-09-04 15:15:32 +020029#include <osmocom/bsc/chan_alloc.h>
30#include <osmocom/bsc/abis_nm.h>
31#include <osmocom/bsc/abis_rsl.h>
32#include <osmocom/bsc/debug.h>
Neels Hofmeyrc0164792017-09-04 15:15:32 +020033#include <osmocom/bsc/signal.h>
34#include <osmocom/bsc/gsm_04_08_utils.h>
Holger Freytherc6ea9db2008-12-30 19:18:21 +000035
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010036#include <osmocom/core/talloc.h>
Holger Hans Peter Freyther5ba05f42010-06-22 12:11:59 +080037
Andreas Eversberg7c41cd12013-06-02 10:36:53 +020038bool ts_is_usable(const struct gsm_bts_trx_ts *ts)
Harald Welte4c704542009-12-24 10:10:16 +010039{
Neels Hofmeyra70084b2018-05-03 16:16:03 +020040 if (!trx_is_usable(ts->trx)) {
41 LOGP(DRLL, LOGL_DEBUG, "%s not usable\n", gsm_trx_name(ts->trx));
Max6e4f1842018-01-07 16:45:42 +010042 return false;
Neels Hofmeyra70084b2018-05-03 16:16:03 +020043 }
Harald Welte4c704542009-12-24 10:10:16 +010044
Neels Hofmeyrc6926d02016-07-14 02:51:13 +020045 /* If a TCH/F_PDCH TS is busy changing, it is already taken or not
Neels Hofmeyr832afa32016-06-14 13:12:00 +020046 * yet available. */
47 if (ts->pchan == GSM_PCHAN_TCH_F_PDCH) {
Neels Hofmeyra70084b2018-05-03 16:16:03 +020048 if (ts->flags & TS_F_PDCH_PENDING_MASK) {
49 LOGP(DRLL, LOGL_DEBUG, "%s in switchover, not available\n",
50 gsm_ts_and_pchan_name(ts));
Maxd0ff6942017-11-29 12:45:34 +010051 return false;
Neels Hofmeyra70084b2018-05-03 16:16:03 +020052 }
Neels Hofmeyr832afa32016-06-14 13:12:00 +020053 }
54
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +020055 /* If a dynamic channel is busy changing, it is already taken or not
56 * yet available. */
57 if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
Neels Hofmeyra70084b2018-05-03 16:16:03 +020058 if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
59 LOGP(DRLL, LOGL_DEBUG, "%s in switchover, not available\n",
60 gsm_ts_and_pchan_name(ts));
Maxd0ff6942017-11-29 12:45:34 +010061 return false;
Neels Hofmeyra70084b2018-05-03 16:16:03 +020062 }
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +020063 }
64
Maxd0ff6942017-11-29 12:45:34 +010065 return true;
Harald Welte4c704542009-12-24 10:10:16 +010066}
67
Maxd0ff6942017-11-29 12:45:34 +010068bool trx_is_usable(const struct gsm_bts_trx *trx)
Harald Welte4c704542009-12-24 10:10:16 +010069{
70 /* FIXME: How does this behave for BS-11 ? */
71 if (is_ipaccess_bts(trx->bts)) {
Harald Welted64c0bc2011-05-30 12:07:53 +020072 if (!nm_is_running(&trx->mo.nm_state) ||
73 !nm_is_running(&trx->bb_transc.mo.nm_state))
Maxd0ff6942017-11-29 12:45:34 +010074 return false;
Harald Welte4c704542009-12-24 10:10:16 +010075 }
76
Maxd0ff6942017-11-29 12:45:34 +010077 return true;
Harald Welte4c704542009-12-24 10:10:16 +010078}
79
Andreas Eversbergdf65c9a2013-05-30 10:29:36 +020080static int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
81{
82 struct gsm_bts_trx_ts *ts;
83 int j, ss;
84 int count = 0;
85
86 if (!trx_is_usable(trx))
87 return 0;
88
89 for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
90 enum gsm_phys_chan_config ts_pchan_is;
91 ts = &trx->ts[j];
92 if (!ts_is_usable(ts))
93 continue;
94
95 ts_pchan_is = ts_pchan(ts);
96
97 if (ts_pchan_is == GSM_PCHAN_PDCH) {
98 /* Dynamic timeslots in PDCH mode will become TCH if needed. */
99 switch (ts->pchan) {
100 case GSM_PCHAN_TCH_F_PDCH:
101 if (pchan == GSM_PCHAN_TCH_F)
102 count++;
103 continue;
104
105 case GSM_PCHAN_TCH_F_TCH_H_PDCH:
106 if (pchan == GSM_PCHAN_TCH_F)
107 count++;
108 else if (pchan == GSM_PCHAN_TCH_H)
109 count += 2;
110 continue;
111
112 default:
113 /* Not dynamic, not applicable. */
114 continue;
115 }
116 }
117
118 if (ts_pchan_is != pchan)
119 continue;
120 /* check if all sub-slots are allocated yet */
121 for (ss = 0; ss < ts_subslots(ts); ss++) {
122 struct gsm_lchan *lc = &ts->lchan[ss];
123 if (lc->type == GSM_LCHAN_NONE &&
124 lc->state == LCHAN_S_NONE)
125 count++;
126 }
127 }
128
129 return count;
130}
131
132/* Count number of free TS of given pchan type */
133int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
134{
135 struct gsm_bts_trx *trx;
136 int count = 0;
137
138 llist_for_each_entry(trx, &bts->trx_list, list)
139 count += trx_count_free_ts(trx, pchan);
140
141 return count;
142}
143
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200144static bool ts_usable_as_pchan(struct gsm_bts_trx_ts *ts,
145 enum gsm_phys_chan_config as_pchan)
146{
147 switch (ts->pchan) {
148 case GSM_PCHAN_TCH_F_PDCH:
149 if (ts->flags & TS_F_PDCH_PENDING_MASK) {
150 /* currently being switched over. Not usable. */
151 return false;
152 }
153 switch (as_pchan) {
154 case GSM_PCHAN_TCH_F:
155 case GSM_PCHAN_PDCH:
156 /* continue to check below. */
157 break;
158 default:
159 return false;
160 }
161 break;
162
163 case GSM_PCHAN_TCH_F_TCH_H_PDCH:
164 if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
165 /* currently being switched over. Not usable. */
166 return false;
167 }
168 switch (as_pchan) {
169 case GSM_PCHAN_TCH_F:
170 case GSM_PCHAN_TCH_H:
171 case GSM_PCHAN_PDCH:
172 /* continue to check below. */
173 break;
174 default:
175 return false;
176 }
177 break;
178
179 default:
180 /* static timeslots never switch. */
181 return ts->pchan == as_pchan;
182 }
183
184 /* Dynamic timeslots -- Checks depending on the current actual pchan mode: */
185 switch (ts_pchan(ts)) {
186 case GSM_PCHAN_NONE:
187 /* Not initialized, possibly because GPRS was disabled. We may switch. */
188 return true;
189
190 case GSM_PCHAN_PDCH:
191 /* This slot is in PDCH mode and available to switch pchan mode. But check for
192 * error states: */
193 if (ts->lchan->state != LCHAN_S_NONE && ts->lchan->state != LCHAN_S_ACTIVE)
194 return false;
195 return true;
196
197 case GSM_PCHAN_TCH_F:
198 case GSM_PCHAN_TCH_H:
199 /* No need to switch at all? */
200 if (ts_pchan(ts) == as_pchan)
201 return true;
202
203 /* If any lchan is in use, we can't change the pchan kind */
204 {
205 int ss;
206 int subslots = ts_subslots(ts);
207 for (ss = 0; ss < subslots; ss++) {
208 struct gsm_lchan *lc = &ts->lchan[ss];
209 if (lc->type != GSM_LCHAN_NONE || lc->state != LCHAN_S_NONE)
210 return false;
211 }
212 }
213 return true;
214
215 default:
216 /* Not implemented. */
217 return false;
218 }
219}
220
Harald Welte8470bf22008-12-25 23:28:35 +0000221static struct gsm_lchan *
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200222_lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan,
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200223 enum gsm_phys_chan_config as_pchan)
Harald Welte8470bf22008-12-25 23:28:35 +0000224{
Harald Welte8470bf22008-12-25 23:28:35 +0000225 struct gsm_bts_trx_ts *ts;
Andreas Eversberg0434efa2013-10-11 13:05:16 +0200226 int j, start, stop, dir, ss;
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200227 int check_subslots;
Harald Welte88367262009-08-10 13:25:55 +0200228
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200229#define LOGPLCHANALLOC(fmt, args...) \
230 LOGP(DRLL, LOGL_DEBUG, "looking for lchan %s as %s: " fmt, \
231 gsm_pchan_name(pchan), gsm_pchan_name(as_pchan), ## args)
232
233 if (!trx_is_usable(trx)) {
234 LOGPLCHANALLOC("%s trx not usable\n", gsm_trx_name(trx));
Harald Welte4c704542009-12-24 10:10:16 +0100235 return NULL;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200236 }
Harald Welte4c704542009-12-24 10:10:16 +0100237
Andreas Eversberg0434efa2013-10-11 13:05:16 +0200238 if (trx->bts->chan_alloc_reverse) {
239 /* check TS 7..0 */
240 start = 7;
241 stop = -1;
242 dir = -1;
243 } else {
244 /* check TS 0..7 */
245 start = 0;
246 stop = 8;
247 dir = 1;
248 }
249
250 for (j = start; j != stop; j += dir) {
Harald Weltefc0d9522009-08-10 13:46:55 +0200251 ts = &trx->ts[j];
Harald Welte4c704542009-12-24 10:10:16 +0100252 if (!ts_is_usable(ts))
253 continue;
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200254 /* The caller first selects what kind of TS to search in, e.g. looking for exact
255 * GSM_PCHAN_TCH_F, or maybe among dynamic GSM_PCHAN_TCH_F_TCH_H_PDCH... */
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200256 if (ts->pchan != pchan) {
257 LOGPLCHANALLOC("%s is != %s\n", gsm_ts_and_pchan_name(ts),
258 gsm_pchan_name(pchan));
Harald Weltefc0d9522009-08-10 13:46:55 +0200259 continue;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200260 }
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200261 /* Next, is this timeslot in or can it be switched to the pchan we want to use it for? */
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200262 if (!ts_usable_as_pchan(ts, as_pchan)) {
263 LOGPLCHANALLOC("%s is not usable as %s\n", gsm_ts_and_pchan_name(ts),
264 gsm_pchan_name(as_pchan));
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200265 continue;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200266 }
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200267 /* If we need to switch it, after above check we are also allowed to switch it, and we
268 * will always use the first lchan after the switch. Return that lchan and rely on the
269 * caller to perform the pchan switchover. */
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200270 if (ts_pchan(ts) != as_pchan) {
271 LOGPLCHANALLOC("%s is a match, will switch to %s\n", gsm_ts_and_pchan_name(ts),
272 gsm_pchan_name(as_pchan));
Neels Hofmeyr8825c692016-12-05 16:50:47 +0100273 return ts->lchan;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200274 }
Neels Hofmeyr8825c692016-12-05 16:50:47 +0100275
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200276 /* TS is in desired pchan mode. Go ahead and check for an available lchan. */
277 check_subslots = ts_subslots(ts);
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200278 for (ss = 0; ss < check_subslots; ss++) {
Harald Weltefc0d9522009-08-10 13:46:55 +0200279 struct gsm_lchan *lc = &ts->lchan[ss];
Harald Welte (local)3e460312009-12-27 18:12:29 +0100280 if (lc->type == GSM_LCHAN_NONE &&
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200281 lc->state == LCHAN_S_NONE) {
282 LOGPLCHANALLOC("%s ss=%d is available\n", gsm_ts_and_pchan_name(ts),
283 lc->nr);
Harald Weltefc0d9522009-08-10 13:46:55 +0200284 return lc;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200285 }
286 LOGPLCHANALLOC("%s ss=%d in type=%s,state=%s not suitable\n",
287 gsm_ts_and_pchan_name(ts), lc->nr, gsm_lchant_name(lc->type),
288 gsm_lchans_name(lc->state));
Harald Welte8470bf22008-12-25 23:28:35 +0000289 }
290 }
Harald Weltec0d83b02010-03-28 15:58:03 +0800291
Harald Weltefc0d9522009-08-10 13:46:55 +0200292 return NULL;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200293#undef LOGPLCHANALLOC
Harald Weltefc0d9522009-08-10 13:46:55 +0200294}
295
296static struct gsm_lchan *
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200297_lc_dyn_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
298 enum gsm_phys_chan_config dyn_as_pchan)
Harald Weltefc0d9522009-08-10 13:46:55 +0200299{
300 struct gsm_bts_trx *trx;
Harald Weltefc0d9522009-08-10 13:46:55 +0200301 struct gsm_lchan *lc;
302
303 if (bts->chan_alloc_reverse) {
304 llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200305 lc = _lc_find_trx(trx, pchan, dyn_as_pchan);
Harald Weltefc0d9522009-08-10 13:46:55 +0200306 if (lc)
307 return lc;
308 }
309 } else {
310 llist_for_each_entry(trx, &bts->trx_list, list) {
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200311 lc = _lc_find_trx(trx, pchan, dyn_as_pchan);
Harald Weltefc0d9522009-08-10 13:46:55 +0200312 if (lc)
313 return lc;
314 }
315 }
316
Harald Weltef86852c2015-01-01 12:46:26 +0100317 return NULL;
Harald Welte8470bf22008-12-25 23:28:35 +0000318}
319
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200320static struct gsm_lchan *
321_lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
322{
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200323 return _lc_dyn_find_bts(bts, pchan, pchan);
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200324}
325
Neels Hofmeyra6685252016-06-06 12:53:25 +0200326/* Allocate a logical channel.
327 *
Neels Hofmeyrc6926d02016-07-14 02:51:13 +0200328 * Dynamic channel types: we always prefer a dedicated TS, and only pick +
329 * switch a dynamic TS if no pure TS of the requested PCHAN is available.
330 *
331 * TCH_F/PDCH: if we pick a PDCH ACT style dynamic TS as TCH/F channel, PDCH
332 * will be disabled in rsl_chan_activate_lchan(); there is no need to check
333 * whether PDCH mode is currently active, here.
Neels Hofmeyra6685252016-06-06 12:53:25 +0200334 */
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800335struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
336 int allow_bigger)
Harald Welte8470bf22008-12-25 23:28:35 +0000337{
338 struct gsm_lchan *lchan = NULL;
Harald Welte30f1f372014-12-28 15:00:45 +0100339 enum gsm_phys_chan_config first, first_cbch, second, second_cbch;
Harald Welte8470bf22008-12-25 23:28:35 +0000340
Pau Espin Pedrol18a4ae82018-05-30 12:49:47 +0200341 LOGP(DRLL, LOGL_DEBUG, "(bts=%d) lchan_alloc(%s)\n", bts->nr, gsm_lchant_name(type));
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200342
Harald Welte8470bf22008-12-25 23:28:35 +0000343 switch (type) {
344 case GSM_LCHAN_SDCCH:
Harald Welte65676fe2009-08-10 14:44:24 +0200345 if (bts->chan_alloc_reverse) {
346 first = GSM_PCHAN_SDCCH8_SACCH8C;
Harald Welte30f1f372014-12-28 15:00:45 +0100347 first_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200348 second = GSM_PCHAN_CCCH_SDCCH4;
Harald Welte30f1f372014-12-28 15:00:45 +0100349 second_cbch = GSM_PCHAN_CCCH_SDCCH4_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200350 } else {
351 first = GSM_PCHAN_CCCH_SDCCH4;
Harald Welte30f1f372014-12-28 15:00:45 +0100352 first_cbch = GSM_PCHAN_CCCH_SDCCH4_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200353 second = GSM_PCHAN_SDCCH8_SACCH8C;
Harald Welte30f1f372014-12-28 15:00:45 +0100354 second_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200355 }
356
357 lchan = _lc_find_bts(bts, first);
Harald Welte8470bf22008-12-25 23:28:35 +0000358 if (lchan == NULL)
Harald Welte30f1f372014-12-28 15:00:45 +0100359 lchan = _lc_find_bts(bts, first_cbch);
360 if (lchan == NULL)
Harald Welte65676fe2009-08-10 14:44:24 +0200361 lchan = _lc_find_bts(bts, second);
Harald Welte30f1f372014-12-28 15:00:45 +0100362 if (lchan == NULL)
363 lchan = _lc_find_bts(bts, second_cbch);
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800364
365 /* allow to assign bigger channels */
366 if (allow_bigger) {
367 if (lchan == NULL) {
368 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200369 if (lchan)
370 type = GSM_LCHAN_TCH_H;
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800371 }
372
373 if (lchan == NULL) {
374 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200375 if (lchan)
376 type = GSM_LCHAN_TCH_F;
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800377 }
Neels Hofmeyra6685252016-06-06 12:53:25 +0200378
379 /* try dynamic TCH/F_PDCH */
380 if (lchan == NULL) {
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200381 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,
382 GSM_PCHAN_TCH_F);
Neels Hofmeyra6685252016-06-06 12:53:25 +0200383 /* TCH/F_PDCH will be used as TCH/F */
384 if (lchan)
385 type = GSM_LCHAN_TCH_F;
386 }
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200387
388 /* try fully dynamic TCH/F_TCH/H_PDCH */
389 if (lchan == NULL) {
390 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_TCH_H_PDCH,
391 GSM_PCHAN_TCH_H);
392 if (lchan)
393 type = GSM_LCHAN_TCH_H;
394 }
395 /*
396 * No need to check fully dynamic channels for TCH/F:
397 * if no TCH/H was available, neither will be TCH/F.
398 */
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800399 }
Harald Welte8470bf22008-12-25 23:28:35 +0000400 break;
401 case GSM_LCHAN_TCH_F:
Harald Weltefc0d9522009-08-10 13:46:55 +0200402 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
Harald Weltea4c63b02014-05-18 22:23:26 +0200403 /* If we don't have TCH/F available, fall-back to TCH/H */
404 if (!lchan) {
405 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200406 if (lchan)
407 type = GSM_LCHAN_TCH_H;
Harald Weltea4c63b02014-05-18 22:23:26 +0200408 }
Neels Hofmeyra6685252016-06-06 12:53:25 +0200409 /* If we don't have TCH/H either, try dynamic TCH/F_PDCH */
410 if (!lchan) {
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200411 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,
412 GSM_PCHAN_TCH_F);
Neels Hofmeyra6685252016-06-06 12:53:25 +0200413 /* TCH/F_PDCH used as TCH/F -- here, type is already
414 * set to GSM_LCHAN_TCH_F, but for clarity's sake... */
415 if (lchan)
416 type = GSM_LCHAN_TCH_F;
417 }
Neels Hofmeyr5f0c71b2016-07-23 20:15:28 +0200418
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200419 /* Try fully dynamic TCH/F_TCH/H_PDCH as TCH/F... */
Neels Hofmeyr5f0c71b2016-07-23 20:15:28 +0200420 if (!lchan && bts->network->dyn_ts_allow_tch_f) {
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200421 lchan = _lc_dyn_find_bts(bts,
422 GSM_PCHAN_TCH_F_TCH_H_PDCH,
423 GSM_PCHAN_TCH_F);
424 if (lchan)
425 type = GSM_LCHAN_TCH_F;
426 }
427 /* ...and as TCH/H. */
428 if (!lchan) {
429 lchan = _lc_dyn_find_bts(bts,
430 GSM_PCHAN_TCH_F_TCH_H_PDCH,
431 GSM_PCHAN_TCH_H);
432 if (lchan)
433 type = GSM_LCHAN_TCH_H;
434 }
Harald Welte8470bf22008-12-25 23:28:35 +0000435 break;
436 case GSM_LCHAN_TCH_H:
Alexander Couzensfbd96f52016-08-29 18:40:02 +0200437 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
Harald Welte210c8502009-12-12 20:58:20 +0100438 /* If we don't have TCH/H available, fall-back to TCH/F */
Harald Welte487e6be2009-12-12 21:16:38 +0100439 if (!lchan) {
Harald Welte210c8502009-12-12 20:58:20 +0100440 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200441 if (lchan)
442 type = GSM_LCHAN_TCH_F;
Harald Welte487e6be2009-12-12 21:16:38 +0100443 }
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200444 /* No dedicated TCH/x available -- try fully dynamic
445 * TCH/F_TCH/H_PDCH */
446 if (!lchan) {
447 lchan = _lc_dyn_find_bts(bts,
448 GSM_PCHAN_TCH_F_TCH_H_PDCH,
449 GSM_PCHAN_TCH_H);
450 if (lchan)
451 type = GSM_LCHAN_TCH_H;
452 }
453 /*
454 * No need to check TCH/F_TCH/H_PDCH channels for TCH/F:
455 * if no TCH/H was available, neither will be TCH/F.
456 */
Neels Hofmeyra6685252016-06-06 12:53:25 +0200457 /* If we don't have TCH/F either, try dynamic TCH/F_PDCH */
458 if (!lchan) {
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200459 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,
460 GSM_PCHAN_TCH_F);
Neels Hofmeyra6685252016-06-06 12:53:25 +0200461 if (lchan)
462 type = GSM_LCHAN_TCH_F;
463 }
Harald Welte8470bf22008-12-25 23:28:35 +0000464 break;
465 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100466 LOGP(DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type);
Harald Welte8470bf22008-12-25 23:28:35 +0000467 }
468
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000469 if (lchan) {
Harald Welte8470bf22008-12-25 23:28:35 +0000470 lchan->type = type;
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000471
Neels Hofmeyrd1c0e372016-07-25 12:33:02 +0200472 LOGP(DRLL, LOGL_INFO, "%s Allocating lchan=%u as %s\n",
473 gsm_ts_and_pchan_name(lchan->ts),
474 lchan->nr, gsm_lchant_name(lchan->type));
475
Andreas Eversberg970b4342013-06-01 16:46:39 +0200476 /* reset measurement report counter and index */
477 lchan->meas_rep_count = 0;
478 lchan->meas_rep_idx = 0;
Neels Hofmeyr35ba85c2018-02-12 16:47:40 +0100479 lchan->meas_rep_last_seen_nr = 255;
Andreas Eversberg970b4342013-06-01 16:46:39 +0200480
Holger Hans Peter Freyther5ba6f482009-10-28 14:23:39 +0100481 /* clear sapis */
Holger Hans Peter Freyther45b02432009-11-18 22:59:51 +0100482 memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
Holger Hans Peter Freyther5ba6f482009-10-28 14:23:39 +0100483
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100484 /* clear multi rate config */
Andreas Eversberg73266522014-01-19 11:47:44 +0100485 memset(&lchan->mr_ms_lv, 0, sizeof(lchan->mr_ms_lv));
486 memset(&lchan->mr_bts_lv, 0, sizeof(lchan->mr_bts_lv));
Holger Hans Peter Freyther454140e2014-12-28 12:08:28 +0100487 lchan->broken_reason = "";
Harald Weltec0d83b02010-03-28 15:58:03 +0800488 } else {
489 struct challoc_signal_data sig;
Neels Hofmeyrd1c0e372016-07-25 12:33:02 +0200490
Pau Espin Pedrol18a4ae82018-05-30 12:49:47 +0200491 LOGP(DRLL, LOGL_ERROR, "(bts=%d) Failed to allocate %s channel\n",
492 bts->nr, gsm_lchant_name(type));
Neels Hofmeyrd1c0e372016-07-25 12:33:02 +0200493
Harald Weltec0d83b02010-03-28 15:58:03 +0800494 sig.bts = bts;
495 sig.type = type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200496 osmo_signal_dispatch(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig);
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000497 }
Harald Welte8470bf22008-12-25 23:28:35 +0000498
499 return lchan;
500}
501
502/* Free a logical channel */
503void lchan_free(struct gsm_lchan *lchan)
504{
Harald Weltec0d83b02010-03-28 15:58:03 +0800505 struct challoc_signal_data sig;
Harald Welted12b0fd2009-12-15 21:36:05 +0100506 int i;
507
Harald Weltec0d83b02010-03-28 15:58:03 +0800508 sig.type = lchan->type;
Harald Welte8470bf22008-12-25 23:28:35 +0000509 lchan->type = GSM_LCHAN_NONE;
Holger Hans Peter Freyther2412a072010-06-28 15:47:12 +0800510
511
Neels Hofmeyr968c1422018-05-04 23:01:01 +0200512 if (lchan->conn
513 && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
514 && lchan->ts->dyn.pchan_is != lchan->ts->dyn.pchan_want)) {
Holger Hans Peter Freyther08eebd52010-12-27 13:28:20 +0100515 struct lchan_signal_data sig;
516
Holger Hans Peter Freyther2412a072010-06-28 15:47:12 +0800517 /* We might kill an active channel... */
Holger Hans Peter Freyther08eebd52010-12-27 13:28:20 +0100518 sig.lchan = lchan;
519 sig.mr = NULL;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200520 osmo_signal_dispatch(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, &sig);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000521 }
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000522
523 /* stop the timer */
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200524 osmo_timer_del(&lchan->T3101);
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000525
Harald Welted12b0fd2009-12-15 21:36:05 +0100526 /* clear cached measuement reports */
527 lchan->meas_rep_idx = 0;
528 for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) {
529 lchan->meas_rep[i].flags = 0;
530 lchan->meas_rep[i].nr = 0;
531 }
Harald Weltef7c28b02009-12-21 13:30:17 +0100532 for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
533 lchan->neigh_meas[i].arfcn = 0;
Harald Welted12b0fd2009-12-15 21:36:05 +0100534
Holger Hans Peter Freyther5ba05f42010-06-22 12:11:59 +0800535 if (lchan->rqd_ref) {
536 talloc_free(lchan->rqd_ref);
537 lchan->rqd_ref = NULL;
538 lchan->rqd_ta = 0;
539 }
540
Harald Weltec0d83b02010-03-28 15:58:03 +0800541 sig.lchan = lchan;
542 sig.bts = lchan->ts->trx->bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200543 osmo_signal_dispatch(SS_CHALLOC, S_CHALLOC_FREED, &sig);
Harald Weltec0d83b02010-03-28 15:58:03 +0800544
Neels Hofmeyr968c1422018-05-04 23:01:01 +0200545 if (lchan->conn
546 && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
547 && lchan->ts->dyn.pchan_is != lchan->ts->dyn.pchan_want)) {
Holger Hans Peter Freyther40494552010-06-28 17:09:29 +0800548 LOGP(DRLL, LOGL_ERROR, "the subscriber connection should be gone.\n");
Holger Hans Peter Freyther2412a072010-06-28 15:47:12 +0800549 lchan->conn = NULL;
550 }
551
Harald Welte8470bf22008-12-25 23:28:35 +0000552 /* FIXME: ts_free() the timeslot, if we're the last logical
553 * channel using it */
554}
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000555
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200556/*
557 * There was an error with the TRX and we need to forget
558 * any state so that a lchan can be allocated again after
559 * the trx is fully usable.
Holger Hans Peter Freytherf7a1c232010-06-22 12:19:06 +0800560 *
561 * This should be called after lchan_free to force a channel
562 * be available for allocation again. This means that this
563 * method will stop the "delay after error"-timer and set the
564 * state to LCHAN_S_NONE.
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200565 */
566void lchan_reset(struct gsm_lchan *lchan)
567{
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200568 osmo_timer_del(&lchan->T3101);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100569 osmo_timer_del(&lchan->T3109);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200570 osmo_timer_del(&lchan->T3111);
571 osmo_timer_del(&lchan->error_timer);
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200572
573 lchan->type = GSM_LCHAN_NONE;
Maxdc10ce92017-09-06 18:20:36 +0200574 rsl_lchan_set_state(lchan, LCHAN_S_NONE);
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200575}
576
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800577/* Drive the release process of the lchan */
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100578static void _lchan_handle_release(struct gsm_lchan *lchan,
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100579 int sacch_deact, int mode)
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800580{
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100581 /* Release all SAPIs on the local end and continue */
582 rsl_release_sapis_from(lchan, 1, RSL_REL_LOCAL_END);
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800583
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100584 /*
585 * Shall we send a RR Release, start T3109 and wait for the
586 * release indication from the BTS or just take it down (e.g.
587 * on assignment requests)
588 */
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100589 if (sacch_deact) {
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800590 gsm48_send_rr_release(lchan);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100591
592 /* Deactivate the SACCH on the BTS side */
593 rsl_deact_sacch(lchan);
594 rsl_start_t3109(lchan);
Holger Hans Peter Freyther006e3d82012-12-25 23:45:14 +0100595 } else if (lchan->sapis[0] == LCHAN_SAPI_UNUSED) {
596 rsl_direct_rf_release(lchan);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100597 } else {
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100598 rsl_release_request(lchan, 0, mode);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100599 }
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800600}
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200601
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000602/* Consider releasing the channel now */
Holger Hans Peter Freyther5ca825e2012-12-06 12:01:38 +0100603int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode mode)
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000604{
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800605 DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan));
Holger Hans Peter Freyther63d18b52010-04-10 00:14:55 +0200606 rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800607
Holger Hans Peter Freytherabf962b2010-11-14 16:04:46 +0100608 lchan->conn = NULL;
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100609 _lchan_handle_release(lchan, sacch_deact, mode);
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000610 return 1;
611}
612
Neels Hofmeyr2afffd52016-09-25 17:01:20 +0200613void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
Harald Welteb908cb72009-12-22 13:09:29 +0100614{
615 struct gsm_bts_trx *trx;
616
617 llist_for_each_entry(trx, &bts->trx_list, list) {
618 int i;
619
620 /* skip administratively deactivated tranxsceivers */
Harald Welted64c0bc2011-05-30 12:07:53 +0200621 if (!nm_is_running(&trx->mo.nm_state) ||
622 !nm_is_running(&trx->bb_transc.mo.nm_state))
Harald Welteb908cb72009-12-22 13:09:29 +0100623 continue;
624
625 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
626 struct gsm_bts_trx_ts *ts = &trx->ts[i];
627 struct load_counter *pl = &cl->pchan[ts->pchan];
628 int j;
Neels Hofmeyr36733802016-07-29 18:10:59 +0200629 int subslots;
Harald Welteb908cb72009-12-22 13:09:29 +0100630
631 /* skip administratively deactivated timeslots */
Harald Welted64c0bc2011-05-30 12:07:53 +0200632 if (!nm_is_running(&ts->mo.nm_state))
Harald Welteb908cb72009-12-22 13:09:29 +0100633 continue;
634
Neels Hofmeyr36733802016-07-29 18:10:59 +0200635 subslots = ts_subslots(ts);
636 for (j = 0; j < subslots; j++) {
Harald Welteb908cb72009-12-22 13:09:29 +0100637 struct gsm_lchan *lchan = &ts->lchan[j];
638
639 pl->total++;
640
641 switch (lchan->state) {
642 case LCHAN_S_NONE:
643 break;
644 default:
645 pl->used++;
646 break;
647 }
648 }
649 }
650 }
651}
652
653void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
654{
655 struct gsm_bts *bts;
656
657 memset(pl, 0, sizeof(*pl));
658
659 llist_for_each_entry(bts, &net->bts_list, list)
Neels Hofmeyr2afffd52016-09-25 17:01:20 +0200660 bts_chan_load(pl, bts);
Harald Welteb908cb72009-12-22 13:09:29 +0100661}
Neels Hofmeyr2afffd52016-09-25 17:01:20 +0200662
Stefan Sperling6cee8932018-01-30 18:14:22 +0100663/* Update T3122 wait indicator based on samples of BTS channel load. */
664void
665bts_update_t3122_chan_load(struct gsm_bts *bts)
666{
667 struct pchan_load pl;
668 uint64_t used = 0;
669 uint32_t total = 0;
670 uint64_t load;
671 uint64_t wait_ind;
672 static const uint8_t min_wait_ind = GSM_T3122_DEFAULT;
673 static const uint8_t max_wait_ind = 128; /* max wait ~2 minutes */
674 int i;
675
Neels Hofmeyrf802f7f2018-02-15 18:46:39 +0100676 /* Ignore BTS that are not in operation, in order to not flood the log with "bogus channel load"
677 * messages */
678 if (!trx_is_usable(bts->c0))
679 return;
680
Stefan Sperling6cee8932018-01-30 18:14:22 +0100681 /* Sum up current load across all channels. */
682 memset(&pl, 0, sizeof(pl));
683 bts_chan_load(&pl, bts);
684 for (i = 0; i < ARRAY_SIZE(pl.pchan); i++) {
685 struct load_counter *lc = &pl.pchan[i];
686
687 /* Ignore samples too large for fixed-point calculations (shouldn't happen). */
688 if (lc->used > UINT16_MAX || lc->total > UINT16_MAX) {
689 LOGP(DRLL, LOGL_NOTICE, "(bts=%d) numbers in channel load sample "
690 "too large (used=%u / total=%u)\n", bts->nr, lc->used, lc->total);
691 continue;
692 }
693
694 used += lc->used;
695 total += lc->total;
696 }
697
698 /* Check for invalid samples (shouldn't happen). */
699 if (total == 0 || used > total) {
Pau Espin Pedrolfa422552018-04-19 14:31:13 +0200700 LOGP(DRLL, LOGL_NOTICE, "(bts=%d) bogus channel load sample (used=%"PRIu64" / total=%"PRIu32")\n",
Stefan Sperling6cee8932018-01-30 18:14:22 +0100701 bts->nr, used, total);
702 bts->T3122 = 0; /* disable override of network-wide default value */
703 bts->chan_load_samples_idx = 0; /* invalidate other samples collected so far */
704 return;
705 }
706
707 /* If we haven't got enough samples yet, store measurement for later use. */
708 if (bts->chan_load_samples_idx < ARRAY_SIZE(bts->chan_load_samples)) {
709 struct load_counter *sample = &bts->chan_load_samples[bts->chan_load_samples_idx++];
710 sample->total = (unsigned int)total;
711 sample->used = (unsigned int)used;
712 return;
713 }
714
715 /* We have enough samples and will overwrite our current samples later. */
716 bts->chan_load_samples_idx = 0;
717
718 /* Add all previous samples to the current sample. */
719 for (i = 0; i < ARRAY_SIZE(bts->chan_load_samples); i++) {
720 struct load_counter *sample = &bts->chan_load_samples[i];
721 total += sample->total;
722 used += sample->used;
723 }
724
725 used <<= 8; /* convert to fixed-point */
726
727 /* Log channel load average. */
728 load = ((used / total) * 100);
Stefan Sperling5b6aa652018-04-09 13:31:51 +0200729 LOGP(DRLL, LOGL_DEBUG, "(bts=%d) channel load average is %"PRIu64".%.2"PRIu64"%%\n",
Stefan Sperling6cee8932018-01-30 18:14:22 +0100730 bts->nr, (load & 0xffffff00) >> 8, (load & 0xff) / 10);
Stefan Sperling6442e432018-02-06 14:44:54 +0100731 bts->chan_load_avg = ((load & 0xffffff00) >> 8);
732 OSMO_ASSERT(bts->chan_load_avg <= 100);
733 osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_LOAD_AVERAGE], bts->chan_load_avg);
Stefan Sperling6cee8932018-01-30 18:14:22 +0100734
735 /* Calculate new T3122 wait indicator. */
736 wait_ind = ((used / total) * max_wait_ind);
737 wait_ind >>= 8; /* convert from fixed-point to integer */
738 if (wait_ind < min_wait_ind)
739 wait_ind = min_wait_ind;
740 else if (wait_ind > max_wait_ind)
741 wait_ind = max_wait_ind;
742
Pau Espin Pedrolfa422552018-04-19 14:31:13 +0200743 LOGP(DRLL, LOGL_DEBUG, "(bts=%d) T3122 wait indicator set to %"PRIu64" seconds\n", bts->nr, wait_ind);
Stefan Sperling6cee8932018-01-30 18:14:22 +0100744 bts->T3122 = (uint8_t)wait_ind;
Stefan Sperling81dc9e72018-02-05 17:34:36 +0100745 osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_T3122], wait_ind);
Stefan Sperling6cee8932018-01-30 18:14:22 +0100746}