blob: 2e1224d9995b30a04a264c18ae607529ba45c604 [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>
Harald Welte52b1f982008-12-23 20:25:15 +000035
Harald Welte8470bf22008-12-25 23:28:35 +000036#define RSL_ALLOC_SIZE 1024
37#define RSL_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000038
Holger Freyther3b72a892009-02-04 00:31:39 +000039#define MAX(a, b) (a) >= (b) ? (a) : (b)
40
Harald Welte52b1f982008-12-23 20:25:15 +000041static u_int8_t mdisc_by_msgtype(u_int8_t msg_type)
42{
43 /* mask off the transparent bit ? */
44 msg_type &= 0xfe;
45
Harald Welte8470bf22008-12-25 23:28:35 +000046 if ((msg_type & 0xf0) == 0x00)
Harald Welte52b1f982008-12-23 20:25:15 +000047 return ABIS_RSL_MDISC_RLL;
Harald Welte8470bf22008-12-25 23:28:35 +000048 if ((msg_type & 0xf0) == 0x10) {
Harald Welte52b1f982008-12-23 20:25:15 +000049 if (msg_type >= 0x19 && msg_type <= 0x22)
50 return ABIS_RSL_MDISC_TRX;
51 else
52 return ABIS_RSL_MDISC_COM_CHAN;
53 }
Harald Welte2d5b6382008-12-27 19:46:06 +000054 if ((msg_type & 0xe0) == 0x20)
Harald Welte52b1f982008-12-23 20:25:15 +000055 return ABIS_RSL_MDISC_DED_CHAN;
56
57 return ABIS_RSL_MDISC_LOC;
58}
59
60static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh,
61 u_int8_t msg_type)
62{
63 dh->c.msg_discr = mdisc_by_msgtype(msg_type);
64 dh->c.msg_type = msg_type;
65 dh->ie_chan = RSL_IE_CHAN_NR;
66}
67
68static inline void init_llm_hdr(struct abis_rsl_rll_hdr *dh,
69 u_int8_t msg_type)
70{
71 /* dh->c.msg_discr = mdisc_by_msgtype(msg_type); */
72 dh->c.msg_discr = ABIS_RSL_MDISC_RLL;
73 dh->c.msg_type = msg_type;
74 dh->ie_chan = RSL_IE_CHAN_NR;
75 dh->ie_link_id = RSL_IE_LINK_IDENT;
76}
77
78
79/* encode channel number as per Section 9.3.1 */
80u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot)
81{
82 u_int8_t ret;
83
84 ret = (timeslot & 0x07) | type;
85
86 switch (type) {
87 case RSL_CHAN_Lm_ACCHs:
88 subch &= 0x01;
89 break;
90 case RSL_CHAN_SDCCH4_ACCH:
91 subch &= 0x07;
92 break;
93 case RSL_CHAN_SDCCH8_ACCH:
94 subch &= 0x07;
95 break;
96 default:
97 /* no subchannels allowed */
98 subch = 0x00;
99 break;
100 }
101 ret |= (subch << 3);
102
103 return ret;
104}
105
Harald Welte8470bf22008-12-25 23:28:35 +0000106/* determine logical channel based on TRX and channel number IE */
107struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr)
108{
109 struct gsm_lchan *lchan;
110 u_int8_t ts_nr = chan_nr & 0x07;
111 u_int8_t cbits = chan_nr >> 3;
112 u_int8_t lch_idx;
113 struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
114
115 if (cbits == 0x01) {
116 lch_idx = 0; /* TCH/F */
117 if (ts->pchan != GSM_PCHAN_TCH_F)
118 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
119 chan_nr, ts->pchan);
120 } else if ((cbits & 0x1e) == 0x02) {
121 lch_idx = cbits & 0x1; /* TCH/H */
122 if (ts->pchan != GSM_PCHAN_TCH_H)
123 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
124 chan_nr, ts->pchan);
125 } else if ((cbits & 0x1c) == 0x04) {
126 lch_idx = cbits & 0x3; /* SDCCH/4 */
127 if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
128 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
129 chan_nr, ts->pchan);
130 } else if ((cbits & 0x18) == 0x08) {
131 lch_idx = cbits & 0x7; /* SDCCH/8 */
132 if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C)
133 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
134 chan_nr, ts->pchan);
135 } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) {
136 lch_idx = 0;
137 if (ts->pchan != GSM_PCHAN_CCCH &&
138 ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
139 fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
140 chan_nr, ts->pchan);
141 /* FIXME: we should not return first sdcch4 !!! */
142 } else {
143 fprintf(stderr, "unknown chan_nr=0x%02x\n", chan_nr);
144 return NULL;
145 }
146
147 lchan = &ts->lchan[lch_idx];
148
149 return lchan;
150}
151
152u_int8_t lchan2chan_nr(struct gsm_lchan *lchan)
153{
154 struct gsm_bts_trx_ts *ts = lchan->ts;
155 u_int8_t cbits, chan_nr;
156
157 switch (ts->pchan) {
158 case GSM_PCHAN_TCH_F:
159 cbits = 0x01;
160 break;
161 case GSM_PCHAN_TCH_H:
162 cbits = 0x02;
163 cbits += lchan->nr;
164 break;
165 case GSM_PCHAN_CCCH_SDCCH4:
166 cbits = 0x04;
167 cbits += lchan->nr;
168 break;
169 case GSM_PCHAN_SDCCH8_SACCH8C:
170 cbits = 0x08;
171 cbits += lchan->nr;
172 break;
173 default:
174 case GSM_PCHAN_CCCH:
175 cbits = 0x10;
176 break;
177 }
178
179 chan_nr = (cbits << 3) | (ts->nr & 0x7);
180
181 return chan_nr;
182}
183
Harald Welte52b1f982008-12-23 20:25:15 +0000184/* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */
185u_int64_t str_to_imsi(const char *imsi_str)
186{
187 u_int64_t ret;
188
189 ret = strtoull(imsi_str, NULL, 10);
190
191 return ret;
192}
193
194/* Table 5 Clause 7 TS 05.02 */
195unsigned int n_pag_blocks(int bs_ccch_sdcch_comb, unsigned int bs_ag_blks_res)
196{
197 if (!bs_ccch_sdcch_comb)
198 return 9 - bs_ag_blks_res;
199 else
200 return 3 - bs_ag_blks_res;
201}
202
203/* Chapter 6.5.2 of TS 05.02 */
204unsigned int get_ccch_group(u_int64_t imsi, unsigned int bs_cc_chans,
205 unsigned int n_pag_blocks)
206{
207 return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) / n_pag_blocks;
208}
209
210/* Chapter 6.5.2 of TS 05.02 */
211unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans,
212 int n_pag_blocks)
213{
214 return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) % n_pag_blocks;
215}
216
Harald Welte8470bf22008-12-25 23:28:35 +0000217static struct msgb *rsl_msgb_alloc(void)
218{
219 return msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM);
220}
221
Harald Welte52b1f982008-12-23 20:25:15 +0000222/* Send a BCCH_INFO message as per Chapter 8.5.1 */
223int rsl_bcch_info(struct gsm_bts *bts, u_int8_t type,
224 const u_int8_t *data, int len)
225{
226 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000227 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000228
229 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof*dh);
230 init_dchan_hdr(dh, RSL_MT_BCCH_INFO);
231 dh->chan_nr = RSL_CHAN_BCCH;
232
233 msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
234 msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
235
Harald Welte8470bf22008-12-25 23:28:35 +0000236 msg->trx = bts->c0;
237
238 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000239}
240
241int rsl_sacch_filling(struct gsm_bts *bts, u_int8_t type,
242 const u_int8_t *data, int len)
243{
244 struct abis_rsl_common_hdr *ch;
Harald Welte8470bf22008-12-25 23:28:35 +0000245 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000246
247 ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
248 ch->msg_discr = ABIS_RSL_MDISC_TRX;
249 ch->msg_type = RSL_MT_SACCH_FILL;
250
251 msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
Harald Welte702d8702008-12-26 20:25:35 +0000252 msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
Harald Welte52b1f982008-12-23 20:25:15 +0000253
Harald Welte8470bf22008-12-25 23:28:35 +0000254 msg->trx = bts->c0;
255
256 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000257}
258
259/* Chapter 8.4.1 */
260int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr,
261 u_int8_t act_type,
262 struct rsl_ie_chan_mode *chan_mode,
263 struct rsl_ie_chan_ident *chan_ident,
264 u_int8_t bs_power, u_int8_t ms_power,
265 u_int8_t ta)
266{
267 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000268 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000269
270 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
271 init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
272 dh->chan_nr = chan_nr;
273
274 msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
275 /* For compatibility with Phase 1 */
276 msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(*chan_mode),
277 (u_int8_t *) chan_mode);
278 msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
Harald Welte702d8702008-12-26 20:25:35 +0000279 (u_int8_t *) chan_ident);
Harald Welte52b1f982008-12-23 20:25:15 +0000280 /* FIXME: this shoould be optional */
Harald Welte702d8702008-12-26 20:25:35 +0000281#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000282 msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
283 (u_int8_t *) &encr_info);
284 msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power);
Harald Welte702d8702008-12-26 20:25:35 +0000285#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000286 msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
287 msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
288
Harald Welte8470bf22008-12-25 23:28:35 +0000289 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000290}
291
292#define TSC 7
293
Harald Welte8f5e2392009-02-03 12:57:37 +0000294int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
295 u_int8_t ta)
Harald Welte4b634542008-12-27 01:55:51 +0000296{
297 struct abis_rsl_dchan_hdr *dh;
298 struct msgb *msg = rsl_msgb_alloc();
299 /* FXIME: don't hardcode these!! */
Harald Welte4b634542008-12-27 01:55:51 +0000300 u_int8_t ms_power = 0x0f;
Harald Welte4b634542008-12-27 01:55:51 +0000301
302 u_int8_t chan_nr = lchan2chan_nr(lchan);
303 u_int16_t arfcn = lchan->ts->trx->arfcn;
304 struct rsl_ie_chan_mode cm;
305 struct rsl_ie_chan_ident ci;
306
307 /* FIXME: what to do with data calls ? */
308 cm.dtx_dtu = 0x00;
309 switch (lchan->type) {
310 case GSM_LCHAN_SDCCH:
311 cm.spd_ind = RSL_CMOD_SPD_SIGN;
312 cm.chan_rt = RSL_CMOD_CRT_SDCCH;
313 cm.chan_rate = 0x00;
314 break;
315 case GSM_LCHAN_TCH_F:
316 cm.spd_ind = RSL_CMOD_SPD_SPEECH;
317 cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
318 cm.chan_rate = 0x11; /* speech coding alg version 2*/
319 break;
Holger Freytherca362a62009-01-04 21:05:01 +0000320 case GSM_LCHAN_TCH_H:
Harald Welte8f5e2392009-02-03 12:57:37 +0000321 DEBUGP(DRSL, "Unimplemented TCH_H activation\n");
Holger Freytherca362a62009-01-04 21:05:01 +0000322 return -1;
323 case GSM_LCHAN_UNKNOWN:
324 case GSM_LCHAN_NONE:
325 return -1;
Harald Welte4b634542008-12-27 01:55:51 +0000326 }
327
328 ci.chan_desc.iei = 0x64;
329 ci.chan_desc.chan_nr = chan_nr;
330 ci.chan_desc.oct3 = (TSC << 5) | ((arfcn & 0x3ff) >> 8);
331 ci.chan_desc.oct4 = arfcn & 0xff;
332
333 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
334 init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
335 dh->chan_nr = chan_nr;
336
337 msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
338 /* For compatibility with Phase 1 */
339 msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
340 (u_int8_t *) &cm);
341 msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
342 (u_int8_t *) &ci);
Holger Freytherca362a62009-01-04 21:05:01 +0000343 /* FIXME: this should be optional */
Harald Welte4b634542008-12-27 01:55:51 +0000344#if 0
345 msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
346 (u_int8_t *) &encr_info);
347 msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power);
348#endif
349 msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
350 msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
351
352 return abis_rsl_sendmsg(msg);
353}
354
Holger Freyther36cbeff2008-12-30 19:15:20 +0000355/* Chapter 9.1.7 of 04.08 */
Harald Welte8470bf22008-12-25 23:28:35 +0000356int rsl_chan_release(struct gsm_lchan *lchan)
Harald Welte52b1f982008-12-23 20:25:15 +0000357{
358 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000359 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000360
361 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
362 init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
Harald Welte8470bf22008-12-25 23:28:35 +0000363 dh->chan_nr = lchan2chan_nr(lchan);
Harald Welte52b1f982008-12-23 20:25:15 +0000364
Harald Welte8470bf22008-12-25 23:28:35 +0000365 msg->lchan = lchan;
366 msg->trx = lchan->ts->trx;
367
Harald Welte2d5b6382008-12-27 19:46:06 +0000368 DEBUGP(DRSL, "Channel Release CMD, chan_nr=0x%02x\n", dh->chan_nr);
369
Harald Welte8470bf22008-12-25 23:28:35 +0000370 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000371}
372
373int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
374 u_int8_t *ms_ident, u_int8_t chan_needed)
375{
376 struct abis_rsl_dchan_hdr *dh;
Harald Welte8470bf22008-12-25 23:28:35 +0000377 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000378
379 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
380 init_dchan_hdr(dh, RSL_MT_PAGING_CMD);
381 dh->chan_nr = RSL_CHAN_PCH_AGCH;
382
383 msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group);
Harald Welte255539c2008-12-28 02:26:27 +0000384 msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
Harald Welte52b1f982008-12-23 20:25:15 +0000385 msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
386
Harald Welte8470bf22008-12-25 23:28:35 +0000387 msg->trx = bts->c0;
388
389 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000390}
391
Holger Freyther7448a532009-01-04 20:18:23 +0000392int rsl_paging_cmd_subscr(struct gsm_bts *bts, u_int8_t chan_need,
393 struct gsm_subscriber *subscr)
394{
Holger Freytherca362a62009-01-04 21:05:01 +0000395#if 0
Holger Freyther7448a532009-01-04 20:18:23 +0000396 u_int8_t mi[128];
397 unsigned int mi_len;
398 u_int8_t paging_group;
Holger Freytherca362a62009-01-04 21:05:01 +0000399#endif
Holger Freyther7448a532009-01-04 20:18:23 +0000400
401 return -1;
402}
403
Harald Welte52b1f982008-12-23 20:25:15 +0000404int imsi_str2bcd(u_int8_t *bcd_out, const char *str_in)
405{
406 int i, len = strlen(str_in);
407
408 for (i = 0; i < len; i++) {
409 int num = str_in[i] - 0x30;
410 if (num < 0 || num > 9)
411 return -1;
412 if (i % 2 == 0)
413 bcd_out[i/2] = num;
414 else
415 bcd_out[i/2] |= (num << 4);
416 }
417
418 return 0;
419}
420
Harald Welte702d8702008-12-26 20:25:35 +0000421/* Chapter 8.5.6 */
Harald Welte52b1f982008-12-23 20:25:15 +0000422int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val)
423{
Harald Welte8470bf22008-12-25 23:28:35 +0000424 struct msgb *msg = rsl_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000425 struct abis_rsl_dchan_hdr *dh;
426
427 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
428 init_dchan_hdr(dh, RSL_MT_IMMEDIATE_ASSIGN_CMD);
429 dh->chan_nr = RSL_CHAN_PCH_AGCH;
430
431 /* If phase 2, FULL_IMM_ASS_INFO */
432
433 msgb_tlv_put(msg, RSL_IE_IMM_ASS_INFO, len, val);
434
Harald Welte8470bf22008-12-25 23:28:35 +0000435 msg->trx = bts->c0;
436
437 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000438}
439
Harald Welte8470bf22008-12-25 23:28:35 +0000440/* Send "DATA REQUEST" message with given L3 Info payload */
Harald Welte52b1f982008-12-23 20:25:15 +0000441/* Chapter 8.3.1 */
Harald Welte8470bf22008-12-25 23:28:35 +0000442int rsl_data_request(struct msgb *msg, u_int8_t link_id)
Harald Welte52b1f982008-12-23 20:25:15 +0000443{
Harald Welte8470bf22008-12-25 23:28:35 +0000444 u_int8_t l3_len = msg->tail - (u_int8_t *)msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000445 struct abis_rsl_rll_hdr *rh;
446
Harald Welte8470bf22008-12-25 23:28:35 +0000447 if (msg->lchan == NULL) {
448 fprintf(stderr, "cannot send DATA REQUEST to unknown lchan\n");
449 return -EINVAL;
450 }
Harald Welte52b1f982008-12-23 20:25:15 +0000451
Harald Welte8470bf22008-12-25 23:28:35 +0000452 /* First push the L3 IE tag and length */
Harald Welte4b634542008-12-27 01:55:51 +0000453 msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
Harald Welte8470bf22008-12-25 23:28:35 +0000454
455 /* Then push the RSL header */
Harald Welte52b1f982008-12-23 20:25:15 +0000456 rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh));
457 init_llm_hdr(rh, RSL_MT_DATA_REQ);
Harald Welte8470bf22008-12-25 23:28:35 +0000458 rh->chan_nr = lchan2chan_nr(msg->lchan);
459 rh->link_id = link_id;
Harald Welte52b1f982008-12-23 20:25:15 +0000460
Harald Welte8470bf22008-12-25 23:28:35 +0000461 msg->trx = msg->lchan->ts->trx;
462
463 return abis_rsl_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000464}
465
Harald Welte702d8702008-12-26 20:25:35 +0000466/* Chapter 8.4.2: Channel Activate Acknowledge */
467static int rsl_rx_chan_act_ack(struct msgb *msg)
468{
469 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
470
471 /* BTS has confirmed channel activation, we now need
472 * to assign the activated channel to the MS */
Harald Welte4b634542008-12-27 01:55:51 +0000473 if (rslh->ie_chan != RSL_IE_CHAN_NR)
474 return -EINVAL;
475
476 DEBUGP(DRSL, "Channel Activate ACK Channel 0x%02x\n", rslh->chan_nr);
Harald Welte702d8702008-12-26 20:25:35 +0000477
Harald Welte4b634542008-12-27 01:55:51 +0000478 return 0;
479}
Harald Welte702d8702008-12-26 20:25:35 +0000480
Harald Welte4b634542008-12-27 01:55:51 +0000481/* Chapter 8.4.3: Channel Activate NACK */
482static int rsl_rx_chan_act_nack(struct msgb *msg)
483{
484 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
485
486 /* BTS has confirmed channel activation, we now need
487 * to assign the activated channel to the MS */
488 if (rslh->ie_chan != RSL_IE_CHAN_NR)
489 return -EINVAL;
490
491 DEBUGP(DRSL, "Channel Activate NACK Channel 0x%02x\n", rslh->chan_nr);
492
493 return 0;
Harald Welte702d8702008-12-26 20:25:35 +0000494}
495
Harald Welte52b1f982008-12-23 20:25:15 +0000496static int abis_rsl_rx_dchan(struct msgb *msg)
497{
Harald Welte8470bf22008-12-25 23:28:35 +0000498 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
499 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000500
Harald Welte8470bf22008-12-25 23:28:35 +0000501 msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
502
503 switch (rslh->c.msg_type) {
Harald Welte52b1f982008-12-23 20:25:15 +0000504 case RSL_MT_CHAN_ACTIV_ACK:
Harald Welte4b634542008-12-27 01:55:51 +0000505 rc = rsl_rx_chan_act_ack(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000506 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000507 case RSL_MT_CHAN_ACTIV_NACK:
Harald Welte4b634542008-12-27 01:55:51 +0000508 rc = rsl_rx_chan_act_nack(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000509 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000510 case RSL_MT_CONN_FAIL:
Harald Welte2d5b6382008-12-27 19:46:06 +0000511 DEBUGP(DRSL, "Connection Fail, release channel\n");
Harald Welte14537e52008-12-27 10:29:08 +0000512 rc = rsl_chan_release(msg->lchan);
Harald Welte2d5b6382008-12-27 19:46:06 +0000513 /* only free it after channel release ACK */
Harald Welte8470bf22008-12-25 23:28:35 +0000514 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000515 case RSL_MT_MEAS_RES:
Harald Welte2d5b6382008-12-27 19:46:06 +0000516 DEBUGP(DRSL, "Measurement Result\n");
517 break;
518 case RSL_MT_RF_CHAN_REL_ACK:
Harald Welte8f5e2392009-02-03 12:57:37 +0000519 DEBUGP(DRSL, "RF CHANNEL RELEASE ACK chan_nr=0x%02x\n",
520 rslh->chan_nr);
Harald Welte2d5b6382008-12-27 19:46:06 +0000521 lchan_free(msg->lchan);
Harald Welte8470bf22008-12-25 23:28:35 +0000522 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000523 case RSL_MT_MODE_MODIFY_ACK:
524 case RSL_MT_MODE_MODIFY_NACK:
525 case RSL_MT_PHY_CONTEXT_CONF:
526 case RSL_MT_PREPROC_MEAS_RES:
Harald Welte52b1f982008-12-23 20:25:15 +0000527 case RSL_MT_TALKER_DET:
528 case RSL_MT_LISTENER_DET:
529 case RSL_MT_REMOTE_CODEC_CONF_REP:
530 case RSL_MT_MR_CODEC_MOD_ACK:
531 case RSL_MT_MR_CODEC_MOD_NACK:
532 case RSL_MT_MR_CODEC_MOD_PER:
533 fprintf(stderr, "Unimplemented Abis RSL DChan msg 0x%02x\n",
Harald Welte8470bf22008-12-25 23:28:35 +0000534 rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000535 break;
536 default:
537 fprintf(stderr, "unknown Abis RSL DChan msg 0x%02x\n",
Harald Welte8470bf22008-12-25 23:28:35 +0000538 rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000539 return -EINVAL;
540 }
Harald Welte8470bf22008-12-25 23:28:35 +0000541 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000542}
543
Harald Welte702d8702008-12-26 20:25:35 +0000544static int rsl_rx_error_rep(struct msgb *msg)
545{
546 struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
547 u_int8_t cause_len;
548
549 if (rslh->data[0] != RSL_IE_CAUSE)
550 return -EINVAL;
551
552 cause_len = rslh->data[1];
Harald Welte4b634542008-12-27 01:55:51 +0000553 fprintf(stdout, "RSL ERROR REPORT, Cause ");
Harald Welte702d8702008-12-26 20:25:35 +0000554 hexdump(&rslh->data[2], cause_len);
555
556 return 0;
557}
558
Harald Welte52b1f982008-12-23 20:25:15 +0000559static int abis_rsl_rx_trx(struct msgb *msg)
560{
Harald Welte702d8702008-12-26 20:25:35 +0000561 struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000562 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000563
564 switch (rslh->msg_type) {
Harald Welte702d8702008-12-26 20:25:35 +0000565 case RSL_MT_ERROR_REPORT:
566 rc = rsl_rx_error_rep(msg);
567 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000568 case RSL_MT_RF_RES_IND:
569 /* interference on idle channels of TRX */
Harald Welte8f5e2392009-02-03 12:57:37 +0000570 fprintf(stderr, "RSL TRX: RF Interference Indication\n");
571 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000572 case RSL_MT_OVERLOAD:
573 /* indicate CCCH / ACCH / processor overload */
Harald Welte8f5e2392009-02-03 12:57:37 +0000574 fprintf(stderr, "RSL TRX: CCCH/ACCH/CPU Overload\n");
Harald Welte52b1f982008-12-23 20:25:15 +0000575 break;
576 default:
577 fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n",
578 rslh->msg_type);
579 return -EINVAL;
580 }
Harald Welte8470bf22008-12-25 23:28:35 +0000581 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000582}
583
Harald Welte8470bf22008-12-25 23:28:35 +0000584/* MS has requested a channel on the RACH */
Harald Welte52b1f982008-12-23 20:25:15 +0000585static int rsl_rx_chan_rqd(struct msgb *msg)
586{
Harald Welte702d8702008-12-26 20:25:35 +0000587 struct gsm_bts *bts = msg->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +0000588 struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
589 struct gsm48_req_ref *rqd_ref;
Harald Welte52b1f982008-12-23 20:25:15 +0000590 struct gsm48_imm_ass ia;
Harald Welte8470bf22008-12-25 23:28:35 +0000591 enum gsm_chan_t lctype;
Harald Welte2cbe0922008-12-29 04:09:31 +0000592 enum gsm_chreq_reason_t chreq_reason;
Harald Welte8470bf22008-12-25 23:28:35 +0000593 struct gsm_lchan *lchan;
594 u_int8_t rqd_ta;
Holger Freyther3186bf22008-12-29 06:23:49 +0000595 int ret;
Harald Welte8470bf22008-12-25 23:28:35 +0000596
Harald Welte52b1f982008-12-23 20:25:15 +0000597 u_int16_t arfcn;
598 u_int8_t ts_number, subch;
599
Harald Welte8470bf22008-12-25 23:28:35 +0000600 /* parse request reference to be used in immediate assign */
601 if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE)
602 return -EINVAL;
603
604 rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1];
605
606 /* parse access delay and use as TA */
607 if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY)
608 return -EINVAL;
609 rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
610
611 /* determine channel type (SDCCH/TCH_F/TCH_H) based on
612 * request reference RA */
613 lctype = get_ctype_by_chreq(bts, rqd_ref->ra);
Harald Welte2cbe0922008-12-29 04:09:31 +0000614 chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra);
615
Harald Welte8470bf22008-12-25 23:28:35 +0000616 /* check availability / allocate channel */
617 lchan = lchan_alloc(bts, lctype);
618 if (!lchan) {
619 fprintf(stderr, "CHAN RQD: no resources\n");
620 /* FIXME: send some kind of reject ?!? */
621 return -ENOMEM;
622 }
623
624 ts_number = lchan->ts->nr;
625 arfcn = lchan->ts->trx->arfcn;
626 subch = lchan->nr;
Harald Welte52b1f982008-12-23 20:25:15 +0000627
Harald Welte4b634542008-12-27 01:55:51 +0000628 rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
Harald Welte52b1f982008-12-23 20:25:15 +0000629
630 /* create IMMEDIATE ASSIGN 04.08 messge */
631 memset(&ia, 0, sizeof(ia));
632 ia.l2_plen = 0x2d;
633 ia.proto_discr = GSM48_PDISC_RR;
634 ia.msg_type = GSM48_MT_RR_IMM_ASS;
Harald Welte2d5b6382008-12-27 19:46:06 +0000635 ia.page_mode = GSM48_PM_SAME;
Harald Welte4b634542008-12-27 01:55:51 +0000636 ia.chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte52b1f982008-12-23 20:25:15 +0000637 ia.chan_desc.h0.h = 0;
638 ia.chan_desc.h0.arfcn_high = arfcn >> 8;
639 ia.chan_desc.h0.arfcn_low = arfcn & 0xff;
640 ia.chan_desc.h0.tsc = 7;
Harald Welte8470bf22008-12-25 23:28:35 +0000641 /* use request reference extracted from CHAN_RQD */
642 memcpy(&ia.req_ref, rqd_ref, sizeof(ia.req_ref));
643 ia.timing_advance = rqd_ta;
Harald Welte52b1f982008-12-23 20:25:15 +0000644 ia.mob_alloc_len = 0;
645
Harald Welte8f5e2392009-02-03 12:57:37 +0000646 DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %s "
647 "chan_nr=0x%02x r=%s\n",
Harald Welteca64da92009-01-04 16:54:12 +0000648 arfcn, ts_number, subch, gsm_lchan_name(lchan->type),
649 ia.chan_desc.chan_nr, gsm_chreq_name(chreq_reason));
Harald Welte75a983f2008-12-27 21:34:06 +0000650
Holger Freyther3186bf22008-12-29 06:23:49 +0000651
Harald Welte52b1f982008-12-23 20:25:15 +0000652 /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */
Holger Freyther3186bf22008-12-29 06:23:49 +0000653 ret = rsl_imm_assign_cmd(bts, sizeof(ia), (u_int8_t *) &ia);
654
Harald Welte817f3c82008-12-30 14:57:59 +0000655 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000656}
657
Harald Welteea280442009-02-02 22:29:56 +0000658/* MS has requested a channel on the RACH */
659static int rsl_rx_ccch_load(struct msgb *msg)
660{
661 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
662 u_int16_t pg_buf_space;
Holger Freyther8c563cf2009-02-03 20:08:51 +0000663 u_int16_t rach_slot_count = -1;
664 u_int16_t rach_busy_count = -1;
665 u_int16_t rach_access_count = -1;
Harald Welteea280442009-02-02 22:29:56 +0000666
667 switch (rslh->data[0]) {
668 case RSL_IE_PAGING_LOAD:
669 pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
670 DEBUGP(DRSL, "CCCH LOAD IND, free paging buffer space: %u\n",
671 pg_buf_space);
672 break;
673 case RSL_IE_RACH_LOAD:
Holger Freyther8c563cf2009-02-03 20:08:51 +0000674 if (msg->data_len >= 7) {
675 rach_slot_count = rslh->data[2] << 8 | rslh->data[3];
676 rach_busy_count = rslh->data[4] << 8 | rslh->data[5];
677 rach_access_count = rslh->data[6] << 8 | rslh->data[7];
678 }
679 DEBUGP(DRSL, "CCCH LOAD IND, RACH Load Count: %u Busy: %u Access: %u\n",
680 rach_slot_count, rach_busy_count, rach_access_count);
Harald Welteea280442009-02-02 22:29:56 +0000681 break;
682 default:
683 break;
684 }
685
686 return 0;
687}
688
Harald Welte52b1f982008-12-23 20:25:15 +0000689static int abis_rsl_rx_cchan(struct msgb *msg)
690{
Harald Welteea280442009-02-02 22:29:56 +0000691 struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000692 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000693
Harald Welte8470bf22008-12-25 23:28:35 +0000694 msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
695
696 switch (rslh->c.msg_type) {
Harald Welte52b1f982008-12-23 20:25:15 +0000697 case RSL_MT_CHAN_RQD:
698 /* MS has requested a channel on the RACH */
699 rc = rsl_rx_chan_rqd(msg);
700 break;
Harald Welteea280442009-02-02 22:29:56 +0000701 case RSL_MT_CCCH_LOAD_IND:
702 /* current load on the CCCH */
703 rc = rsl_rx_ccch_load(msg);
704 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000705 case RSL_MT_DELETE_IND:
706 /* CCCH overloaded, IMM_ASSIGN was dropped */
707 case RSL_MT_CBCH_LOAD_IND:
708 /* current load on the CBCH */
Harald Welte8f5e2392009-02-03 12:57:37 +0000709 fprintf(stderr, "Unimplemented Abis RSL TRX message type "
710 "0x%02x\n", rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000711 break;
712 default:
713 fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n",
Harald Welte8470bf22008-12-25 23:28:35 +0000714 rslh->c.msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000715 return -EINVAL;
716 }
Harald Welte8470bf22008-12-25 23:28:35 +0000717
718 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000719}
720
Harald Welte4b634542008-12-27 01:55:51 +0000721static int rsl_rx_rll_err_ind(struct msgb *msg)
722{
723 struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
724 u_int8_t *rlm_cause = rllh->data;
725
726 DEBUGP(DRLL, "RLL ERROR INDICATION: chan_nr=0x%02x cause=0x%02x\n",
727 rllh->chan_nr, rlm_cause[1]);
728
729 return 0;
730}
Harald Welte52b1f982008-12-23 20:25:15 +0000731/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
732 0x02, 0x06,
733 0x01, 0x20,
734 0x02, 0x00,
735 0x0b, 0x00, 0x0f, 0x05, 0x08, ... */
736
737static int abis_rsl_rx_rll(struct msgb *msg)
738{
739 struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
740 int rc;
Harald Welte8470bf22008-12-25 23:28:35 +0000741
742 msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
Harald Welte52b1f982008-12-23 20:25:15 +0000743
744 switch (rllh->c.msg_type) {
745 case RSL_MT_DATA_IND:
Harald Welte4b634542008-12-27 01:55:51 +0000746 DEBUGP(DRLL, "DATA INDICATION chan_nr=0x%02x\n", rllh->chan_nr);
Harald Welte8470bf22008-12-25 23:28:35 +0000747 /* FIXME: Verify L3 info element */
Harald Welte702d8702008-12-26 20:25:35 +0000748 msg->l3h = &rllh->data[3];
Harald Welte52b1f982008-12-23 20:25:15 +0000749 rc = gsm0408_rcvmsg(msg);
750 break;
751 case RSL_MT_EST_IND:
Harald Welte8f5e2392009-02-03 12:57:37 +0000752 DEBUGP(DRLL, "ESTABLISH INDICATION chan_nr=0x%02x\n",
753 rllh->chan_nr);
Harald Welte8470bf22008-12-25 23:28:35 +0000754 /* FIXME: Verify L3 info element */
Harald Welte702d8702008-12-26 20:25:35 +0000755 msg->l3h = &rllh->data[3];
Harald Welte52b1f982008-12-23 20:25:15 +0000756 rc = gsm0408_rcvmsg(msg);
757 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000758 case RSL_MT_REL_IND:
Harald Welte8f5e2392009-02-03 12:57:37 +0000759 DEBUGP(DRLL, "RELEASE INDICATION chan_nr=0x%02x\n",
760 rllh->chan_nr);
Harald Welte2d5b6382008-12-27 19:46:06 +0000761 break;
762 case RSL_MT_REL_CONF:
Harald Welte8f5e2392009-02-03 12:57:37 +0000763 DEBUGP(DRLL, "RELEASE CONFIRMATION chan_nr=0x%02x\n",
764 rllh->chan_nr);
Harald Welte4b634542008-12-27 01:55:51 +0000765 break;
766 case RSL_MT_ERROR_IND:
767 rc = rsl_rx_rll_err_ind(msg);
768 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000769 case RSL_MT_UNIT_DATA_IND:
770 fprintf(stderr, "unimplemented Abis RLL message type 0x%02x\n",
771 rllh->c.msg_type);
772 break;
773 default:
774 fprintf(stderr, "unknown Abis RLL message type 0x%02x\n",
775 rllh->c.msg_type);
776 }
Harald Welte8470bf22008-12-25 23:28:35 +0000777 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000778}
779
780/* Entry-point where L2 RSL from BTS enters */
Harald Welte8470bf22008-12-25 23:28:35 +0000781int abis_rsl_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000782{
783 struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ;
Harald Welte8f5e2392009-02-03 12:57:37 +0000784 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000785
786 switch (rslh->msg_discr & 0xfe) {
787 case ABIS_RSL_MDISC_RLL:
788 rc = abis_rsl_rx_rll(msg);
789 break;
790 case ABIS_RSL_MDISC_DED_CHAN:
791 rc = abis_rsl_rx_dchan(msg);
792 break;
793 case ABIS_RSL_MDISC_COM_CHAN:
Harald Welte52b1f982008-12-23 20:25:15 +0000794 rc = abis_rsl_rx_cchan(msg);
795 break;
Harald Welte8470bf22008-12-25 23:28:35 +0000796 case ABIS_RSL_MDISC_TRX:
797 rc = abis_rsl_rx_trx(msg);
798 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000799 case ABIS_RSL_MDISC_LOC:
Harald Welte8f5e2392009-02-03 12:57:37 +0000800 fprintf(stderr, "unimplemented RSL msg disc 0x%02x\n",
801 rslh->msg_discr);
802 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000803 default:
804 fprintf(stderr, "unknown RSL message discriminator 0x%02x\n",
805 rslh->msg_discr);
806 return -EINVAL;
807 }
Harald Welte4f4a3902008-12-26 00:04:49 +0000808 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000809 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +0000810}
Holger Freyther3b72a892009-02-04 00:31:39 +0000811
812
813/* Section 3.3.2.3 . I think this looks like a table */
814int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf)
815{
816 switch (ccch_conf) {
817 case RSL_BCCH_CCCH_CONF_1_NC:
818 return 1;
819 case RSL_BCCH_CCCH_CONF_1_C:
820 return 1;
821 case RSL_BCCH_CCCH_CONF_2_NC:
822 return 2;
823 case RSL_BCCH_CCCH_CONF_3_NC:
824 return 3;
825 case RSL_BCCH_CCCH_CONF_4_NC:
826 return 4;
827 default:
828 return -1;
829 }
830}
831
832int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf)
833{
834 switch (ccch_conf) {
835 case RSL_BCCH_CCCH_CONF_1_NC:
836 return 0;
837 case RSL_BCCH_CCCH_CONF_1_C:
838 return 1;
839 case RSL_BCCH_CCCH_CONF_2_NC:
840 return 0;
841 case RSL_BCCH_CCCH_CONF_3_NC:
842 return 0;
843 case RSL_BCCH_CCCH_CONF_4_NC:
844 return 0;
845 default:
846 return -1;
847 }
848}
849
850/* From Table 10.5.33 of GSM 04.08 */
851int rsl_number_of_paging_subchannels(struct gsm_bts *bts)
852{
853 if (bts->chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
854 return MAX(1, (3 - bts->chan_desc.bs_ag_blks_res))
855 * bts->chan_desc.bs_pa_mfrms;
856 } else {
857 return (9 - bts->chan_desc.bs_ag_blks_res)
858 * bts->chan_desc.bs_pa_mfrms;
859 }
860}