blob: 68f34f4094d09013dbe5c09ea2d6bed45fc6b89a [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);
60 msg->lchan = trans->lchan;
61 }
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 Welteafedeab2010-03-04 10:55:40 +010071 gsm48_cc_msg_names[gh->msg_type & 0x3f]);
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 Freytherd1862d72009-08-19 07:54:59 +0200239/* Convert Mobile Identity (10.5.1.4) to string */
240int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len)
241{
242 int i;
243 u_int8_t mi_type;
244 char *str_cur = string;
245 u_int32_t tmsi;
246
247 mi_type = mi[0] & GSM_MI_TYPE_MASK;
248
249 switch (mi_type) {
250 case GSM_MI_TYPE_NONE:
251 break;
252 case GSM_MI_TYPE_TMSI:
253 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
254 if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
255 memcpy(&tmsi, &mi[1], 4);
256 tmsi = ntohl(tmsi);
257 return snprintf(string, str_len, "%u", tmsi);
258 }
259 break;
260 case GSM_MI_TYPE_IMSI:
261 case GSM_MI_TYPE_IMEI:
262 case GSM_MI_TYPE_IMEISV:
263 *str_cur++ = bcd2char(mi[0] >> 4);
264
265 for (i = 1; i < mi_len; i++) {
266 if (str_cur + 2 >= string + str_len)
267 return str_cur - string;
268 *str_cur++ = bcd2char(mi[i] & 0xf);
269 /* skip last nibble in last input byte when GSM_EVEN */
270 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
271 *str_cur++ = bcd2char(mi[i] >> 4);
272 }
273 break;
274 default:
275 break;
276 }
277 *str_cur++ = '\0';
278
279 return str_cur - string;
280}
281
Holger Hans Peter Freytheradc14782009-08-21 04:57:35 +0200282
283int send_siemens_mrpci(struct gsm_lchan *lchan,
284 u_int8_t *classmark2_lv)
285{
286 struct rsl_mrpci mrpci;
287
288 if (classmark2_lv[0] < 2)
289 return -EINVAL;
290
291 mrpci.power_class = classmark2_lv[1] & 0x7;
292 mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
293 mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
294 mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
295
296 return rsl_siemens_mrpci(lchan, &mrpci);
297}
298
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200299int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type)
300{
301 struct gsm48_hdr *gh = msgb_l3(msg);
302 u_int8_t *classmark2_lv = gh->data + 1;
303 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
304 *mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
305
306 return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
307}
308
309int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
310{
311 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
312 struct gsm48_hdr *gh = msgb_l3(msg);
313 u_int8_t *classmark2_lv = gh->data + 1;
314 struct paging_signal_data sig_data;
315
316 if (is_siemens_bts(bts))
317 send_siemens_mrpci(msg->lchan, classmark2_lv);
318
319 if (!msg->lchan->subscr) {
320 msg->lchan->subscr = subscr;
321 } else if (msg->lchan->subscr != subscr) {
Harald Welte50720e72009-12-24 11:50:20 +0100322 LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200323 subscr_put(subscr);
324 return -EINVAL;
325 } else {
326 DEBUGP(DRR, "<- Channel already owned by us\n");
327 subscr_put(subscr);
328 subscr = msg->lchan->subscr;
329 }
330
331 sig_data.subscr = subscr;
332 sig_data.bts = msg->lchan->ts->trx->bts;
333 sig_data.lchan = msg->lchan;
334
Harald Welte24ff6ee2009-12-22 00:41:05 +0100335 bts->network->stats.paging.completed++;
336
Sylvain Munautef24dff2009-12-19 12:38:10 +0100337 dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);
Holger Hans Peter Freyther3ee5d3e2009-08-21 05:18:21 +0200338
339 /* Stop paging on the bts we received the paging response */
340 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
341 return 0;
342}
Holger Hans Peter Freytherea4088a2009-10-05 13:25:06 +0200343
344/* Chapter 9.1.9: Ciphering Mode Command */
Holger Hans Peter Freytherca6bc1d2009-10-05 14:00:14 +0200345int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv)
Holger Hans Peter Freytherea4088a2009-10-05 13:25:06 +0200346{
347 struct msgb *msg = gsm48_msgb_alloc();
348 struct gsm48_hdr *gh;
349 u_int8_t ciph_mod_set;
350
351 msg->lchan = lchan;
352
353 DEBUGP(DRR, "TX CIPHERING MODE CMD\n");
354
355 if (lchan->encr.alg_id <= RSL_ENC_ALG_A5(0))
356 ciph_mod_set = 0;
357 else
358 ciph_mod_set = (lchan->encr.alg_id-2)<<1 | 1;
359
360 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
361 gh->proto_discr = GSM48_PDISC_RR;
362 gh->msg_type = GSM48_MT_RR_CIPH_M_CMD;
Holger Hans Peter Freytherca6bc1d2009-10-05 14:00:14 +0200363 gh->data[0] = (want_imeisv & 0x1) << 4 | (ciph_mod_set & 0xf);
Holger Hans Peter Freytherea4088a2009-10-05 13:25:06 +0200364
365 return rsl_encryption_cmd(msg);
366}
367
Harald Welte8c83af62009-11-29 20:02:53 +0100368static void gsm48_cell_desc(struct gsm48_cell_desc *cd,
369 const struct gsm_bts *bts)
370{
371 cd->ncc = (bts->bsic >> 3 & 0x7);
372 cd->bcc = (bts->bsic & 0x7);
373 cd->arfcn_hi = bts->c0->arfcn >> 8;
374 cd->arfcn_lo = bts->c0->arfcn & 0xff;
375}
376
377static void gsm48_chan_desc(struct gsm48_chan_desc *cd,
378 const struct gsm_lchan *lchan)
379{
380 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
381
382 cd->chan_nr = lchan2chan_nr(lchan);
383 cd->h0.tsc = lchan->ts->trx->bts->tsc;
384 cd->h0.h = 0;
385 cd->h0.arfcn_high = arfcn >> 8;
386 cd->h0.arfcn_low = arfcn & 0xff;
387}
388
389/* Chapter 9.1.15: Handover Command */
Harald Welte7a7a0d52009-12-17 00:25:18 +0100390int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
391 u_int8_t power_command, u_int8_t ho_ref)
Harald Welte8c83af62009-11-29 20:02:53 +0100392{
393 struct msgb *msg = gsm48_msgb_alloc();
394 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
395 struct gsm48_ho_cmd *ho =
396 (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho));
Harald Welte8c83af62009-11-29 20:02:53 +0100397
398 msg->lchan = old_lchan;
Harald Welte7a7a0d52009-12-17 00:25:18 +0100399 gh->proto_discr = GSM48_PDISC_RR;
400 gh->msg_type = GSM48_MT_RR_HANDO_CMD;
Harald Welte8c83af62009-11-29 20:02:53 +0100401
402 /* mandatory bits */
403 gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts);
404 gsm48_chan_desc(&ho->chan_desc, new_lchan);
Harald Welte7a7a0d52009-12-17 00:25:18 +0100405 ho->ho_ref = ho_ref;
Harald Welte8c83af62009-11-29 20:02:53 +0100406 ho->power_command = power_command;
407
408 /* FIXME: optional bits for type of synchronization? */
409
410 return gsm48_sendmsg(msg, NULL);
411}
412
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200413/* Chapter 9.1.2: Assignment Command */
Holger Hans Peter Freyther550197f2010-01-28 09:43:49 +0100414int 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 +0200415{
416 struct msgb *msg = gsm48_msgb_alloc();
417 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
418 struct gsm48_ass_cmd *ass =
419 (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass));
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200420
421 DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
422
Holger Hans Peter Freyther550197f2010-01-28 09:43:49 +0100423 msg->lchan = dest_lchan;
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200424 gh->proto_discr = GSM48_PDISC_RR;
425 gh->msg_type = GSM48_MT_RR_ASS_CMD;
426
427 /*
428 * fill the channel information element, this code
429 * should probably be shared with rsl_rx_chan_rqd(),
430 * gsm48_tx_chan_mode_modify. But beware that 10.5.2.5
431 * 10.5.2.5.a have slightly different semantic for
432 * the chan_desc. But as long as multi-slot configurations
433 * are not used we seem to be fine.
434 */
Harald Welte8c83af62009-11-29 20:02:53 +0100435 gsm48_chan_desc(&ass->chan_desc, lchan);
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200436 ass->power_command = power_command;
437
Holger Hans Peter Freyther1b891fd2010-01-28 11:51:24 +0100438 msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode);
439
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100440 /* in case of multi rate we need to attach a config */
441 if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100442 if (lchan->mr_conf.ver == 0) {
Harald Welte50720e72009-12-24 11:50:20 +0100443 LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
444 "without multirate config.\n");
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100445 } else {
446 u_int8_t *data = msgb_put(msg, 4);
447 data[0] = GSM48_IE_MUL_RATE_CFG;
448 data[1] = 0x2;
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100449 memcpy(&data[2], &lchan->mr_conf, 2);
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100450 }
451 }
452
Holger Hans Peter Freythere81a6102009-10-22 11:47:45 +0200453 return gsm48_sendmsg(msg, NULL);
454}
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200455
456/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100457int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200458{
459 struct msgb *msg = gsm48_msgb_alloc();
460 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
461 struct gsm48_chan_mode_modify *cmm =
462 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
463 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
464
465 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
466
467 lchan->tch_mode = mode;
468 msg->lchan = lchan;
469 gh->proto_discr = GSM48_PDISC_RR;
470 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
471
472 /* fill the channel information element, this code
473 * should probably be shared with rsl_rx_chan_rqd() */
474 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
475 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
476 cmm->chan_desc.h0.h = 0;
477 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
478 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
479 cmm->mode = mode;
480
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100481 /* in case of multi rate we need to attach a config */
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100482 if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
483 if (lchan->mr_conf.ver == 0) {
Harald Welte50720e72009-12-24 11:50:20 +0100484 LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
485 "without multirate config.\n");
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100486 } else {
487 u_int8_t *data = msgb_put(msg, 4);
488 data[0] = GSM48_IE_MUL_RATE_CFG;
489 data[1] = 0x2;
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100490 memcpy(&data[2], &lchan->mr_conf, 2);
Holger Hans Peter Freythera6bcc742009-11-16 22:49:24 +0100491 }
492 }
493
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200494 return gsm48_sendmsg(msg, NULL);
495}
496
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100497int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode)
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200498{
499 int rc;
500
Holger Hans Peter Freytherea528022009-11-18 22:57:02 +0100501 rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode);
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200502 if (rc < 0)
503 return rc;
504
Holger Hans Peter Freytherff3f2602009-10-22 15:13:00 +0200505 return rc;
506}
507
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200508int gsm48_rx_rr_modif_ack(struct msgb *msg)
509{
Holger Hans Peter Freyther25b1e252009-11-18 19:30:24 +0100510 int rc;
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200511 struct gsm48_hdr *gh = msgb_l3(msg);
512 struct gsm48_chan_mode_modify *mod =
513 (struct gsm48_chan_mode_modify *) gh->data;
514
515 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
516
517 if (mod->mode != msg->lchan->tch_mode) {
Harald Welte50720e72009-12-24 11:50:20 +0100518 LOGP(DRR, LOGL_ERROR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n",
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200519 msg->lchan->tch_mode, mod->mode);
520 return -1;
521 }
522
523 /* update the channel type */
524 switch (mod->mode) {
525 case GSM48_CMODE_SIGN:
526 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
527 break;
528 case GSM48_CMODE_SPEECH_V1:
529 case GSM48_CMODE_SPEECH_EFR:
530 case GSM48_CMODE_SPEECH_AMR:
531 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
532 break;
533 case GSM48_CMODE_DATA_14k5:
534 case GSM48_CMODE_DATA_12k0:
535 case GSM48_CMODE_DATA_6k0:
536 case GSM48_CMODE_DATA_3k6:
537 msg->lchan->rsl_cmode = RSL_CMOD_SPD_DATA;
538 break;
539 }
540
541 /* We've successfully modified the MS side of the channel,
542 * now go on to modify the BTS side of the channel */
Holger Hans Peter Freyther25b1e252009-11-18 19:30:24 +0100543 rc = rsl_chan_mode_modify_req(msg->lchan);
544
545 /* FIXME: we not only need to do this after mode modify, but
546 * also after channel activation */
547 if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && mod->mode != GSM48_CMODE_SIGN)
548 rsl_ipacc_crcx(msg->lchan);
549 return rc;
Holger Hans Peter Freytherf520e642009-10-22 15:23:11 +0200550}
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100551
552int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
553{
554 struct gsm48_hdr *gh = msgb_l3(msg);
555 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
556 u_int8_t *data = gh->data;
557 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
558 struct bitvec *nbv = &bts->si_common.neigh_list;
Harald Weltea06c35e2009-12-25 22:46:25 +0100559 struct gsm_meas_rep_cell *mrc;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100560
561 if (gh->msg_type != GSM48_MT_RR_MEAS_REP)
562 return -EINVAL;
563
564 if (data[0] & 0x80)
565 rep->flags |= MEAS_REP_F_BA1;
566 if (data[0] & 0x40)
567 rep->flags |= MEAS_REP_F_UL_DTX;
568 if ((data[1] & 0x40) == 0x00)
569 rep->flags |= MEAS_REP_F_DL_VALID;
570
571 rep->dl.full.rx_lev = data[0] & 0x3f;
572 rep->dl.sub.rx_lev = data[1] & 0x3f;
573 rep->dl.full.rx_qual = (data[3] >> 4) & 0x7;
574 rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7;
575
576 rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2);
577 if (rep->num_cell < 1 || rep->num_cell > 6)
578 return 0;
579
580 /* an encoding nightmare in perfection */
Harald Weltea06c35e2009-12-25 22:46:25 +0100581 mrc = &rep->cell[0];
582 mrc->rxlev = data[3] & 0x3f;
Harald Welte950eca92009-12-25 22:49:34 +0100583 mrc->neigh_idx = data[4] >> 3;
Harald Welteeaa95d52009-12-25 23:01:54 +0100584 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100585 mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5);
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100586 if (rep->num_cell < 2)
587 return 0;
588
Harald Weltea06c35e2009-12-25 22:46:25 +0100589 mrc = &rep->cell[1];
590 mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7);
Harald Welte950eca92009-12-25 22:49:34 +0100591 mrc->neigh_idx = (data[6] >> 2) & 0x1f;
Harald Welteeaa95d52009-12-25 23:01:54 +0100592 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100593 mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4);
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100594 if (rep->num_cell < 3)
595 return 0;
596
Harald Weltea06c35e2009-12-25 22:46:25 +0100597 mrc = &rep->cell[2];
598 mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6);
Harald Welte950eca92009-12-25 22:49:34 +0100599 mrc->neigh_idx = (data[8] >> 1) & 0x1f;
Harald Welteeaa95d52009-12-25 23:01:54 +0100600 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Welte (local)65898582009-12-26 14:12:43 +0100601 mrc->bsic = ((data[8] & 0x01) << 5) | (data[9] >> 3);
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100602 if (rep->num_cell < 4)
603 return 0;
604
Harald Weltea06c35e2009-12-25 22:46:25 +0100605 mrc = &rep->cell[3];
606 mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5);
Harald Welte950eca92009-12-25 22:49:34 +0100607 mrc->neigh_idx = data[10] & 0x1f;
Harald Welteeaa95d52009-12-25 23:01:54 +0100608 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100609 mrc->bsic = data[11] >> 2;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100610 if (rep->num_cell < 5)
611 return 0;
612
Harald Weltea06c35e2009-12-25 22:46:25 +0100613 mrc = &rep->cell[4];
614 mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4);
Harald Welte950eca92009-12-25 22:49:34 +0100615 mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7);
Harald Welteeaa95d52009-12-25 23:01:54 +0100616 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100617 mrc->bsic = (data[13] >> 1) & 0x3f;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100618 if (rep->num_cell < 6)
619 return 0;
620
Harald Weltea06c35e2009-12-25 22:46:25 +0100621 mrc = &rep->cell[5];
Harald Welte950eca92009-12-25 22:49:34 +0100622 mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3);
623 mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6);
Harald Welteeaa95d52009-12-25 23:01:54 +0100624 mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
Harald Weltea06c35e2009-12-25 22:46:25 +0100625 mrc->bsic = data[15] & 0x3f;
Holger Hans Peter Freyther92ffd922009-12-22 07:45:17 +0100626
627 return 0;
628}
629