blob: 53d63861233ea398e90ce8b8d9d80eeb879cb3e1 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* GSM Radio Signalling Link messages on the A-bis interface
2 * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
3
Harald Welte8f5e2392009-02-03 12:57:37 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (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
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24#include <stdio.h>
Harald Welte8470bf22008-12-25 23:28:35 +000025#include <stdlib.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <errno.h>
27#include <sys/types.h>
28
Harald Welte8470bf22008-12-25 23:28:35 +000029#include <openbsc/gsm_data.h>
30#include <openbsc/gsm_04_08.h>
31#include <openbsc/abis_rsl.h>
32#include <openbsc/chan_alloc.h>
33#include <openbsc/debug.h>
34#include <openbsc/tlv.h>
Holger Freyther392209c2009-02-10 00:06:19 +000035#include <openbsc/paging.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#define RSL_ALLOC_SIZE 1024
38#define RSL_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000039
Holger Freyther3b72a892009-02-04 00:31:39 +000040#define MAX(a, b) (a) >= (b) ? (a) : (b)
41
Harald Welte52b1f982008-12-23 20:25:15 +000042static u_int8_t mdisc_by_msgtype(u_int8_t msg_type)
43{
44 /* mask off the transparent bit ? */
45 msg_type &= 0xfe;
46
Harald Welte8470bf22008-12-25 23:28:35 +000047 if ((msg_type & 0xf0) == 0x00)
Harald Welte52b1f982008-12-23 20:25:15 +000048 return ABIS_RSL_MDISC_RLL;
Harald Welte8470bf22008-12-25 23:28:35 +000049 if ((msg_type & 0xf0) == 0x10) {
Harald Welte52b1f982008-12-23 20:25:15 +000050 if (msg_type >= 0x19 && msg_type <= 0x22)
51 return ABIS_RSL_MDISC_TRX;
52 else
53 return ABIS_RSL_MDISC_COM_CHAN;
54 }
Harald Welte2d5b6382008-12-27 19:46:06 +000055 if ((msg_type & 0xe0) == 0x20)
Harald Welte52b1f982008-12-23 20:25:15 +000056 return ABIS_RSL_MDISC_DED_CHAN;
57
58 return ABIS_RSL_MDISC_LOC;
59}
60
61static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh,
62 u_int8_t msg_type)
63{
64 dh->c.msg_discr = mdisc_by_msgtype(msg_type);
65 dh->c.msg_type = msg_type;
66 dh->ie_chan = RSL_IE_CHAN_NR;
67}
68
69static inline void init_llm_hdr(struct abis_rsl_rll_hdr *dh,
70 u_int8_t msg_type)
71{
72 /* dh->c.msg_discr = mdisc_by_msgtype(msg_type); */
73 dh->c.msg_discr = ABIS_RSL_MDISC_RLL;
74 dh->c.msg_type = msg_type;
75 dh->ie_chan = RSL_IE_CHAN_NR;
76 dh->ie_link_id = RSL_IE_LINK_IDENT;
77}
78
79
80/* encode channel number as per Section 9.3.1 */
81u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot)
82{
83 u_int8_t ret;
84
85 ret = (timeslot & 0x07) | type;
86
87 switch (type) {
88 case RSL_CHAN_Lm_ACCHs:
89 subch &= 0x01;
90 break;
91 case RSL_CHAN_SDCCH4_ACCH:
92 subch &= 0x07;
93 break;
94 case RSL_CHAN_SDCCH8_ACCH:
95 subch &= 0x07;
96 break;
97 default:
98 /* no subchannels allowed */
99 subch = 0x00;
100 break;
101 }
102 ret |= (subch << 3);
103
104 return ret;
105}
106
Harald Welte8470bf22008-12-25 23:28:35 +0000107/* determine logical channel based on TRX and channel number IE */
108struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr)
109{
110 struct gsm_lchan *lchan;
111 u_int8_t ts_nr = chan_nr & 0x07;
112 u_int8_t cbits = chan_nr >> 3;
113 u_int8_t lch_idx;
114 struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
115
116 if (cbits == 0x01) {
117 lch_idx = 0; /* TCH/F */
118 if (ts->pchan != GSM_PCHAN_TCH_F)
119 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
120 chan_nr, ts->pchan);
121 } else if ((cbits & 0x1e) == 0x02) {
122 lch_idx = cbits & 0x1; /* TCH/H */
123 if (ts->pchan != GSM_PCHAN_TCH_H)
124 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
125 chan_nr, ts->pchan);
126 } else if ((cbits & 0x1c) == 0x04) {
127 lch_idx = cbits & 0x3; /* SDCCH/4 */
128 if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
129 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
130 chan_nr, ts->pchan);
131 } else if ((cbits & 0x18) == 0x08) {
132 lch_idx = cbits & 0x7; /* SDCCH/8 */
133 if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C)
134 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
135 chan_nr, ts->pchan);
136 } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) {
137 lch_idx = 0;
138 if (ts->pchan != GSM_PCHAN_CCCH &&
139 ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
140 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
141 chan_nr, ts->pchan);
142 /* FIXME: we should not return first sdcch4 !!! */
143 } else {
144 fprintf(stderr, "unknown chan_nr=0x%02x\n", chan_nr);
145 return NULL;
146 }
147
148 lchan = &ts->lchan[lch_idx];
149
150 return lchan;
151}
152
153u_int8_t lchan2chan_nr(struct gsm_lchan *lchan)
154{
155 struct gsm_bts_trx_ts *ts = lchan->ts;
156 u_int8_t cbits, chan_nr;
157
158 switch (ts->pchan) {
159 case GSM_PCHAN_TCH_F:
160 cbits = 0x01;
161 break;
162 case GSM_PCHAN_TCH_H:
163 cbits = 0x02;
164 cbits += lchan->nr;
165 break;
166 case GSM_PCHAN_CCCH_SDCCH4:
167 cbits = 0x04;
168 cbits += lchan->nr;
169 break;
170 case GSM_PCHAN_SDCCH8_SACCH8C:
171 cbits = 0x08;
172 cbits += lchan->nr;
173 break;
174 default:
175 case GSM_PCHAN_CCCH:
176 cbits = 0x10;
177 break;
178 }
179
180 chan_nr = (cbits << 3) | (ts->nr & 0x7);
181
182 return chan_nr;
183}
184
Harald Welte52b1f982008-12-23 20:25:15 +0000185/* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */
186u_int64_t str_to_imsi(const char *imsi_str)
187{
188 u_int64_t ret;
189
190 ret = strtoull(imsi_str, NULL, 10);
191
192 return ret;
193}
194
195/* Table 5 Clause 7 TS 05.02 */
196unsigned int n_pag_blocks(int bs_ccch_sdcch_comb, unsigned int bs_ag_blks_res)
197{
198 if (!bs_ccch_sdcch_comb)
199 return 9 - bs_ag_blks_res;
200 else
201 return 3 - bs_ag_blks_res;
202}
203
204/* Chapter 6.5.2 of TS 05.02 */
205unsigned int get_ccch_group(u_int64_t imsi, unsigned int bs_cc_chans,
206 unsigned int n_pag_blocks)
207{
208 return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) / n_pag_blocks;
209}
210
211/* Chapter 6.5.2 of TS 05.02 */
212unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans,
213 int n_pag_blocks)
214{
215 return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) % n_pag_blocks;
216}
217
Harald Welte8470bf22008-12-25 23:28:35 +0000218static struct msgb *rsl_msgb_alloc(void)
219{
220 return msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM);
221}
222
Harald Welte362322e2009-02-15 14:36:38 +0000223#define MACBLOCK_SIZE 23
224static void pad_macblock(u_int8_t *out, const u_int8_t *in, int len)
225{
226 memcpy(out, in, len);
227
228 if (len < MACBLOCK_SIZE)
229 memset(out+len, 0x2b, MACBLOCK_SIZE-len);
230}
231
Harald Welte52b1f982008-12-23 20:25:15 +0000232/* Send a BCCH_INFO message as per Chapter 8.5.1 */
Harald Weltee79769b2009-02-07 00:48:17 +0000233int rsl_bcch_info(struct gsm_bts_trx *trx, u_int8_t type,
Harald Welte52b1f982008-12-23 20:25:15 +0000234 const u_int8_t *data, int len)
235{
236 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000237 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000238
239 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof*dh);
240 init_dchan_hdr(dh, RSL_MT_BCCH_INFO);
241 dh->chan_nr = RSL_CHAN_BCCH;
242
243 msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
244 msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
245
Harald Weltee79769b2009-02-07 00:48:17 +0000246 msg->trx = trx;
Harald Welte8470bf22008-12-25 23:28:35 +0000247
248 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000249}
250
Harald Weltee79769b2009-02-07 00:48:17 +0000251int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type,
Harald Welte52b1f982008-12-23 20:25:15 +0000252 const u_int8_t *data, int len)
253{
254 struct abis_rsl_common_hdr *ch;
Harald Welte8470bf22008-12-25 23:28:35 +0000255 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000256
257 ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
258 ch->msg_discr = ABIS_RSL_MDISC_TRX;
259 ch->msg_type = RSL_MT_SACCH_FILL;
260
261 msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
Harald Welte702d8702008-12-26 20:25:35 +0000262 msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
Harald Welte52b1f982008-12-23 20:25:15 +0000263
Harald Weltee79769b2009-02-07 00:48:17 +0000264 msg->trx = trx;
Harald Welte8470bf22008-12-25 23:28:35 +0000265
266 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000267}
268
269/* Chapter 8.4.1 */
Harald Weltee79769b2009-02-07 00:48:17 +0000270int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
Harald Welte52b1f982008-12-23 20:25:15 +0000271 u_int8_t act_type,
272 struct rsl_ie_chan_mode *chan_mode,
273 struct rsl_ie_chan_ident *chan_ident,
274 u_int8_t bs_power, u_int8_t ms_power,
275 u_int8_t ta)
276{
277 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000278 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000279
280 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
281 init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
282 dh->chan_nr = chan_nr;
283
284 msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
285 /* For compatibility with Phase 1 */
286 msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(*chan_mode),
287 (u_int8_t *) chan_mode);
288 msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
Harald Welte702d8702008-12-26 20:25:35 +0000289 (u_int8_t *) chan_ident);
Harald Welte702d8702008-12-26 20:25:35 +0000290#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000291 msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
292 (u_int8_t *) &encr_info);
Harald Welte702d8702008-12-26 20:25:35 +0000293#endif
Harald Welted4c9bf32009-02-15 16:56:18 +0000294 msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power);
Harald Welte52b1f982008-12-23 20:25:15 +0000295 msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
296 msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
297
Harald Weltee79769b2009-02-07 00:48:17 +0000298 msg->trx = trx;
299
Harald Welte8470bf22008-12-25 23:28:35 +0000300 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000301}
302
303#define TSC 7
304
Harald Welte8f5e2392009-02-03 12:57:37 +0000305int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
306 u_int8_t ta)
Harald Welte4b634542008-12-27 01:55:51 +0000307{
308 struct abis_rsl_dchan_hdr *dh;
309 struct msgb *msg = rsl_msgb_alloc();
Harald Welte4b634542008-12-27 01:55:51 +0000310
311 u_int8_t chan_nr = lchan2chan_nr(lchan);
312 u_int16_t arfcn = lchan->ts->trx->arfcn;
313 struct rsl_ie_chan_mode cm;
314 struct rsl_ie_chan_ident ci;
315
316 /* FIXME: what to do with data calls ? */
317 cm.dtx_dtu = 0x00;
318 switch (lchan->type) {
319 case GSM_LCHAN_SDCCH:
320 cm.spd_ind = RSL_CMOD_SPD_SIGN;
321 cm.chan_rt = RSL_CMOD_CRT_SDCCH;
322 cm.chan_rate = 0x00;
323 break;
324 case GSM_LCHAN_TCH_F:
325 cm.spd_ind = RSL_CMOD_SPD_SPEECH;
326 cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
327 cm.chan_rate = 0x11; /* speech coding alg version 2*/
328 break;
Holger Freytherca362a62009-01-04 21:05:01 +0000329 case GSM_LCHAN_TCH_H:
Harald Welte8f5e2392009-02-03 12:57:37 +0000330 DEBUGP(DRSL, "Unimplemented TCH_H activation\n");
Holger Freytherca362a62009-01-04 21:05:01 +0000331 return -1;
332 case GSM_LCHAN_UNKNOWN:
333 case GSM_LCHAN_NONE:
334 return -1;
Harald Welte4b634542008-12-27 01:55:51 +0000335 }
336
337 ci.chan_desc.iei = 0x64;
338 ci.chan_desc.chan_nr = chan_nr;
339 ci.chan_desc.oct3 = (TSC << 5) | ((arfcn & 0x3ff) >> 8);
340 ci.chan_desc.oct4 = arfcn & 0xff;
341
342 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
343 init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
344 dh->chan_nr = chan_nr;
345
346 msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
347 /* For compatibility with Phase 1 */
348 msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
349 (u_int8_t *) &cm);
350 msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
351 (u_int8_t *) &ci);
Harald Welte4b634542008-12-27 01:55:51 +0000352#if 0
353 msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
354 (u_int8_t *) &encr_info);
Harald Welte4b634542008-12-27 01:55:51 +0000355#endif
Harald Welted4c9bf32009-02-15 16:56:18 +0000356 msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
357 msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
Harald Welte4b634542008-12-27 01:55:51 +0000358 msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
359
Harald Weltee79769b2009-02-07 00:48:17 +0000360 msg->trx = lchan->ts->trx;
361
Harald Welte4b634542008-12-27 01:55:51 +0000362 return abis_rsl_sendmsg(msg);
363}
364
Holger Freyther36cbeff2008-12-30 19:15:20 +0000365/* Chapter 9.1.7 of 04.08 */
Harald Welte8470bf22008-12-25 23:28:35 +0000366int rsl_chan_release(struct gsm_lchan *lchan)
Harald Welte52b1f982008-12-23 20:25:15 +0000367{
368 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000369 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000370
371 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
372 init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
Harald Welte8470bf22008-12-25 23:28:35 +0000373 dh->chan_nr = lchan2chan_nr(lchan);
Harald Welte52b1f982008-12-23 20:25:15 +0000374
Harald Welte8470bf22008-12-25 23:28:35 +0000375 msg->lchan = lchan;
376 msg->trx = lchan->ts->trx;
377
Harald Welte2d5b6382008-12-27 19:46:06 +0000378 DEBUGP(DRSL, "Channel Release CMD, chan_nr=0x%02x\n", dh->chan_nr);
379
Harald Welte8470bf22008-12-25 23:28:35 +0000380 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000381}
382
383int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
384 u_int8_t *ms_ident, u_int8_t chan_needed)
385{
386 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000387 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000388
389 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
390 init_dchan_hdr(dh, RSL_MT_PAGING_CMD);
391 dh->chan_nr = RSL_CHAN_PCH_AGCH;
392
393 msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group);
Harald Welte255539c2008-12-28 02:26:27 +0000394 msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
Harald Welte52b1f982008-12-23 20:25:15 +0000395 msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
396
Harald Welte8470bf22008-12-25 23:28:35 +0000397 msg->trx = bts->c0;
398
399 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000400}
401
Holger Freyther7448a532009-01-04 20:18:23 +0000402int rsl_paging_cmd_subscr(struct gsm_bts *bts, u_int8_t chan_need,
403 struct gsm_subscriber *subscr)
404{
Holger Freytherca362a62009-01-04 21:05:01 +0000405#if 0
Holger Freyther7448a532009-01-04 20:18:23 +0000406 u_int8_t mi[128];
407 unsigned int mi_len;
408 u_int8_t paging_group;
Holger Freytherca362a62009-01-04 21:05:01 +0000409#endif
Holger Freyther7448a532009-01-04 20:18:23 +0000410
411 return -1;
412}
413
Harald Welte52b1f982008-12-23 20:25:15 +0000414int imsi_str2bcd(u_int8_t *bcd_out, const char *str_in)
415{
416 int i, len = strlen(str_in);
417
418 for (i = 0; i < len; i++) {
419 int num = str_in[i] - 0x30;
420 if (num < 0 || num > 9)
421 return -1;
422 if (i % 2 == 0)
423 bcd_out[i/2] = num;
424 else
425 bcd_out[i/2] |= (num << 4);
426 }
427
428 return 0;
429}
430
Harald Welte702d8702008-12-26 20:25:35 +0000431/* Chapter 8.5.6 */
Harald Welte52b1f982008-12-23 20:25:15 +0000432int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val)
433{
Harald Welte8470bf22008-12-25 23:28:35 +0000434 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000435 struct abis_rsl_dchan_hdr *dh;
Harald Welte362322e2009-02-15 14:36:38 +0000436 u_int8_t buf[MACBLOCK_SIZE];
Harald Welte52b1f982008-12-23 20:25:15 +0000437
438 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
439 init_dchan_hdr(dh, RSL_MT_IMMEDIATE_ASSIGN_CMD);
440 dh->chan_nr = RSL_CHAN_PCH_AGCH;
441
Harald Welte362322e2009-02-15 14:36:38 +0000442 switch (bts->type) {
443 case GSM_BTS_TYPE_BS11:
444 msgb_tlv_put(msg, RSL_IE_IMM_ASS_INFO, len, val);
445 break;
446 default:
447 /* If phase 2, construct a FULL_IMM_ASS_INFO */
448 pad_macblock(buf, val, len);
449 msgb_tlv_put(msg, RSL_IE_FULL_IMM_ASS_INFO, MACBLOCK_SIZE, buf);
450 break;
451 }
Harald Welte52b1f982008-12-23 20:25:15 +0000452
Harald Welte8470bf22008-12-25 23:28:35 +0000453 msg->trx = bts->c0;
454
455 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000456}
457
Harald Welte8470bf22008-12-25 23:28:35 +0000458/* Send "DATA REQUEST" message with given L3 Info payload */
Harald Welte52b1f982008-12-23 20:25:15 +0000459/* Chapter 8.3.1 */
Harald Welte8470bf22008-12-25 23:28:35 +0000460int rsl_data_request(struct msgb *msg, u_int8_t link_id)
Harald Welte52b1f982008-12-23 20:25:15 +0000461{
Harald Welte8470bf22008-12-25 23:28:35 +0000462 u_int8_t l3_len = msg->tail - (u_int8_t *)msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000463 struct abis_rsl_rll_hdr *rh;
464
Harald Welte8470bf22008-12-25 23:28:35 +0000465 if (msg->lchan == NULL) {
466 fprintf(stderr, "cannot send DATA REQUEST to unknown lchan\n");
467 return -EINVAL;
468 }
Harald Welte52b1f982008-12-23 20:25:15 +0000469
Harald Welte8470bf22008-12-25 23:28:35 +0000470 /* First push the L3 IE tag and length */
Harald Welte4b634542008-12-27 01:55:51 +0000471 msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
Harald Welte8470bf22008-12-25 23:28:35 +0000472
473 /* Then push the RSL header */
Harald Welte52b1f982008-12-23 20:25:15 +0000474 rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh));
475 init_llm_hdr(rh, RSL_MT_DATA_REQ);
Harald Welte8470bf22008-12-25 23:28:35 +0000476 rh->chan_nr = lchan2chan_nr(msg->lchan);
477 rh->link_id = link_id;
Harald Welte52b1f982008-12-23 20:25:15 +0000478
Harald Welte8470bf22008-12-25 23:28:35 +0000479 msg->trx = msg->lchan->ts->trx;
480
481 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000482}
483
Harald Welte702d8702008-12-26 20:25:35 +0000484/* Chapter 8.4.2: Channel Activate Acknowledge */
485static int rsl_rx_chan_act_ack(struct msgb *msg)
486{
487 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
488
489 /* BTS has confirmed channel activation, we now need
490 * to assign the activated channel to the MS */
Harald Welte4b634542008-12-27 01:55:51 +0000491 if (rslh->ie_chan != RSL_IE_CHAN_NR)
492 return -EINVAL;
493
494 DEBUGP(DRSL, "Channel Activate ACK Channel 0x%02x\n", rslh->chan_nr);
Harald Welte702d8702008-12-26 20:25:35 +0000495
Harald Welte4b634542008-12-27 01:55:51 +0000496 return 0;
497}
Harald Welte702d8702008-12-26 20:25:35 +0000498
Harald Welte4b634542008-12-27 01:55:51 +0000499/* Chapter 8.4.3: Channel Activate NACK */
500static int rsl_rx_chan_act_nack(struct msgb *msg)
501{
502 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
503
504 /* BTS has confirmed channel activation, we now need
505 * to assign the activated channel to the MS */
506 if (rslh->ie_chan != RSL_IE_CHAN_NR)
507 return -EINVAL;
508
509 DEBUGP(DRSL, "Channel Activate NACK Channel 0x%02x\n", rslh->chan_nr);
510
511 return 0;
Harald Welte702d8702008-12-26 20:25:35 +0000512}
513
Harald Welte52b1f982008-12-23 20:25:15 +0000514static int abis_rsl_rx_dchan(struct msgb *msg)
515{
Harald Welte8470bf22008-12-25 23:28:35 +0000516 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
517 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000518
Harald Welte8470bf22008-12-25 23:28:35 +0000519 msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
520
521 switch (rslh->c.msg_type) {
Harald Welte52b1f982008-12-23 20:25:15 +0000522 case RSL_MT_CHAN_ACTIV_ACK:
Harald Welte4b634542008-12-27 01:55:51 +0000523 rc = rsl_rx_chan_act_ack(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000524 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000525 case RSL_MT_CHAN_ACTIV_NACK:
Harald Welte4b634542008-12-27 01:55:51 +0000526 rc = rsl_rx_chan_act_nack(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000527 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000528 case RSL_MT_CONN_FAIL:
Harald Welte2d5b6382008-12-27 19:46:06 +0000529 DEBUGP(DRSL, "Connection Fail, release channel\n");
Harald Welte14537e52008-12-27 10:29:08 +0000530 rc = rsl_chan_release(msg->lchan);
Harald Welte2d5b6382008-12-27 19:46:06 +0000531 /* only free it after channel release ACK */
Harald Welte8470bf22008-12-25 23:28:35 +0000532 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000533 case RSL_MT_MEAS_RES:
Harald Welte2d5b6382008-12-27 19:46:06 +0000534 DEBUGP(DRSL, "Measurement Result\n");
535 break;
536 case RSL_MT_RF_CHAN_REL_ACK:
Harald Welte8f5e2392009-02-03 12:57:37 +0000537 DEBUGP(DRSL, "RF CHANNEL RELEASE ACK chan_nr=0x%02x\n",
538 rslh->chan_nr);
Harald Welte2d5b6382008-12-27 19:46:06 +0000539 lchan_free(msg->lchan);
Harald Welte8470bf22008-12-25 23:28:35 +0000540 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000541 case RSL_MT_MODE_MODIFY_ACK:
542 case RSL_MT_MODE_MODIFY_NACK:
543 case RSL_MT_PHY_CONTEXT_CONF:
544 case RSL_MT_PREPROC_MEAS_RES:
Harald Welte52b1f982008-12-23 20:25:15 +0000545 case RSL_MT_TALKER_DET:
546 case RSL_MT_LISTENER_DET:
547 case RSL_MT_REMOTE_CODEC_CONF_REP:
548 case RSL_MT_MR_CODEC_MOD_ACK:
549 case RSL_MT_MR_CODEC_MOD_NACK:
550 case RSL_MT_MR_CODEC_MOD_PER:
551 fprintf(stderr, "Unimplemented Abis RSL DChan msg 0x%02x\n",
Harald Welte8470bf22008-12-25 23:28:35 +0000552 rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000553 break;
554 default:
555 fprintf(stderr, "unknown Abis RSL DChan msg 0x%02x\n",
Harald Welte8470bf22008-12-25 23:28:35 +0000556 rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000557 return -EINVAL;
558 }
Harald Welte8470bf22008-12-25 23:28:35 +0000559 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000560}
561
Harald Welte702d8702008-12-26 20:25:35 +0000562static int rsl_rx_error_rep(struct msgb *msg)
563{
564 struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
565 u_int8_t cause_len;
566
567 if (rslh->data[0] != RSL_IE_CAUSE)
568 return -EINVAL;
569
570 cause_len = rslh->data[1];
Harald Welte4b634542008-12-27 01:55:51 +0000571 fprintf(stdout, "RSL ERROR REPORT, Cause ");
Harald Welte702d8702008-12-26 20:25:35 +0000572 hexdump(&rslh->data[2], cause_len);
573
574 return 0;
575}
576
Harald Welte52b1f982008-12-23 20:25:15 +0000577static int abis_rsl_rx_trx(struct msgb *msg)
578{
Harald Welte702d8702008-12-26 20:25:35 +0000579 struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000580 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000581
582 switch (rslh->msg_type) {
Harald Welte702d8702008-12-26 20:25:35 +0000583 case RSL_MT_ERROR_REPORT:
584 rc = rsl_rx_error_rep(msg);
585 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000586 case RSL_MT_RF_RES_IND:
587 /* interference on idle channels of TRX */
Harald Welte8f5e2392009-02-03 12:57:37 +0000588 fprintf(stderr, "RSL TRX: RF Interference Indication\n");
589 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000590 case RSL_MT_OVERLOAD:
591 /* indicate CCCH / ACCH / processor overload */
Harald Welte8f5e2392009-02-03 12:57:37 +0000592 fprintf(stderr, "RSL TRX: CCCH/ACCH/CPU Overload\n");
Harald Welte52b1f982008-12-23 20:25:15 +0000593 break;
594 default:
595 fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n",
596 rslh->msg_type);
597 return -EINVAL;
598 }
Harald Welte8470bf22008-12-25 23:28:35 +0000599 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000600}
601
Harald Welte8470bf22008-12-25 23:28:35 +0000602/* MS has requested a channel on the RACH */
Harald Welte52b1f982008-12-23 20:25:15 +0000603static int rsl_rx_chan_rqd(struct msgb *msg)
604{
Harald Welte702d8702008-12-26 20:25:35 +0000605 struct gsm_bts *bts = msg->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +0000606 struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
607 struct gsm48_req_ref *rqd_ref;
Harald Welte52b1f982008-12-23 20:25:15 +0000608 struct gsm48_imm_ass ia;
Harald Welte8470bf22008-12-25 23:28:35 +0000609 enum gsm_chan_t lctype;
Harald Welte2cbe0922008-12-29 04:09:31 +0000610 enum gsm_chreq_reason_t chreq_reason;
Harald Welte8470bf22008-12-25 23:28:35 +0000611 struct gsm_lchan *lchan;
612 u_int8_t rqd_ta;
Holger Freyther3186bf22008-12-29 06:23:49 +0000613 int ret;
Harald Welte8470bf22008-12-25 23:28:35 +0000614
Harald Welte52b1f982008-12-23 20:25:15 +0000615 u_int16_t arfcn;
616 u_int8_t ts_number, subch;
617
Harald Welte8470bf22008-12-25 23:28:35 +0000618 /* parse request reference to be used in immediate assign */
619 if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE)
620 return -EINVAL;
621
622 rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1];
623
624 /* parse access delay and use as TA */
625 if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY)
626 return -EINVAL;
627 rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
628
629 /* determine channel type (SDCCH/TCH_F/TCH_H) based on
630 * request reference RA */
631 lctype = get_ctype_by_chreq(bts, rqd_ref->ra);
Harald Welte2cbe0922008-12-29 04:09:31 +0000632 chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra);
633
Harald Welte8470bf22008-12-25 23:28:35 +0000634 /* check availability / allocate channel */
635 lchan = lchan_alloc(bts, lctype);
636 if (!lchan) {
637 fprintf(stderr, "CHAN RQD: no resources\n");
638 /* FIXME: send some kind of reject ?!? */
639 return -ENOMEM;
640 }
641
642 ts_number = lchan->ts->nr;
643 arfcn = lchan->ts->trx->arfcn;
644 subch = lchan->nr;
Harald Welte52b1f982008-12-23 20:25:15 +0000645
Harald Welted4c9bf32009-02-15 16:56:18 +0000646 lchan->ms_power = lchan->bs_power = 0x0f; /* 30dB reduction */
Harald Welte4b634542008-12-27 01:55:51 +0000647 rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
Harald Welte52b1f982008-12-23 20:25:15 +0000648
649 /* create IMMEDIATE ASSIGN 04.08 messge */
650 memset(&ia, 0, sizeof(ia));
651 ia.l2_plen = 0x2d;
652 ia.proto_discr = GSM48_PDISC_RR;
653 ia.msg_type = GSM48_MT_RR_IMM_ASS;
Harald Welte2d5b6382008-12-27 19:46:06 +0000654 ia.page_mode = GSM48_PM_SAME;
Harald Welte4b634542008-12-27 01:55:51 +0000655 ia.chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte52b1f982008-12-23 20:25:15 +0000656 ia.chan_desc.h0.h = 0;
657 ia.chan_desc.h0.arfcn_high = arfcn >> 8;
658 ia.chan_desc.h0.arfcn_low = arfcn & 0xff;
659 ia.chan_desc.h0.tsc = 7;
Harald Welte8470bf22008-12-25 23:28:35 +0000660 /* use request reference extracted from CHAN_RQD */
661 memcpy(&ia.req_ref, rqd_ref, sizeof(ia.req_ref));
662 ia.timing_advance = rqd_ta;
Harald Welte52b1f982008-12-23 20:25:15 +0000663 ia.mob_alloc_len = 0;
664
Harald Welte8f5e2392009-02-03 12:57:37 +0000665 DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %s "
666 "chan_nr=0x%02x r=%s\n",
Harald Welteca64da92009-01-04 16:54:12 +0000667 arfcn, ts_number, subch, gsm_lchan_name(lchan->type),
668 ia.chan_desc.chan_nr, gsm_chreq_name(chreq_reason));
Harald Welte75a983f2008-12-27 21:34:06 +0000669
Holger Freyther3186bf22008-12-29 06:23:49 +0000670
Harald Welte52b1f982008-12-23 20:25:15 +0000671 /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */
Holger Freyther3186bf22008-12-29 06:23:49 +0000672 ret = rsl_imm_assign_cmd(bts, sizeof(ia), (u_int8_t *) &ia);
673
Harald Welte817f3c82008-12-30 14:57:59 +0000674 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000675}
676
Harald Welteea280442009-02-02 22:29:56 +0000677/* MS has requested a channel on the RACH */
678static int rsl_rx_ccch_load(struct msgb *msg)
679{
680 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
681 u_int16_t pg_buf_space;
Holger Freyther8c563cf2009-02-03 20:08:51 +0000682 u_int16_t rach_slot_count = -1;
683 u_int16_t rach_busy_count = -1;
684 u_int16_t rach_access_count = -1;
Harald Welteea280442009-02-02 22:29:56 +0000685
686 switch (rslh->data[0]) {
687 case RSL_IE_PAGING_LOAD:
688 pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
Holger Freyther392209c2009-02-10 00:06:19 +0000689 paging_update_buffer_space(msg->trx->bts, pg_buf_space);
Harald Welteea280442009-02-02 22:29:56 +0000690 break;
691 case RSL_IE_RACH_LOAD:
Holger Freyther8c563cf2009-02-03 20:08:51 +0000692 if (msg->data_len >= 7) {
693 rach_slot_count = rslh->data[2] << 8 | rslh->data[3];
694 rach_busy_count = rslh->data[4] << 8 | rslh->data[5];
695 rach_access_count = rslh->data[6] << 8 | rslh->data[7];
696 }
Harald Welteea280442009-02-02 22:29:56 +0000697 break;
698 default:
699 break;
700 }
701
702 return 0;
703}
704
Harald Welte52b1f982008-12-23 20:25:15 +0000705static int abis_rsl_rx_cchan(struct msgb *msg)
706{
Harald Welteea280442009-02-02 22:29:56 +0000707 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000708 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000709
Harald Welte8470bf22008-12-25 23:28:35 +0000710 msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
711
712 switch (rslh->c.msg_type) {
Harald Welte52b1f982008-12-23 20:25:15 +0000713 case RSL_MT_CHAN_RQD:
714 /* MS has requested a channel on the RACH */
715 rc = rsl_rx_chan_rqd(msg);
716 break;
Harald Welteea280442009-02-02 22:29:56 +0000717 case RSL_MT_CCCH_LOAD_IND:
718 /* current load on the CCCH */
719 rc = rsl_rx_ccch_load(msg);
720 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000721 case RSL_MT_DELETE_IND:
722 /* CCCH overloaded, IMM_ASSIGN was dropped */
723 case RSL_MT_CBCH_LOAD_IND:
724 /* current load on the CBCH */
Harald Welte8f5e2392009-02-03 12:57:37 +0000725 fprintf(stderr, "Unimplemented Abis RSL TRX message type "
726 "0x%02x\n", rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000727 break;
728 default:
729 fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n",
Harald Welte8470bf22008-12-25 23:28:35 +0000730 rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000731 return -EINVAL;
732 }
Harald Welte8470bf22008-12-25 23:28:35 +0000733
734 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000735}
736
Harald Welte4b634542008-12-27 01:55:51 +0000737static int rsl_rx_rll_err_ind(struct msgb *msg)
738{
739 struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
740 u_int8_t *rlm_cause = rllh->data;
741
742 DEBUGP(DRLL, "RLL ERROR INDICATION: chan_nr=0x%02x cause=0x%02x\n",
743 rllh->chan_nr, rlm_cause[1]);
744
745 return 0;
746}
Harald Welte52b1f982008-12-23 20:25:15 +0000747/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
748 0x02, 0x06,
749 0x01, 0x20,
750 0x02, 0x00,
751 0x0b, 0x00, 0x0f, 0x05, 0x08, ... */
752
753static int abis_rsl_rx_rll(struct msgb *msg)
754{
755 struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
756 int rc;
Harald Welte8470bf22008-12-25 23:28:35 +0000757
758 msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
Harald Welte52b1f982008-12-23 20:25:15 +0000759
760 switch (rllh->c.msg_type) {
761 case RSL_MT_DATA_IND:
Harald Welte4b634542008-12-27 01:55:51 +0000762 DEBUGP(DRLL, "DATA INDICATION chan_nr=0x%02x\n", rllh->chan_nr);
Harald Welte8470bf22008-12-25 23:28:35 +0000763 /* FIXME: Verify L3 info element */
Harald Welte702d8702008-12-26 20:25:35 +0000764 msg->l3h = &rllh->data[3];
Harald Welte52b1f982008-12-23 20:25:15 +0000765 rc = gsm0408_rcvmsg(msg);
766 break;
767 case RSL_MT_EST_IND:
Harald Welte8f5e2392009-02-03 12:57:37 +0000768 DEBUGP(DRLL, "ESTABLISH INDICATION chan_nr=0x%02x\n",
769 rllh->chan_nr);
Harald Welte8470bf22008-12-25 23:28:35 +0000770 /* FIXME: Verify L3 info element */
Harald Welte702d8702008-12-26 20:25:35 +0000771 msg->l3h = &rllh->data[3];
Harald Welte52b1f982008-12-23 20:25:15 +0000772 rc = gsm0408_rcvmsg(msg);
773 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000774 case RSL_MT_REL_IND:
Harald Welte8f5e2392009-02-03 12:57:37 +0000775 DEBUGP(DRLL, "RELEASE INDICATION chan_nr=0x%02x\n",
776 rllh->chan_nr);
Harald Welte2d5b6382008-12-27 19:46:06 +0000777 break;
778 case RSL_MT_REL_CONF:
Harald Welte8f5e2392009-02-03 12:57:37 +0000779 DEBUGP(DRLL, "RELEASE CONFIRMATION chan_nr=0x%02x\n",
780 rllh->chan_nr);
Harald Welte4b634542008-12-27 01:55:51 +0000781 break;
782 case RSL_MT_ERROR_IND:
783 rc = rsl_rx_rll_err_ind(msg);
784 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000785 case RSL_MT_UNIT_DATA_IND:
786 fprintf(stderr, "unimplemented Abis RLL message type 0x%02x\n",
787 rllh->c.msg_type);
788 break;
789 default:
790 fprintf(stderr, "unknown Abis RLL message type 0x%02x\n",
791 rllh->c.msg_type);
792 }
Harald Welte8470bf22008-12-25 23:28:35 +0000793 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000794}
795
796/* Entry-point where L2 RSL from BTS enters */
Harald Welte8470bf22008-12-25 23:28:35 +0000797int abis_rsl_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000798{
799 struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ;
Harald Welte8f5e2392009-02-03 12:57:37 +0000800 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000801
802 switch (rslh->msg_discr & 0xfe) {
803 case ABIS_RSL_MDISC_RLL:
804 rc = abis_rsl_rx_rll(msg);
805 break;
806 case ABIS_RSL_MDISC_DED_CHAN:
807 rc = abis_rsl_rx_dchan(msg);
808 break;
809 case ABIS_RSL_MDISC_COM_CHAN:
Harald Welte52b1f982008-12-23 20:25:15 +0000810 rc = abis_rsl_rx_cchan(msg);
811 break;
Harald Welte8470bf22008-12-25 23:28:35 +0000812 case ABIS_RSL_MDISC_TRX:
813 rc = abis_rsl_rx_trx(msg);
814 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000815 case ABIS_RSL_MDISC_LOC:
Harald Welte8f5e2392009-02-03 12:57:37 +0000816 fprintf(stderr, "unimplemented RSL msg disc 0x%02x\n",
817 rslh->msg_discr);
818 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000819 default:
820 fprintf(stderr, "unknown RSL message discriminator 0x%02x\n",
821 rslh->msg_discr);
822 return -EINVAL;
823 }
Harald Welte4f4a3902008-12-26 00:04:49 +0000824 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000825 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000826}
Holger Freyther3b72a892009-02-04 00:31:39 +0000827
828
829/* Section 3.3.2.3 . I think this looks like a table */
830int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf)
831{
832 switch (ccch_conf) {
833 case RSL_BCCH_CCCH_CONF_1_NC:
834 return 1;
835 case RSL_BCCH_CCCH_CONF_1_C:
836 return 1;
837 case RSL_BCCH_CCCH_CONF_2_NC:
838 return 2;
839 case RSL_BCCH_CCCH_CONF_3_NC:
840 return 3;
841 case RSL_BCCH_CCCH_CONF_4_NC:
842 return 4;
843 default:
844 return -1;
845 }
846}
847
848int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf)
849{
850 switch (ccch_conf) {
851 case RSL_BCCH_CCCH_CONF_1_NC:
852 return 0;
853 case RSL_BCCH_CCCH_CONF_1_C:
854 return 1;
855 case RSL_BCCH_CCCH_CONF_2_NC:
856 return 0;
857 case RSL_BCCH_CCCH_CONF_3_NC:
858 return 0;
859 case RSL_BCCH_CCCH_CONF_4_NC:
860 return 0;
861 default:
862 return -1;
863 }
864}
865
866/* From Table 10.5.33 of GSM 04.08 */
867int rsl_number_of_paging_subchannels(struct gsm_bts *bts)
868{
869 if (bts->chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
870 return MAX(1, (3 - bts->chan_desc.bs_ag_blks_res))
Holger Freyther3aa8d6c2009-02-04 02:14:45 +0000871 * (bts->chan_desc.bs_pa_mfrms + 2);
Holger Freyther3b72a892009-02-04 00:31:39 +0000872 } else {
873 return (9 - bts->chan_desc.bs_ag_blks_res)
Holger Freyther3aa8d6c2009-02-04 02:14:45 +0000874 * (bts->chan_desc.bs_pa_mfrms + 2);
Holger Freyther3b72a892009-02-04 00:31:39 +0000875 }
876}