blob: b770b52fcf0a6b697f488c20e8be2af8fba31890 [file] [log] [blame]
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +02001/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
2 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0
3 * utility functions
4 */
5
6/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
7 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
8 *
9 * All Rights Reserved
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 *
25 */
26#include <stdio.h>
27#include <stdlib.h>
Holger Hans Peter Freytheradc14782009-08-21 04:57:35 +020028#include <errno.h>
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020029#include <netinet/in.h>
30
Harald Weltedfe6c7d2010-02-20 16:24:02 +010031#include <osmocore/msgb.h>
Harald Welteafedeab2010-03-04 10:55:40 +010032#include <osmocore/gsm48.h>
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020033#include <openbsc/debug.h>
34#include <openbsc/gsm_04_08.h>
35#include <openbsc/transaction.h>
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +020036#include <openbsc/paging.h>
37#include <openbsc/signal.h>
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020038
39#define GSM48_ALLOC_SIZE 1024
40#define GSM48_ALLOC_HEADROOM 128
41
42/* should ip.access BTS use direct RTP streams between each other (1),
43 * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
44int ipacc_rtp_direct = 1;
45
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020046struct msgb *gsm48_msgb_alloc(void)
47{
48 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
49 "GSM 04.08");
50}
51
52int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
53{
54 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
55
56 /* if we get passed a transaction reference, do some common
57 * work that the caller no longer has to do */
58 if (trans) {
59 gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +010060 msg->lchan = trans->conn->lchan;
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020061 }
62
63 if (msg->lchan) {
64 msg->trx = msg->lchan->ts->trx;
65
66 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
67 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
68 "Sending '%s' to MS.\n", msg->trx->bts->nr,
69 msg->trx->nr, msg->lchan->ts->nr,
70 gh->proto_discr & 0xf0,
Harald Weltee95daf192010-03-25 12:13:02 +080071 gsm48_cc_msg_name(gh->msg_type));
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020072 else
73 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
74 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
75 msg->trx->nr, msg->lchan->ts->nr,
76 gh->proto_discr, gh->msg_type);
77 }
78
79 msg->l3h = msg->data;
80
81 return rsl_data_request(msg, 0);
82}
83
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +020084/* Section 9.1.8 / Table 9.9 */
85struct chreq {
86 u_int8_t val;
87 u_int8_t mask;
88 enum chreq_type type;
89};
90
91/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
92static const struct chreq chreq_type_neci1[] = {
93 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
94 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
95 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
96 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
97 { 0xe0, 0xe0, CHREQ_T_SDCCH },
98 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
99 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
100 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
101 { 0x10, 0xf0, CHREQ_T_SDCCH },
Holger Hans Peter Freyther135a7c62009-11-17 16:46:46 +0100102 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI1 },
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200103 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
104 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
Holger Hans Peter Freytherd61654c2009-11-21 20:20:43 +0100105 { 0x67, 0xff, CHREQ_T_LMU },
106 { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH },
107 { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH },
108 { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH },
109 { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE },
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200110};
111
112/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
113static const struct chreq chreq_type_neci0[] = {
114 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
115 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
116 { 0xe0, 0xe0, CHREQ_T_TCH_F },
117 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
118 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
Holger Hans Peter Freyther135a7c62009-11-17 16:46:46 +0100119 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI0 },
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200120 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
121 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
Holger Hans Peter Freytherd61654c2009-11-21 20:20:43 +0100122 { 0x67, 0xff, CHREQ_T_LMU },
123 { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH },
124 { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH },
125 { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH },
126 { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE },
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200127};
128
129static const enum gsm_chan_t ctype_by_chreq[] = {
130 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
131 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
132 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
133 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
134 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
135 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
136 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
137 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
138 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
Holger Hans Peter Freyther135a7c62009-11-17 16:46:46 +0100139 [CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH,
140 [CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH,
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200141 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
142 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
Holger Hans Peter Freytherd61654c2009-11-21 20:20:43 +0100143 [CHREQ_T_LMU] = GSM_LCHAN_SDCCH,
144 [CHREQ_T_RESERVED_SDCCH] = GSM_LCHAN_SDCCH,
145 [CHREQ_T_RESERVED_IGNORE] = GSM_LCHAN_UNKNOWN,
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200146};
147
148static const enum gsm_chreq_reason_t reason_by_chreq[] = {
149 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
150 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
151 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
152 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
153 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
154 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
Harald Welte9385c112009-12-12 20:57:52 +0100155 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_CALL,
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200156 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
157 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
Holger Hans Peter Freyther135a7c62009-11-17 16:46:46 +0100158 [CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG,
159 [CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG,
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200160 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
161 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
Holger Hans Peter Freytherd61654c2009-11-21 20:20:43 +0100162 [CHREQ_T_LMU] = GSM_CHREQ_REASON_OTHER,
163 [CHREQ_T_RESERVED_SDCCH] = GSM_CHREQ_REASON_OTHER,
164 [CHREQ_T_RESERVED_IGNORE] = GSM_CHREQ_REASON_OTHER,
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200165};
166
Holger Hans Peter Freytherf7d752f2009-11-16 17:12:38 +0100167enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci)
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200168{
169 int i;
Holger Hans Peter Freyther843b44d2009-11-17 16:38:25 +0100170 int length;
171 const struct chreq *chreq;
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200172
Holger Hans Peter Freyther843b44d2009-11-17 16:38:25 +0100173 if (neci) {
174 chreq = chreq_type_neci1;
175 length = ARRAY_SIZE(chreq_type_neci1);
176 } else {
177 chreq = chreq_type_neci0;
178 length = ARRAY_SIZE(chreq_type_neci0);
179 }
180
181
182 for (i = 0; i < length; i++) {
183 const struct chreq *chr = &chreq[i];
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200184 if ((ra & chr->mask) == chr->val)
185 return ctype_by_chreq[chr->type];
186 }
Harald Welte50720e72009-12-24 11:50:20 +0100187 LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200188 return GSM_LCHAN_SDCCH;
189}
190
Holger Hans Peter Freytherf7d752f2009-11-16 17:12:38 +0100191enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci)
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200192{
193 int i;
Holger Hans Peter Freyther843b44d2009-11-17 16:38:25 +0100194 int length;
195 const struct chreq *chreq;
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200196
Holger Hans Peter Freyther843b44d2009-11-17 16:38:25 +0100197 if (neci) {
198 chreq = chreq_type_neci1;
199 length = ARRAY_SIZE(chreq_type_neci1);
200 } else {
201 chreq = chreq_type_neci0;
202 length = ARRAY_SIZE(chreq_type_neci0);
203 }
204
205 for (i = 0; i < length; i++) {
206 const struct chreq *chr = &chreq[i];
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200207 if ((ra & chr->mask) == chr->val)
208 return reason_by_chreq[chr->type];
209 }
Harald Welte50720e72009-12-24 11:50:20 +0100210 LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
Holger Hans Peter Freyther1494a762009-08-01 07:26:59 +0200211 return GSM_CHREQ_REASON_OTHER;
212}
213
214/* 7.1.7 and 9.1.7: RR CHANnel RELease */
215int gsm48_send_rr_release(struct gsm_lchan *lchan)
216{
217 struct msgb *msg = gsm48_msgb_alloc();
218 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
219 u_int8_t *cause;
220
221 msg->lchan = lchan;
222 gh->proto_discr = GSM48_PDISC_RR;
223 gh->msg_type = GSM48_MT_RR_CHAN_REL;
224
225 cause = msgb_put(msg, 1);
226 cause[0] = GSM48_RR_CAUSE_NORMAL;
227
228 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
229 lchan->nr, lchan->type);
230
231 /* Send actual release request to MS */
232 gsm48_sendmsg(msg, NULL);
233 /* FIXME: Start Timer T3109 */
234
235 /* Deactivate the SACCH on the BTS side */
236 return rsl_deact_sacch(lchan);
237}
238
Holger Hans Peter Freytheradc14782009-08-21 04:57:35 +0200239int send_siemens_mrpci(struct gsm_lchan *lchan,
240 u_int8_t *classmark2_lv)
241{
242 struct rsl_mrpci mrpci;
243
244 if (classmark2_lv[0] < 2)
245 return -EINVAL;
246
247 mrpci.power_class = classmark2_lv[1] & 0x7;
248 mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
249 mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
250 mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
251
252 return rsl_siemens_mrpci(lchan, &mrpci);
253}
254
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200255int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type)
256{
257 struct gsm48_hdr *gh = msgb_l3(msg);
258 u_int8_t *classmark2_lv = gh->data + 1;
259 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
260 *mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
261
262 return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
263}
264
265int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
266{
267 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
268 struct gsm48_hdr *gh = msgb_l3(msg);
269 u_int8_t *classmark2_lv = gh->data + 1;
270 struct paging_signal_data sig_data;
271
272 if (is_siemens_bts(bts))
273 send_siemens_mrpci(msg->lchan, classmark2_lv);
274
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100275 if (!msg->lchan->conn.subscr) {
276 msg->lchan->conn.subscr = subscr;
277 } else if (msg->lchan->conn.subscr != subscr) {
Harald Welte50720e72009-12-24 11:50:20 +0100278 LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200279 subscr_put(subscr);
280 return -EINVAL;
281 } else {
282 DEBUGP(DRR, "<- Channel already owned by us\n");
283 subscr_put(subscr);
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100284 subscr = msg->lchan->conn.subscr;
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200285 }
286
287 sig_data.subscr = subscr;
288 sig_data.bts = msg->lchan->ts->trx->bts;
289 sig_data.lchan = msg->lchan;
290
Harald Welte24ff6ee2009-12-22 00:41:05 +0100291 bts->network->stats.paging.completed++;
292
Sylvain Munautef24dff2009-12-19 12:38:10 +0100293 dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200294
295 /* Stop paging on the bts we received the paging response */
296 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
297 return 0;
298}
Holger Hans Peter Freytherea4088a2009-10-05 13:25:06 +0200299
300/* Chapter 9.1.9: Ciphering Mode Command */
Holger Hans Peter Freytherca6bc1d2009-10-05 14:00:14 +0200301int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv)
Holger Hans Peter Freytherea4088a2009-10-05 13:25:06 +0200302{
303 struct msgb *msg = gsm48_msgb_alloc();
304 struct gsm48_hdr *gh;
305 u_int8_t ciph_mod_set;
306
307 msg->lchan = lchan;
308
309 DEBUGP(DRR, "TX CIPHERING MODE CMD\n");
310
311 if (lchan->encr.alg_id <= RSL_ENC_ALG_A5(0))
312 ciph_mod_set = 0;
313 else
314 ciph_mod_set = (lchan->encr.alg_id-2)<<1 | 1;
315
316 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
317 gh->proto_discr = GSM48_PDISC_RR;
318 gh->msg_type = GSM48_MT_RR_CIPH_M_CMD;
Holger Hans Peter Freytherca6bc1d2009-10-05 14:00:14 +0200319 gh->data[0] = (want_imeisv & 0x1) << 4 | (ciph_mod_set & 0xf);
Holger Hans Peter Freytherea4088a2009-10-05 13:25:06 +0200320
321 return rsl_encryption_cmd(msg);
322}
323
Harald Welte8c83af62009-11-29 20:02:53 +0100324static void gsm48_cell_desc(struct gsm48_cell_desc *cd,
325 const struct gsm_bts *bts)
326{
327 cd->ncc = (bts->bsic >> 3 & 0x7);
328 cd->bcc = (bts->bsic & 0x7);
329 cd->arfcn_hi = bts->c0->arfcn >> 8;
330 cd->arfcn_lo = bts->c0->arfcn & 0xff;
331}
332
333static void gsm48_chan_desc(struct gsm48_chan_desc *cd,
334 const struct gsm_lchan *lchan)
335{
336 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
337
338 cd->chan_nr = lchan2chan_nr(lchan);
339 cd->h0.tsc = lchan->ts->trx->bts->tsc;
340 cd->h0.h = 0;
341 cd->h0.arfcn_high = arfcn >> 8;
342 cd->h0.arfcn_low = arfcn & 0xff;
343}
344
345/* Chapter 9.1.15: Handover Command */
Harald Welte7a7a0d52009-12-17 00:25:18 +0100346int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
347 u_int8_t power_command, u_int8_t ho_ref)
Harald Welte8c83af62009-11-29 20:02:53 +0100348{
349 struct msgb *msg = gsm48_msgb_alloc();
350 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
351 struct gsm48_ho_cmd *ho =
352 (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho));
Harald Welte8c83af62009-11-29 20:02:53 +0100353
354 msg->lchan = old_lchan;
Harald Welte7a7a0d52009-12-17 00:25:18 +0100355 gh->proto_discr = GSM48_PDISC_RR;
356 gh->msg_type = GSM48_MT_RR_HANDO_CMD;
Harald Welte8c83af62009-11-29 20:02:53 +0100357
358 /* mandatory bits */
359 gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts);
360 gsm48_chan_desc(&ho->chan_desc, new_lchan);
Harald Welte7a7a0d52009-12-17 00:25:18 +0100361 ho->ho_ref = ho_ref;
Harald Welte8c83af62009-11-29 20:02:53 +0100362 ho->power_command = power_command;
363
364 /* FIXME: optional bits for type of synchronization? */
365
366 return gsm48_sendmsg(msg, NULL);
367}
368
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200369/* Chapter 9.1.2: Assignment Command */
Holger Hans Peter Freyther550197f2010-01-28 09:43:49 +0100370int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_command)
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200371{
372 struct msgb *msg = gsm48_msgb_alloc();
373 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
374 struct gsm48_ass_cmd *ass =
375 (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass));
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200376
377 DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
378
Holger Hans Peter Freyther550197f2010-01-28 09:43:49 +0100379 msg->lchan = dest_lchan;
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200380 gh->proto_discr = GSM48_PDISC_RR;
381 gh->msg_type = GSM48_MT_RR_ASS_CMD;
382
383 /*
384 * fill the channel information element, this code
385 * should probably be shared with rsl_rx_chan_rqd(),
386 * gsm48_tx_chan_mode_modify. But beware that 10.5.2.5
387 * 10.5.2.5.a have slightly different semantic for
388 * the chan_desc. But as long as multi-slot configurations
389 * are not used we seem to be fine.
390 */
Harald Welte8c83af62009-11-29 20:02:53 +0100391 gsm48_chan_desc(&ass->chan_desc, lchan);
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200392 ass->power_command = power_command;
393
Holger Hans Peter Freyther1b891fd2010-01-28 11:51:24 +0100394 msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode);
395
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100396 /* in case of multi rate we need to attach a config */
397 if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100398 if (lchan->mr_conf.ver == 0) {
Harald Welte50720e72009-12-24 11:50:20 +0100399 LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
400 "without multirate config.\n");
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100401 } else {
402 u_int8_t *data = msgb_put(msg, 4);
403 data[0] = GSM48_IE_MUL_RATE_CFG;
404 data[1] = 0x2;
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100405 memcpy(&data[2], &lchan->mr_conf, 2);
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100406 }
407 }
408
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200409 return gsm48_sendmsg(msg, NULL);
410}
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200411
412/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100413int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200414{
415 struct msgb *msg = gsm48_msgb_alloc();
416 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
417 struct gsm48_chan_mode_modify *cmm =
418 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
419 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
420
421 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
422
423 lchan->tch_mode = mode;
424 msg->lchan = lchan;
425 gh->proto_discr = GSM48_PDISC_RR;
426 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
427
428 /* fill the channel information element, this code
429 * should probably be shared with rsl_rx_chan_rqd() */
430 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
431 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
432 cmm->chan_desc.h0.h = 0;
433 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
434 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
435 cmm->mode = mode;
436
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100437 /* in case of multi rate we need to attach a config */
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100438 if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
439 if (lchan->mr_conf.ver == 0) {
Harald Welte50720e72009-12-24 11:50:20 +0100440 LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
441 "without multirate config.\n");
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100442 } else {
443 u_int8_t *data = msgb_put(msg, 4);
444 data[0] = GSM48_IE_MUL_RATE_CFG;
445 data[1] = 0x2;
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100446 memcpy(&data[2], &lchan->mr_conf, 2);
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100447 }
448 }
449
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200450 return gsm48_sendmsg(msg, NULL);
451}
452
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100453int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode)
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200454{
455 int rc;
456
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100457 rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode);
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200458 if (rc < 0)
459 return rc;
460
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200461 return rc;
462}
463
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200464int gsm48_rx_rr_modif_ack(struct msgb *msg)
465{
Holger Hans Peter Freyther25b1e252009-11-18 19:30:24 +0100466 int rc;
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200467 struct gsm48_hdr *gh = msgb_l3(msg);
468 struct gsm48_chan_mode_modify *mod =
469 (struct gsm48_chan_mode_modify *) gh->data;
470
471 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
472
473 if (mod->mode != msg->lchan->tch_mode) {
Harald Welte50720e72009-12-24 11:50:20 +0100474 LOGP(DRR, LOGL_ERROR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n",
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200475 msg->lchan->tch_mode, mod->mode);
476 return -1;
477 }
478
479 /* update the channel type */
480 switch (mod->mode) {
481 case GSM48_CMODE_SIGN:
482 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
483 break;
484 case GSM48_CMODE_SPEECH_V1:
485 case GSM48_CMODE_SPEECH_EFR:
486 case GSM48_CMODE_SPEECH_AMR:
487 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
488 break;
489 case GSM48_CMODE_DATA_14k5:
490 case GSM48_CMODE_DATA_12k0:
491 case GSM48_CMODE_DATA_6k0:
492 case GSM48_CMODE_DATA_3k6:
493 msg->lchan->rsl_cmode = RSL_CMOD_SPD_DATA;
494 break;
495 }
496
497 /* We've successfully modified the MS side of the channel,
498 * now go on to modify the BTS side of the channel */
Holger Hans Peter Freyther25b1e252009-11-18 19:30:24 +0100499 rc = rsl_chan_mode_modify_req(msg->lchan);
500
501 /* FIXME: we not only need to do this after mode modify, but
502 * also after channel activation */
503 if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && mod->mode != GSM48_CMODE_SIGN)
504 rsl_ipacc_crcx(msg->lchan);
505 return rc;
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200506}
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100507
508int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
509{
510 struct gsm48_hdr *gh = msgb_l3(msg);
511 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
512 u_int8_t *data = gh->data;
513 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
514 struct bitvec *nbv = &bts->si_common.neigh_list;
Harald Weltea06c35e2009-12-25 22:46:25 +0100515 struct gsm_meas_rep_cell *mrc;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100516
517 if (gh->msg_type != GSM48_MT_RR_MEAS_REP)
518 return -EINVAL;
519
520 if (data[0] & 0x80)
521 rep->flags |= MEAS_REP_F_BA1;
522 if (data[0] & 0x40)
523 rep->flags |= MEAS_REP_F_UL_DTX;
524 if ((data[1] & 0x40) == 0x00)
525 rep->flags |= MEAS_REP_F_DL_VALID;
526
527 rep->dl.full.rx_lev = data[0] & 0x3f;
528 rep->dl.sub.rx_lev = data[1] & 0x3f;
529 rep->dl.full.rx_qual = (data[3] >> 4) & 0x7;
530 rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7;
531
532 rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2);
533 if (rep->num_cell < 1 || rep->num_cell > 6)
534 return 0;
535
536 /* an encoding nightmare in perfection */
Harald Weltea06c35e2009-12-25 22:46:25 +0100537 mrc = &rep->cell[0];
538 mrc->rxlev = data[3] & 0x3f;
Harald Welte950eca92009-12-25 22:49:34 +0100539 mrc->neigh_idx = data[4] >> 3;
Harald Welteeaa95d52009-12-25 23:01:54 +0100540 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100541 mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5);
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100542 if (rep->num_cell < 2)
543 return 0;
544
Harald Weltea06c35e2009-12-25 22:46:25 +0100545 mrc = &rep->cell[1];
546 mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7);
Harald Welte950eca92009-12-25 22:49:34 +0100547 mrc->neigh_idx = (data[6] >> 2) & 0x1f;
Harald Welteeaa95d52009-12-25 23:01:54 +0100548 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100549 mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4);
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100550 if (rep->num_cell < 3)
551 return 0;
552
Harald Weltea06c35e2009-12-25 22:46:25 +0100553 mrc = &rep->cell[2];
554 mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6);
Harald Welte950eca92009-12-25 22:49:34 +0100555 mrc->neigh_idx = (data[8] >> 1) & 0x1f;
Harald Welteeaa95d52009-12-25 23:01:54 +0100556 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Welte (local)65898582009-12-26 14:12:43 +0100557 mrc->bsic = ((data[8] & 0x01) << 5) | (data[9] >> 3);
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100558 if (rep->num_cell < 4)
559 return 0;
560
Harald Weltea06c35e2009-12-25 22:46:25 +0100561 mrc = &rep->cell[3];
562 mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5);
Harald Welte950eca92009-12-25 22:49:34 +0100563 mrc->neigh_idx = data[10] & 0x1f;
Harald Welteeaa95d52009-12-25 23:01:54 +0100564 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100565 mrc->bsic = data[11] >> 2;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100566 if (rep->num_cell < 5)
567 return 0;
568
Harald Weltea06c35e2009-12-25 22:46:25 +0100569 mrc = &rep->cell[4];
570 mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4);
Harald Welte950eca92009-12-25 22:49:34 +0100571 mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7);
Harald Welteeaa95d52009-12-25 23:01:54 +0100572 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100573 mrc->bsic = (data[13] >> 1) & 0x3f;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100574 if (rep->num_cell < 6)
575 return 0;
576
Harald Weltea06c35e2009-12-25 22:46:25 +0100577 mrc = &rep->cell[5];
Harald Welte950eca92009-12-25 22:49:34 +0100578 mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3);
579 mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6);
Harald Welteeaa95d52009-12-25 23:01:54 +0100580 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100581 mrc->bsic = data[15] & 0x3f;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100582
583 return 0;
584}