blob: c73ecb74bffdec81a22a88554359885a024b5f78 [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>
Neels Hofmeyr62427422018-07-24 16:18:15 +020034#include <osmocom/bsc/gsm_04_08_rr.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
Andreas Eversbergdf65c9a2013-05-30 10:29:36 +020068static int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
69{
70 struct gsm_bts_trx_ts *ts;
71 int j, ss;
72 int count = 0;
73
74 if (!trx_is_usable(trx))
75 return 0;
76
77 for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
78 enum gsm_phys_chan_config ts_pchan_is;
79 ts = &trx->ts[j];
80 if (!ts_is_usable(ts))
81 continue;
82
83 ts_pchan_is = ts_pchan(ts);
84
85 if (ts_pchan_is == GSM_PCHAN_PDCH) {
86 /* Dynamic timeslots in PDCH mode will become TCH if needed. */
87 switch (ts->pchan) {
88 case GSM_PCHAN_TCH_F_PDCH:
89 if (pchan == GSM_PCHAN_TCH_F)
90 count++;
91 continue;
92
93 case GSM_PCHAN_TCH_F_TCH_H_PDCH:
94 if (pchan == GSM_PCHAN_TCH_F)
95 count++;
96 else if (pchan == GSM_PCHAN_TCH_H)
97 count += 2;
98 continue;
99
100 default:
101 /* Not dynamic, not applicable. */
102 continue;
103 }
104 }
105
106 if (ts_pchan_is != pchan)
107 continue;
108 /* check if all sub-slots are allocated yet */
109 for (ss = 0; ss < ts_subslots(ts); ss++) {
110 struct gsm_lchan *lc = &ts->lchan[ss];
111 if (lc->type == GSM_LCHAN_NONE &&
112 lc->state == LCHAN_S_NONE)
113 count++;
114 }
115 }
116
117 return count;
118}
119
120/* Count number of free TS of given pchan type */
121int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
122{
123 struct gsm_bts_trx *trx;
124 int count = 0;
125
126 llist_for_each_entry(trx, &bts->trx_list, list)
127 count += trx_count_free_ts(trx, pchan);
128
129 return count;
130}
131
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200132static bool ts_usable_as_pchan(struct gsm_bts_trx_ts *ts,
133 enum gsm_phys_chan_config as_pchan)
134{
135 switch (ts->pchan) {
136 case GSM_PCHAN_TCH_F_PDCH:
137 if (ts->flags & TS_F_PDCH_PENDING_MASK) {
138 /* currently being switched over. Not usable. */
139 return false;
140 }
141 switch (as_pchan) {
142 case GSM_PCHAN_TCH_F:
143 case GSM_PCHAN_PDCH:
144 /* continue to check below. */
145 break;
146 default:
147 return false;
148 }
149 break;
150
151 case GSM_PCHAN_TCH_F_TCH_H_PDCH:
152 if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
153 /* currently being switched over. Not usable. */
154 return false;
155 }
156 switch (as_pchan) {
157 case GSM_PCHAN_TCH_F:
158 case GSM_PCHAN_TCH_H:
159 case GSM_PCHAN_PDCH:
160 /* continue to check below. */
161 break;
162 default:
163 return false;
164 }
165 break;
166
167 default:
168 /* static timeslots never switch. */
169 return ts->pchan == as_pchan;
170 }
171
172 /* Dynamic timeslots -- Checks depending on the current actual pchan mode: */
173 switch (ts_pchan(ts)) {
174 case GSM_PCHAN_NONE:
175 /* Not initialized, possibly because GPRS was disabled. We may switch. */
176 return true;
177
178 case GSM_PCHAN_PDCH:
179 /* This slot is in PDCH mode and available to switch pchan mode. But check for
180 * error states: */
181 if (ts->lchan->state != LCHAN_S_NONE && ts->lchan->state != LCHAN_S_ACTIVE)
182 return false;
183 return true;
184
185 case GSM_PCHAN_TCH_F:
186 case GSM_PCHAN_TCH_H:
187 /* No need to switch at all? */
188 if (ts_pchan(ts) == as_pchan)
189 return true;
190
191 /* If any lchan is in use, we can't change the pchan kind */
192 {
193 int ss;
194 int subslots = ts_subslots(ts);
195 for (ss = 0; ss < subslots; ss++) {
196 struct gsm_lchan *lc = &ts->lchan[ss];
197 if (lc->type != GSM_LCHAN_NONE || lc->state != LCHAN_S_NONE)
198 return false;
199 }
200 }
201 return true;
202
203 default:
204 /* Not implemented. */
205 return false;
206 }
207}
208
Harald Welte8470bf22008-12-25 23:28:35 +0000209static struct gsm_lchan *
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200210_lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan,
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200211 enum gsm_phys_chan_config as_pchan)
Harald Welte8470bf22008-12-25 23:28:35 +0000212{
Harald Welte8470bf22008-12-25 23:28:35 +0000213 struct gsm_bts_trx_ts *ts;
Andreas Eversberg0434efa2013-10-11 13:05:16 +0200214 int j, start, stop, dir, ss;
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200215 int check_subslots;
Harald Welte88367262009-08-10 13:25:55 +0200216
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200217#define LOGPLCHANALLOC(fmt, args...) \
218 LOGP(DRLL, LOGL_DEBUG, "looking for lchan %s as %s: " fmt, \
219 gsm_pchan_name(pchan), gsm_pchan_name(as_pchan), ## args)
220
221 if (!trx_is_usable(trx)) {
222 LOGPLCHANALLOC("%s trx not usable\n", gsm_trx_name(trx));
Harald Welte4c704542009-12-24 10:10:16 +0100223 return NULL;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200224 }
Harald Welte4c704542009-12-24 10:10:16 +0100225
Andreas Eversberg0434efa2013-10-11 13:05:16 +0200226 if (trx->bts->chan_alloc_reverse) {
227 /* check TS 7..0 */
228 start = 7;
229 stop = -1;
230 dir = -1;
231 } else {
232 /* check TS 0..7 */
233 start = 0;
234 stop = 8;
235 dir = 1;
236 }
237
238 for (j = start; j != stop; j += dir) {
Harald Weltefc0d9522009-08-10 13:46:55 +0200239 ts = &trx->ts[j];
Harald Welte4c704542009-12-24 10:10:16 +0100240 if (!ts_is_usable(ts))
241 continue;
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200242 /* The caller first selects what kind of TS to search in, e.g. looking for exact
243 * GSM_PCHAN_TCH_F, or maybe among dynamic GSM_PCHAN_TCH_F_TCH_H_PDCH... */
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200244 if (ts->pchan != pchan) {
245 LOGPLCHANALLOC("%s is != %s\n", gsm_ts_and_pchan_name(ts),
246 gsm_pchan_name(pchan));
Harald Weltefc0d9522009-08-10 13:46:55 +0200247 continue;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200248 }
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200249 /* 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 +0200250 if (!ts_usable_as_pchan(ts, as_pchan)) {
251 LOGPLCHANALLOC("%s is not usable as %s\n", gsm_ts_and_pchan_name(ts),
252 gsm_pchan_name(as_pchan));
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200253 continue;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200254 }
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200255 /* If we need to switch it, after above check we are also allowed to switch it, and we
256 * will always use the first lchan after the switch. Return that lchan and rely on the
257 * caller to perform the pchan switchover. */
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200258 if (ts_pchan(ts) != as_pchan) {
259 LOGPLCHANALLOC("%s is a match, will switch to %s\n", gsm_ts_and_pchan_name(ts),
260 gsm_pchan_name(as_pchan));
Neels Hofmeyr8825c692016-12-05 16:50:47 +0100261 return ts->lchan;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200262 }
Neels Hofmeyr8825c692016-12-05 16:50:47 +0100263
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200264 /* TS is in desired pchan mode. Go ahead and check for an available lchan. */
265 check_subslots = ts_subslots(ts);
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200266 for (ss = 0; ss < check_subslots; ss++) {
Harald Weltefc0d9522009-08-10 13:46:55 +0200267 struct gsm_lchan *lc = &ts->lchan[ss];
Harald Welte (local)3e460312009-12-27 18:12:29 +0100268 if (lc->type == GSM_LCHAN_NONE &&
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200269 lc->state == LCHAN_S_NONE) {
270 LOGPLCHANALLOC("%s ss=%d is available\n", gsm_ts_and_pchan_name(ts),
271 lc->nr);
Harald Weltefc0d9522009-08-10 13:46:55 +0200272 return lc;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200273 }
274 LOGPLCHANALLOC("%s ss=%d in type=%s,state=%s not suitable\n",
275 gsm_ts_and_pchan_name(ts), lc->nr, gsm_lchant_name(lc->type),
276 gsm_lchans_name(lc->state));
Harald Welte8470bf22008-12-25 23:28:35 +0000277 }
278 }
Harald Weltec0d83b02010-03-28 15:58:03 +0800279
Harald Weltefc0d9522009-08-10 13:46:55 +0200280 return NULL;
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200281#undef LOGPLCHANALLOC
Harald Weltefc0d9522009-08-10 13:46:55 +0200282}
283
284static struct gsm_lchan *
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200285_lc_dyn_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
286 enum gsm_phys_chan_config dyn_as_pchan)
Harald Weltefc0d9522009-08-10 13:46:55 +0200287{
288 struct gsm_bts_trx *trx;
Harald Weltefc0d9522009-08-10 13:46:55 +0200289 struct gsm_lchan *lc;
290
291 if (bts->chan_alloc_reverse) {
292 llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200293 lc = _lc_find_trx(trx, pchan, dyn_as_pchan);
Harald Weltefc0d9522009-08-10 13:46:55 +0200294 if (lc)
295 return lc;
296 }
297 } else {
298 llist_for_each_entry(trx, &bts->trx_list, list) {
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200299 lc = _lc_find_trx(trx, pchan, dyn_as_pchan);
Harald Weltefc0d9522009-08-10 13:46:55 +0200300 if (lc)
301 return lc;
302 }
303 }
304
Harald Weltef86852c2015-01-01 12:46:26 +0100305 return NULL;
Harald Welte8470bf22008-12-25 23:28:35 +0000306}
307
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200308static struct gsm_lchan *
309_lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
310{
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200311 return _lc_dyn_find_bts(bts, pchan, pchan);
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200312}
313
Neels Hofmeyra6685252016-06-06 12:53:25 +0200314/* Allocate a logical channel.
315 *
Neels Hofmeyrc6926d02016-07-14 02:51:13 +0200316 * Dynamic channel types: we always prefer a dedicated TS, and only pick +
317 * switch a dynamic TS if no pure TS of the requested PCHAN is available.
318 *
319 * TCH_F/PDCH: if we pick a PDCH ACT style dynamic TS as TCH/F channel, PDCH
320 * will be disabled in rsl_chan_activate_lchan(); there is no need to check
321 * whether PDCH mode is currently active, here.
Neels Hofmeyra6685252016-06-06 12:53:25 +0200322 */
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800323struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
324 int allow_bigger)
Harald Welte8470bf22008-12-25 23:28:35 +0000325{
326 struct gsm_lchan *lchan = NULL;
Harald Welte30f1f372014-12-28 15:00:45 +0100327 enum gsm_phys_chan_config first, first_cbch, second, second_cbch;
Harald Welte8470bf22008-12-25 23:28:35 +0000328
Pau Espin Pedrol18a4ae82018-05-30 12:49:47 +0200329 LOGP(DRLL, LOGL_DEBUG, "(bts=%d) lchan_alloc(%s)\n", bts->nr, gsm_lchant_name(type));
Neels Hofmeyra70084b2018-05-03 16:16:03 +0200330
Harald Welte8470bf22008-12-25 23:28:35 +0000331 switch (type) {
332 case GSM_LCHAN_SDCCH:
Harald Welte65676fe2009-08-10 14:44:24 +0200333 if (bts->chan_alloc_reverse) {
334 first = GSM_PCHAN_SDCCH8_SACCH8C;
Harald Welte30f1f372014-12-28 15:00:45 +0100335 first_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200336 second = GSM_PCHAN_CCCH_SDCCH4;
Harald Welte30f1f372014-12-28 15:00:45 +0100337 second_cbch = GSM_PCHAN_CCCH_SDCCH4_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200338 } else {
339 first = GSM_PCHAN_CCCH_SDCCH4;
Harald Welte30f1f372014-12-28 15:00:45 +0100340 first_cbch = GSM_PCHAN_CCCH_SDCCH4_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200341 second = GSM_PCHAN_SDCCH8_SACCH8C;
Harald Welte30f1f372014-12-28 15:00:45 +0100342 second_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH;
Harald Welte65676fe2009-08-10 14:44:24 +0200343 }
344
345 lchan = _lc_find_bts(bts, first);
Harald Welte8470bf22008-12-25 23:28:35 +0000346 if (lchan == NULL)
Harald Welte30f1f372014-12-28 15:00:45 +0100347 lchan = _lc_find_bts(bts, first_cbch);
348 if (lchan == NULL)
Harald Welte65676fe2009-08-10 14:44:24 +0200349 lchan = _lc_find_bts(bts, second);
Harald Welte30f1f372014-12-28 15:00:45 +0100350 if (lchan == NULL)
351 lchan = _lc_find_bts(bts, second_cbch);
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800352
353 /* allow to assign bigger channels */
354 if (allow_bigger) {
355 if (lchan == NULL) {
356 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200357 if (lchan)
358 type = GSM_LCHAN_TCH_H;
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800359 }
360
361 if (lchan == NULL) {
362 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200363 if (lchan)
364 type = GSM_LCHAN_TCH_F;
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800365 }
Neels Hofmeyra6685252016-06-06 12:53:25 +0200366
367 /* try dynamic TCH/F_PDCH */
368 if (lchan == NULL) {
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200369 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,
370 GSM_PCHAN_TCH_F);
Neels Hofmeyra6685252016-06-06 12:53:25 +0200371 /* TCH/F_PDCH will be used as TCH/F */
372 if (lchan)
373 type = GSM_LCHAN_TCH_F;
374 }
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200375
376 /* try fully dynamic TCH/F_TCH/H_PDCH */
377 if (lchan == NULL) {
378 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_TCH_H_PDCH,
379 GSM_PCHAN_TCH_H);
380 if (lchan)
381 type = GSM_LCHAN_TCH_H;
382 }
383 /*
384 * No need to check fully dynamic channels for TCH/F:
385 * if no TCH/H was available, neither will be TCH/F.
386 */
Holger Hans Peter Freyther457c2a82010-09-06 08:58:42 +0800387 }
Harald Welte8470bf22008-12-25 23:28:35 +0000388 break;
389 case GSM_LCHAN_TCH_F:
Harald Weltefc0d9522009-08-10 13:46:55 +0200390 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
Harald Weltea4c63b02014-05-18 22:23:26 +0200391 /* If we don't have TCH/F available, fall-back to TCH/H */
392 if (!lchan) {
393 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200394 if (lchan)
395 type = GSM_LCHAN_TCH_H;
Harald Weltea4c63b02014-05-18 22:23:26 +0200396 }
Neels Hofmeyra6685252016-06-06 12:53:25 +0200397 /* If we don't have TCH/H either, try dynamic TCH/F_PDCH */
398 if (!lchan) {
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200399 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,
400 GSM_PCHAN_TCH_F);
Neels Hofmeyra6685252016-06-06 12:53:25 +0200401 /* TCH/F_PDCH used as TCH/F -- here, type is already
402 * set to GSM_LCHAN_TCH_F, but for clarity's sake... */
403 if (lchan)
404 type = GSM_LCHAN_TCH_F;
405 }
Neels Hofmeyr5f0c71b2016-07-23 20:15:28 +0200406
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200407 /* Try fully dynamic TCH/F_TCH/H_PDCH as TCH/F... */
Neels Hofmeyr5f0c71b2016-07-23 20:15:28 +0200408 if (!lchan && bts->network->dyn_ts_allow_tch_f) {
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200409 lchan = _lc_dyn_find_bts(bts,
410 GSM_PCHAN_TCH_F_TCH_H_PDCH,
411 GSM_PCHAN_TCH_F);
412 if (lchan)
413 type = GSM_LCHAN_TCH_F;
414 }
415 /* ...and as TCH/H. */
416 if (!lchan) {
417 lchan = _lc_dyn_find_bts(bts,
418 GSM_PCHAN_TCH_F_TCH_H_PDCH,
419 GSM_PCHAN_TCH_H);
420 if (lchan)
421 type = GSM_LCHAN_TCH_H;
422 }
Harald Welte8470bf22008-12-25 23:28:35 +0000423 break;
424 case GSM_LCHAN_TCH_H:
Alexander Couzensfbd96f52016-08-29 18:40:02 +0200425 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
Harald Welte210c8502009-12-12 20:58:20 +0100426 /* If we don't have TCH/H available, fall-back to TCH/F */
Harald Welte487e6be2009-12-12 21:16:38 +0100427 if (!lchan) {
Harald Welte210c8502009-12-12 20:58:20 +0100428 lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
Neels Hofmeyrf5713a52016-06-06 12:57:22 +0200429 if (lchan)
430 type = GSM_LCHAN_TCH_F;
Harald Welte487e6be2009-12-12 21:16:38 +0100431 }
Neels Hofmeyrfdd9ad72016-07-14 03:01:24 +0200432 /* No dedicated TCH/x available -- try fully dynamic
433 * TCH/F_TCH/H_PDCH */
434 if (!lchan) {
435 lchan = _lc_dyn_find_bts(bts,
436 GSM_PCHAN_TCH_F_TCH_H_PDCH,
437 GSM_PCHAN_TCH_H);
438 if (lchan)
439 type = GSM_LCHAN_TCH_H;
440 }
441 /*
442 * No need to check TCH/F_TCH/H_PDCH channels for TCH/F:
443 * if no TCH/H was available, neither will be TCH/F.
444 */
Neels Hofmeyra6685252016-06-06 12:53:25 +0200445 /* If we don't have TCH/F either, try dynamic TCH/F_PDCH */
446 if (!lchan) {
Neels Hofmeyr4281b7d2018-05-08 01:31:19 +0200447 lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,
448 GSM_PCHAN_TCH_F);
Neels Hofmeyra6685252016-06-06 12:53:25 +0200449 if (lchan)
450 type = GSM_LCHAN_TCH_F;
451 }
Harald Welte8470bf22008-12-25 23:28:35 +0000452 break;
453 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100454 LOGP(DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type);
Harald Welte8470bf22008-12-25 23:28:35 +0000455 }
456
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000457 if (lchan) {
Harald Welte8470bf22008-12-25 23:28:35 +0000458 lchan->type = type;
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000459
Neels Hofmeyrd1c0e372016-07-25 12:33:02 +0200460 LOGP(DRLL, LOGL_INFO, "%s Allocating lchan=%u as %s\n",
461 gsm_ts_and_pchan_name(lchan->ts),
462 lchan->nr, gsm_lchant_name(lchan->type));
463
Andreas Eversberg970b4342013-06-01 16:46:39 +0200464 /* reset measurement report counter and index */
465 lchan->meas_rep_count = 0;
466 lchan->meas_rep_idx = 0;
Neels Hofmeyr35ba85c2018-02-12 16:47:40 +0100467 lchan->meas_rep_last_seen_nr = 255;
Andreas Eversberg970b4342013-06-01 16:46:39 +0200468
Holger Hans Peter Freyther5ba6f482009-10-28 14:23:39 +0100469 /* clear sapis */
Holger Hans Peter Freyther45b02432009-11-18 22:59:51 +0100470 memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
Holger Hans Peter Freyther5ba6f482009-10-28 14:23:39 +0100471
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100472 /* clear multi rate config */
Andreas Eversberg73266522014-01-19 11:47:44 +0100473 memset(&lchan->mr_ms_lv, 0, sizeof(lchan->mr_ms_lv));
474 memset(&lchan->mr_bts_lv, 0, sizeof(lchan->mr_bts_lv));
Holger Hans Peter Freyther454140e2014-12-28 12:08:28 +0100475 lchan->broken_reason = "";
Harald Weltec0d83b02010-03-28 15:58:03 +0800476 } else {
477 struct challoc_signal_data sig;
Neels Hofmeyrd1c0e372016-07-25 12:33:02 +0200478
Pau Espin Pedrol18a4ae82018-05-30 12:49:47 +0200479 LOGP(DRLL, LOGL_ERROR, "(bts=%d) Failed to allocate %s channel\n",
480 bts->nr, gsm_lchant_name(type));
Neels Hofmeyrd1c0e372016-07-25 12:33:02 +0200481
Harald Weltec0d83b02010-03-28 15:58:03 +0800482 sig.bts = bts;
483 sig.type = type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200484 osmo_signal_dispatch(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig);
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000485 }
Harald Welte8470bf22008-12-25 23:28:35 +0000486
487 return lchan;
488}
489
490/* Free a logical channel */
491void lchan_free(struct gsm_lchan *lchan)
492{
Harald Weltec0d83b02010-03-28 15:58:03 +0800493 struct challoc_signal_data sig;
Harald Welted12b0fd2009-12-15 21:36:05 +0100494 int i;
495
Harald Weltec0d83b02010-03-28 15:58:03 +0800496 sig.type = lchan->type;
Harald Welte8470bf22008-12-25 23:28:35 +0000497 lchan->type = GSM_LCHAN_NONE;
Holger Hans Peter Freyther2412a072010-06-28 15:47:12 +0800498
499
Neels Hofmeyr968c1422018-05-04 23:01:01 +0200500 if (lchan->conn
501 && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
502 && lchan->ts->dyn.pchan_is != lchan->ts->dyn.pchan_want)) {
Holger Hans Peter Freyther08eebd52010-12-27 13:28:20 +0100503 struct lchan_signal_data sig;
504
Holger Hans Peter Freyther2412a072010-06-28 15:47:12 +0800505 /* We might kill an active channel... */
Holger Hans Peter Freyther08eebd52010-12-27 13:28:20 +0100506 sig.lchan = lchan;
507 sig.mr = NULL;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200508 osmo_signal_dispatch(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, &sig);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000509 }
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000510
511 /* stop the timer */
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200512 osmo_timer_del(&lchan->T3101);
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000513
Harald Welted12b0fd2009-12-15 21:36:05 +0100514 /* clear cached measuement reports */
515 lchan->meas_rep_idx = 0;
516 for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) {
517 lchan->meas_rep[i].flags = 0;
518 lchan->meas_rep[i].nr = 0;
519 }
Harald Weltef7c28b02009-12-21 13:30:17 +0100520 for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
521 lchan->neigh_meas[i].arfcn = 0;
Harald Welted12b0fd2009-12-15 21:36:05 +0100522
Holger Hans Peter Freyther5ba05f42010-06-22 12:11:59 +0800523 if (lchan->rqd_ref) {
524 talloc_free(lchan->rqd_ref);
525 lchan->rqd_ref = NULL;
526 lchan->rqd_ta = 0;
527 }
528
Harald Weltec0d83b02010-03-28 15:58:03 +0800529 sig.lchan = lchan;
530 sig.bts = lchan->ts->trx->bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200531 osmo_signal_dispatch(SS_CHALLOC, S_CHALLOC_FREED, &sig);
Harald Weltec0d83b02010-03-28 15:58:03 +0800532
Neels Hofmeyr968c1422018-05-04 23:01:01 +0200533 if (lchan->conn
534 && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
535 && lchan->ts->dyn.pchan_is != lchan->ts->dyn.pchan_want)) {
Holger Hans Peter Freyther40494552010-06-28 17:09:29 +0800536 LOGP(DRLL, LOGL_ERROR, "the subscriber connection should be gone.\n");
Holger Hans Peter Freyther2412a072010-06-28 15:47:12 +0800537 lchan->conn = NULL;
538 }
539
Harald Welte8470bf22008-12-25 23:28:35 +0000540 /* FIXME: ts_free() the timeslot, if we're the last logical
541 * channel using it */
Philipp Maier12f79f62018-07-18 10:48:15 +0200542
543 /* reset RTP voice connection related data */
544 memset(&lchan->abis_ip, 0, sizeof(lchan->abis_ip));
Harald Welte8470bf22008-12-25 23:28:35 +0000545}
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000546
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200547/*
548 * There was an error with the TRX and we need to forget
549 * any state so that a lchan can be allocated again after
550 * the trx is fully usable.
Holger Hans Peter Freytherf7a1c232010-06-22 12:19:06 +0800551 *
552 * This should be called after lchan_free to force a channel
553 * be available for allocation again. This means that this
554 * method will stop the "delay after error"-timer and set the
555 * state to LCHAN_S_NONE.
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200556 */
557void lchan_reset(struct gsm_lchan *lchan)
558{
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200559 osmo_timer_del(&lchan->T3101);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100560 osmo_timer_del(&lchan->T3109);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200561 osmo_timer_del(&lchan->T3111);
562 osmo_timer_del(&lchan->error_timer);
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200563
564 lchan->type = GSM_LCHAN_NONE;
Maxdc10ce92017-09-06 18:20:36 +0200565 rsl_lchan_set_state(lchan, LCHAN_S_NONE);
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200566}
567
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800568/* Drive the release process of the lchan */
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100569static void _lchan_handle_release(struct gsm_lchan *lchan,
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100570 int sacch_deact, int mode)
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800571{
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100572 /* Release all SAPIs on the local end and continue */
573 rsl_release_sapis_from(lchan, 1, RSL_REL_LOCAL_END);
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800574
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100575 /*
576 * Shall we send a RR Release, start T3109 and wait for the
577 * release indication from the BTS or just take it down (e.g.
578 * on assignment requests)
579 */
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100580 if (sacch_deact) {
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800581 gsm48_send_rr_release(lchan);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100582
583 /* Deactivate the SACCH on the BTS side */
584 rsl_deact_sacch(lchan);
585 rsl_start_t3109(lchan);
Holger Hans Peter Freyther006e3d82012-12-25 23:45:14 +0100586 } else if (lchan->sapis[0] == LCHAN_SAPI_UNUSED) {
587 rsl_direct_rf_release(lchan);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100588 } else {
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100589 rsl_release_request(lchan, 0, mode);
Holger Hans Peter Freytherb3489392011-12-28 16:21:05 +0100590 }
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800591}
Holger Hans Peter Freyther135f7972010-04-15 11:21:02 +0200592
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000593/* Consider releasing the channel now */
Holger Hans Peter Freyther5ca825e2012-12-06 12:01:38 +0100594int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode mode)
Holger Freytherc6ea9db2008-12-30 19:18:21 +0000595{
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800596 DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan));
Holger Hans Peter Freyther63d18b52010-04-10 00:14:55 +0200597 rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
Holger Hans Peter Freyther4b85a322010-07-29 17:09:36 +0800598
Holger Hans Peter Freytherabf962b2010-11-14 16:04:46 +0100599 lchan->conn = NULL;
Holger Hans Peter Freyther85825352011-12-27 22:24:17 +0100600 _lchan_handle_release(lchan, sacch_deact, mode);
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000601 return 1;
602}
603
Neels Hofmeyr2afffd52016-09-25 17:01:20 +0200604void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
Harald Welteb908cb72009-12-22 13:09:29 +0100605{
606 struct gsm_bts_trx *trx;
607
608 llist_for_each_entry(trx, &bts->trx_list, list) {
609 int i;
610
611 /* skip administratively deactivated tranxsceivers */
Harald Welted64c0bc2011-05-30 12:07:53 +0200612 if (!nm_is_running(&trx->mo.nm_state) ||
613 !nm_is_running(&trx->bb_transc.mo.nm_state))
Harald Welteb908cb72009-12-22 13:09:29 +0100614 continue;
615
616 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
617 struct gsm_bts_trx_ts *ts = &trx->ts[i];
618 struct load_counter *pl = &cl->pchan[ts->pchan];
619 int j;
Neels Hofmeyr36733802016-07-29 18:10:59 +0200620 int subslots;
Harald Welteb908cb72009-12-22 13:09:29 +0100621
622 /* skip administratively deactivated timeslots */
Harald Welted64c0bc2011-05-30 12:07:53 +0200623 if (!nm_is_running(&ts->mo.nm_state))
Harald Welteb908cb72009-12-22 13:09:29 +0100624 continue;
625
Neels Hofmeyr36733802016-07-29 18:10:59 +0200626 subslots = ts_subslots(ts);
627 for (j = 0; j < subslots; j++) {
Harald Welteb908cb72009-12-22 13:09:29 +0100628 struct gsm_lchan *lchan = &ts->lchan[j];
629
630 pl->total++;
631
632 switch (lchan->state) {
633 case LCHAN_S_NONE:
634 break;
635 default:
636 pl->used++;
637 break;
638 }
639 }
640 }
641 }
642}
643
644void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
645{
646 struct gsm_bts *bts;
647
648 memset(pl, 0, sizeof(*pl));
649
650 llist_for_each_entry(bts, &net->bts_list, list)
Neels Hofmeyr2afffd52016-09-25 17:01:20 +0200651 bts_chan_load(pl, bts);
Harald Welteb908cb72009-12-22 13:09:29 +0100652}
Neels Hofmeyr2afffd52016-09-25 17:01:20 +0200653
Stefan Sperling6cee8932018-01-30 18:14:22 +0100654/* Update T3122 wait indicator based on samples of BTS channel load. */
655void
656bts_update_t3122_chan_load(struct gsm_bts *bts)
657{
658 struct pchan_load pl;
659 uint64_t used = 0;
660 uint32_t total = 0;
661 uint64_t load;
662 uint64_t wait_ind;
663 static const uint8_t min_wait_ind = GSM_T3122_DEFAULT;
664 static const uint8_t max_wait_ind = 128; /* max wait ~2 minutes */
665 int i;
666
Neels Hofmeyrf802f7f2018-02-15 18:46:39 +0100667 /* Ignore BTS that are not in operation, in order to not flood the log with "bogus channel load"
668 * messages */
669 if (!trx_is_usable(bts->c0))
670 return;
671
Stefan Sperling6cee8932018-01-30 18:14:22 +0100672 /* Sum up current load across all channels. */
673 memset(&pl, 0, sizeof(pl));
674 bts_chan_load(&pl, bts);
675 for (i = 0; i < ARRAY_SIZE(pl.pchan); i++) {
676 struct load_counter *lc = &pl.pchan[i];
677
678 /* Ignore samples too large for fixed-point calculations (shouldn't happen). */
679 if (lc->used > UINT16_MAX || lc->total > UINT16_MAX) {
680 LOGP(DRLL, LOGL_NOTICE, "(bts=%d) numbers in channel load sample "
681 "too large (used=%u / total=%u)\n", bts->nr, lc->used, lc->total);
682 continue;
683 }
684
685 used += lc->used;
686 total += lc->total;
687 }
688
689 /* Check for invalid samples (shouldn't happen). */
690 if (total == 0 || used > total) {
Pau Espin Pedrolfa422552018-04-19 14:31:13 +0200691 LOGP(DRLL, LOGL_NOTICE, "(bts=%d) bogus channel load sample (used=%"PRIu64" / total=%"PRIu32")\n",
Stefan Sperling6cee8932018-01-30 18:14:22 +0100692 bts->nr, used, total);
693 bts->T3122 = 0; /* disable override of network-wide default value */
694 bts->chan_load_samples_idx = 0; /* invalidate other samples collected so far */
695 return;
696 }
697
698 /* If we haven't got enough samples yet, store measurement for later use. */
699 if (bts->chan_load_samples_idx < ARRAY_SIZE(bts->chan_load_samples)) {
700 struct load_counter *sample = &bts->chan_load_samples[bts->chan_load_samples_idx++];
701 sample->total = (unsigned int)total;
702 sample->used = (unsigned int)used;
703 return;
704 }
705
706 /* We have enough samples and will overwrite our current samples later. */
707 bts->chan_load_samples_idx = 0;
708
709 /* Add all previous samples to the current sample. */
710 for (i = 0; i < ARRAY_SIZE(bts->chan_load_samples); i++) {
711 struct load_counter *sample = &bts->chan_load_samples[i];
712 total += sample->total;
713 used += sample->used;
714 }
715
716 used <<= 8; /* convert to fixed-point */
717
718 /* Log channel load average. */
719 load = ((used / total) * 100);
Stefan Sperling5b6aa652018-04-09 13:31:51 +0200720 LOGP(DRLL, LOGL_DEBUG, "(bts=%d) channel load average is %"PRIu64".%.2"PRIu64"%%\n",
Stefan Sperling6cee8932018-01-30 18:14:22 +0100721 bts->nr, (load & 0xffffff00) >> 8, (load & 0xff) / 10);
Stefan Sperling6442e432018-02-06 14:44:54 +0100722 bts->chan_load_avg = ((load & 0xffffff00) >> 8);
723 OSMO_ASSERT(bts->chan_load_avg <= 100);
724 osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_LOAD_AVERAGE], bts->chan_load_avg);
Stefan Sperling6cee8932018-01-30 18:14:22 +0100725
726 /* Calculate new T3122 wait indicator. */
727 wait_ind = ((used / total) * max_wait_ind);
728 wait_ind >>= 8; /* convert from fixed-point to integer */
729 if (wait_ind < min_wait_ind)
730 wait_ind = min_wait_ind;
731 else if (wait_ind > max_wait_ind)
732 wait_ind = max_wait_ind;
733
Pau Espin Pedrolfa422552018-04-19 14:31:13 +0200734 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 +0100735 bts->T3122 = (uint8_t)wait_ind;
Stefan Sperling81dc9e72018-02-05 17:34:36 +0100736 osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_T3122], wait_ind);
Stefan Sperling6cee8932018-01-30 18:14:22 +0100737}