blob: a9f2ebd8eaf348f3bfec1c9a065444b7863cac81 [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* 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
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30#include <time.h>
31#include <netinet/in.h>
32
33#include <openbsc/db.h>
34#include <openbsc/msgb.h>
35#include <openbsc/tlv.h>
36#include <openbsc/debug.h>
37#include <openbsc/gsm_data.h>
38#include <openbsc/gsm_subscriber.h>
39#include <openbsc/gsm_04_11.h>
40#include <openbsc/gsm_04_08.h>
41#include <openbsc/abis_rsl.h>
42#include <openbsc/chan_alloc.h>
43#include <openbsc/paging.h>
44#include <openbsc/signal.h>
45#include <openbsc/trau_frame.h>
46#include <openbsc/trau_mux.h>
Harald Weltea8379772009-06-20 22:36:41 +020047#include <openbsc/talloc.h>
Harald Weltea54b48d2009-07-23 18:56:43 +020048#include <openbsc/transaction.h>
Harald Welte59b04682009-06-10 05:40:52 +080049
50#define GSM48_ALLOC_SIZE 1024
51#define GSM48_ALLOC_HEADROOM 128
52
Harald Welteb8a18b52009-06-10 12:08:54 +080053#define GSM_MAX_FACILITY 128
54#define GSM_MAX_SSVERSION 128
55#define GSM_MAX_USERUSER 128
56
Harald Weltea8379772009-06-20 22:36:41 +020057static void *tall_locop_ctx;
Harald Weltea8379772009-06-20 22:36:41 +020058
Harald Welte59b04682009-06-10 05:40:52 +080059static const struct tlv_definition rsl_att_tlvdef = {
60 .def = {
61 [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
62 [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
63 [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
64 [GSM48_IE_UTC] = { TLV_TYPE_TV },
65 [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
66 [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
67
68 [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
69 [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
70 [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
71 [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
72 [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
73 [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
74 [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
Harald Welteb8a18b52009-06-10 12:08:54 +080075 [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
Harald Welte59b04682009-06-10 05:40:52 +080076 [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
77 [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
Harald Welteb8a18b52009-06-10 12:08:54 +080078 [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
79 [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
Harald Welte59b04682009-06-10 05:40:52 +080080 [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
81 [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
82 [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
83 [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
84 [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
85 [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
86 [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
87 [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
88 [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
89 [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
90 [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
91 [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
92 [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
93 [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
Harald Welteb8a18b52009-06-10 12:08:54 +080094 [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
95 [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
Harald Welte59b04682009-06-10 05:40:52 +080096 /* FIXME: more elements */
97 },
98};
99
100static const char *rr_cause_names[] = {
101 [GSM48_RR_CAUSE_NORMAL] = "Normal event",
102 [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
103 [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
104 [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
105 [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
106 [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
107 [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
108 [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
109 [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
110 [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
111 [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
112 [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
113 [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
114 [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
115 [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
116 [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
117 [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
118};
119
Harald Welte03740842009-06-10 23:11:52 +0800120static const char *cc_state_names[] = {
121 "NULL",
122 "INITIATED",
123 "illegal state 2",
124 "MO_CALL_PROC",
125 "CALL_DELIVERED",
126 "illegal state 5",
127 "CALL_PRESENT",
128 "CALL_RECEIVED",
129 "CONNECT_REQUEST",
130 "MO_TERM_CALL_CONF",
131 "ACTIVE",
132 "DISCONNECT_REQ",
133 "DISCONNECT_IND",
134 "illegal state 13",
135 "illegal state 14",
136 "illegal state 15",
137 "illegal state 16",
138 "illegal state 17",
139 "illegal state 18",
140 "RELEASE_REQ",
141 "illegal state 20",
142 "illegal state 21",
143 "illegal state 22",
144 "illegal state 23",
145 "illegal state 24",
146 "illegal state 25",
147 "MO_ORIG_MODIFY",
148 "MO_TERM_MODIFY",
149 "CONNECT_IND",
150 "illegal state 29",
151 "illegal state 30",
152 "illegal state 31",
153};
154
155static const char *cc_msg_names[] = {
156 "unknown 0x00",
157 "ALERTING",
158 "CALL_PROC",
159 "PROGRESS",
160 "ESTAB",
161 "SETUP",
162 "ESTAB_CONF",
163 "CONNECT",
164 "CALL_CONF",
165 "START_CC",
166 "unknown 0x0a",
167 "RECALL",
168 "unknown 0x0c",
169 "unknown 0x0d",
170 "EMERG_SETUP",
171 "CONNECT_ACK",
172 "USER_INFO",
173 "unknown 0x11",
174 "unknown 0x12",
175 "MODIFY_REJECT",
176 "unknown 0x14",
177 "unknown 0x15",
178 "unknown 0x16",
179 "MODIFY",
180 "HOLD",
181 "HOLD_ACK",
182 "HOLD_REJ",
183 "unknown 0x1b",
184 "RETR",
185 "RETR_ACK",
186 "RETR_REJ",
187 "MODIFY_COMPL",
188 "unknown 0x20",
189 "unknown 0x21",
190 "unknown 0x22",
191 "unknown 0x23",
192 "unknown 0x24",
193 "DISCONNECT",
194 "unknown 0x26",
195 "unknown 0x27",
196 "unknown 0x28",
197 "unknown 0x29",
198 "RELEASE_COMPL",
199 "unknown 0x2b",
200 "unknown 0x2c",
201 "RELEASE",
202 "unknown 0x2e",
203 "unknown 0x2f",
204 "unknown 0x30",
205 "STOP_DTMF",
206 "STOP_DTMF_ACK",
207 "unknown 0x33",
208 "STATUS_ENQ",
209 "START_DTMF",
210 "START_DTMF_ACK",
211 "START_DTMF_REJ",
212 "unknown 0x38",
213 "CONG_CTRL",
214 "FACILITY",
215 "unknown 0x3b",
216 "STATUS",
217 "unknown 0x3c",
218 "NOTIFY",
219 "unknown 0x3f",
220};
221
Harald Welte59b04682009-06-10 05:40:52 +0800222static char strbuf[64];
223
224static const char *rr_cause_name(u_int8_t cause)
225{
226 if (cause < ARRAY_SIZE(rr_cause_names) &&
227 rr_cause_names[cause])
228 return rr_cause_names[cause];
229
230 snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
231 return strbuf;
232}
233
234static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
235 int len)
236{
237 memset(rep, 0, sizeof(*rep));
238
239 if (data[0] & 0x80)
240 rep->flags |= MEAS_REP_F_BA1;
241 if (data[0] & 0x40)
242 rep->flags |= MEAS_REP_F_DTX;
243 if (data[1] & 0x40)
244 rep->flags |= MEAS_REP_F_VALID;
245
246 rep->rxlev_full = data[0] & 0x3f;
247 rep->rxlev_sub = data[1] & 0x3f;
248 rep->rxqual_full = (data[3] >> 4) & 0x7;
249 rep->rxqual_sub = (data[3] >> 1) & 0x7;
250 rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2);
251 if (rep->num_cell < 1)
252 return;
253
254 /* an encoding nightmare in perfection */
255
256 rep->cell[0].rxlev = data[4] & 0x3f;
257 rep->cell[0].bcch_freq = data[5] >> 2;
258 rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5);
259 if (rep->num_cell < 2)
260 return;
261
262 rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7);
263 rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f;
264 rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4);
265 if (rep->num_cell < 3)
266 return;
267
268 rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6);
269 rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f;
270 rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3);
271 if (rep->num_cell < 4)
272 return;
273
274 rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5);
275 rep->cell[3].bcch_freq = data[11] & 0x1f;
276 rep->cell[3].bsic = data[12] >> 2;
277 if (rep->num_cell < 5)
278 return;
279
280 rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4);
281 rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7);
282 rep->cell[4].bsic = (data[14] >> 1) & 0x3f;
283 if (rep->num_cell < 6)
284 return;
285
286 rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3);
287 rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6);
288 rep->cell[5].bsic = data[16] & 0x3f;
289}
290
291int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
292static int gsm48_tx_simple(struct gsm_lchan *lchan,
293 u_int8_t pdisc, u_int8_t msg_type);
294static void schedule_reject(struct gsm_lchan *lchan);
295
296struct gsm_lai {
297 u_int16_t mcc;
298 u_int16_t mnc;
299 u_int16_t lac;
300};
301
302static int authorize_everonye = 0;
303void gsm0408_allow_everyone(int everyone)
304{
305 printf("Allowing everyone?\n");
306 authorize_everonye = everyone;
307}
308
309static int reject_cause = 0;
310void gsm0408_set_reject_cause(int cause)
311{
312 reject_cause = cause;
313}
314
Harald Welte03740842009-06-10 23:11:52 +0800315static u_int32_t new_callref = 0x80000001;
316
Harald Welte59b04682009-06-10 05:40:52 +0800317static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
318 struct gsm_subscriber *subscriber)
319{
320 if (!subscriber)
321 return 0;
322
323 /*
324 * Do not send accept yet as more information should arrive. Some
325 * phones will not send us the information and we will have to check
326 * what we want to do with that.
327 */
328 if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
329 return 0;
330
331 if (authorize_everonye)
332 return 1;
333
334 return subscriber->authorized;
335}
336
337static void release_loc_updating_req(struct gsm_lchan *lchan)
338{
339 if (!lchan->loc_operation)
340 return;
341
342 bsc_del_timer(&lchan->loc_operation->updating_timer);
Harald Weltea8379772009-06-20 22:36:41 +0200343 talloc_free(lchan->loc_operation);
Harald Welte59b04682009-06-10 05:40:52 +0800344 lchan->loc_operation = 0;
345 put_lchan(lchan);
346}
347
348static void allocate_loc_updating_req(struct gsm_lchan *lchan)
349{
350 use_lchan(lchan);
351 release_loc_updating_req(lchan);
352
Harald Welte857e00d2009-06-26 20:25:23 +0200353 lchan->loc_operation = talloc_zero(tall_locop_ctx,
354 struct gsm_loc_updating_operation);
Harald Welte59b04682009-06-10 05:40:52 +0800355}
356
357static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
358{
359 u_int32_t tmsi;
360
361 if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
362 db_subscriber_alloc_tmsi(lchan->subscr);
363 subscr_update(lchan->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED);
364 tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
365 release_loc_updating_req(lchan);
366 return gsm0408_loc_upd_acc(msg->lchan, tmsi);
367 }
368
369 return 0;
370}
371
372static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
373 void *handler_data, void *signal_data)
374{
Harald Welte03740842009-06-10 23:11:52 +0800375 struct gsm_trans *trans, *temp;
376
Harald Welte59b04682009-06-10 05:40:52 +0800377 if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
378 return 0;
379
380 /*
381 * Cancel any outstanding location updating request
382 * operation taking place on the lchan.
383 */
Harald Welte12560da2009-07-04 09:35:21 +0200384 struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
Harald Welte1ff81b52009-06-26 20:17:06 +0200385 if (!lchan)
386 return 0;
387
Harald Welte59b04682009-06-10 05:40:52 +0800388 release_loc_updating_req(lchan);
389
Harald Welte03740842009-06-10 23:11:52 +0800390 /* Free all transactions that are associated with the released lchan */
Harald Weltea54b48d2009-07-23 18:56:43 +0200391 /* FIXME: this is not neccessarily the right thing to do, we should
392 * only set trans->lchan to NULL and wait for another lchan to be
393 * established to the same MM entity (phone/subscriber) */
Harald Welte03740842009-06-10 23:11:52 +0800394 llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
395 if (trans->lchan == lchan)
Harald Weltea54b48d2009-07-23 18:56:43 +0200396 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +0800397 }
398
Harald Welte59b04682009-06-10 05:40:52 +0800399 return 0;
400}
401
402/*
403 * This will be ran by the linker when loading the DSO. We use it to
404 * do system initialization, e.g. registration of signal handlers.
405 */
406static __attribute__((constructor)) void on_dso_load_0408(void)
407{
Harald Welte932e20d2009-07-28 00:41:45 +0200408 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
409 "loc_updating_oper");
Harald Welte59b04682009-06-10 05:40:52 +0800410 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
411}
412
413static void to_bcd(u_int8_t *bcd, u_int16_t val)
414{
415 bcd[2] = val % 10;
416 val = val / 10;
417 bcd[1] = val % 10;
418 val = val / 10;
419 bcd[0] = val % 10;
420 val = val / 10;
421}
422
423void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
424 u_int16_t mnc, u_int16_t lac)
425{
426 u_int8_t bcd[3];
427
428 to_bcd(bcd, mcc);
429 lai48->digits[0] = bcd[0] | (bcd[1] << 4);
430 lai48->digits[1] = bcd[2];
431
432 to_bcd(bcd, mnc);
433 /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
434#if 0
435 lai48->digits[1] |= bcd[2] << 4;
436 lai48->digits[2] = bcd[0] | (bcd[1] << 4);
437#else
438 lai48->digits[1] |= 0xf << 4;
439 lai48->digits[2] = bcd[1] | (bcd[2] << 4);
440#endif
441
442 lai48->lac = htons(lac);
443}
444
445#define TMSI_LEN 5
446#define MID_TMSI_LEN (TMSI_LEN + 2)
447
448int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
449{
450 u_int32_t *tptr = (u_int32_t *) &buf[3];
451
452 buf[0] = GSM48_IE_MOBILE_ID;
453 buf[1] = TMSI_LEN;
454 buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
455 *tptr = htonl(tmsi);
456
457 return 7;
458}
459
460static const char bcd_num_digits[] = {
461 '0', '1', '2', '3', '4', '5', '6', '7',
462 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
463};
464
Harald Welteb8a18b52009-06-10 12:08:54 +0800465/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
466int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
467 int h_len)
Harald Welte59b04682009-06-10 05:40:52 +0800468{
469 u_int8_t in_len = bcd_lv[0];
470 int i;
471
Harald Welteb8a18b52009-06-10 12:08:54 +0800472 for (i = 1 + h_len; i <= in_len; i++) {
Harald Welte59b04682009-06-10 05:40:52 +0800473 /* lower nibble */
474 output_len--;
475 if (output_len <= 1)
476 break;
477 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
478
479 /* higher nibble */
480 output_len--;
481 if (output_len <= 1)
482 break;
483 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
484 }
485 if (output_len >= 1)
486 *output++ = '\0';
487
Harald Welteb8a18b52009-06-10 12:08:54 +0800488 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800489}
490
491/* convert a single ASCII character to call-control BCD */
492static int asc_to_bcd(const char asc)
493{
494 int i;
495
496 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
497 if (bcd_num_digits[i] == asc)
498 return i;
499 }
500 return -EINVAL;
501}
502
Harald Welteb8a18b52009-06-10 12:08:54 +0800503/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
Harald Welte59b04682009-06-10 05:40:52 +0800504int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
Harald Welteb8a18b52009-06-10 12:08:54 +0800505 int h_len, const char *input)
Harald Welte59b04682009-06-10 05:40:52 +0800506{
507 int in_len = strlen(input);
508 int i;
Harald Welteb8a18b52009-06-10 12:08:54 +0800509 u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
Harald Welte59b04682009-06-10 05:40:52 +0800510
511 /* two digits per byte, plus type byte */
Harald Welteb8a18b52009-06-10 12:08:54 +0800512 bcd_lv[0] = in_len/2 + h_len;
Harald Welte59b04682009-06-10 05:40:52 +0800513 if (in_len % 2)
514 bcd_lv[0]++;
515
Harald Welteb8a18b52009-06-10 12:08:54 +0800516 if (bcd_lv[0] > max_len)
517 return -EIO;
Harald Welte59b04682009-06-10 05:40:52 +0800518
519 for (i = 0; i < in_len; i++) {
520 int rc = asc_to_bcd(input[i]);
521 if (rc < 0)
522 return rc;
523 if (i % 2 == 0)
524 *bcd_cur = rc;
525 else
526 *bcd_cur++ |= (rc << 4);
527 }
528 /* append padding nibble in case of odd length */
529 if (i % 2)
530 *bcd_cur++ |= 0xf0;
531
532 /* return how many bytes we used */
533 return (bcd_cur - bcd_lv);
534}
535
Harald Welteb8a18b52009-06-10 12:08:54 +0800536/* decode 'bearer capability' */
Harald Welte03740842009-06-10 23:11:52 +0800537static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
Harald Welteb8a18b52009-06-10 12:08:54 +0800538 const u_int8_t *lv)
539{
540 u_int8_t in_len = lv[0];
541 int i, s;
542
543 if (in_len < 1)
544 return -EINVAL;
545
Harald Welte03740842009-06-10 23:11:52 +0800546 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
Harald Welteb8a18b52009-06-10 12:08:54 +0800547
548 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800549 bcap->transfer = lv[1] & 0x07;
550 bcap->mode = (lv[1] & 0x08) >> 3;
551 bcap->coding = (lv[1] & 0x10) >> 4;
552 bcap->radio = (lv[1] & 0x60) >> 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800553
554 i = 1;
555 s = 0;
556 while(!(lv[i] & 0x80)) {
557 i++; /* octet 3a etc */
558 if (in_len < i)
559 return 0;
Harald Welte03740842009-06-10 23:11:52 +0800560 bcap->speech_ver[s++] = lv[i] & 0x0f;
561 bcap->speech_ver[s] = -1; /* end of list */
Harald Welteb8a18b52009-06-10 12:08:54 +0800562 if (i == 2) /* octet 3a */
Harald Welte03740842009-06-10 23:11:52 +0800563 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800564 if (s == 7) /* maximum speech versions + end of list */
565 return 0;
566 }
567
568 return 0;
569}
570
571/* encode 'bearer capability' */
Harald Welte03740842009-06-10 23:11:52 +0800572static int encode_bearer_cap(struct msgb *msg, int lv_only,
573 const struct gsm_mncc_bearer_cap *bcap)
Harald Welteb8a18b52009-06-10 12:08:54 +0800574{
575 u_int8_t lv[32 + 1];
576 int i, s;
577
Harald Welte03740842009-06-10 23:11:52 +0800578 lv[1] = bcap->transfer;
579 lv[1] |= bcap->mode << 3;
580 lv[1] |= bcap->coding << 4;
581 lv[1] |= bcap->radio << 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800582
583 i = 1;
Harald Welte03740842009-06-10 23:11:52 +0800584 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
Harald Welteb8a18b52009-06-10 12:08:54 +0800585 i++; /* octet 3a etc */
Harald Welte03740842009-06-10 23:11:52 +0800586 lv[i] = bcap->speech_ver[s];
Harald Welteb8a18b52009-06-10 12:08:54 +0800587 if (i == 2) /* octet 3a */
Harald Welte03740842009-06-10 23:11:52 +0800588 lv[i] |= bcap->speech_ctm << 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800589 }
590 lv[i] |= 0x80; /* last IE of octet 3 etc */
591
592 lv[0] = i;
593 if (lv_only)
594 msgb_lv_put(msg, lv[0], lv+1);
595 else
596 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
597
598 return 0;
599}
600
601/* decode 'call control cap' */
Harald Welte03740842009-06-10 23:11:52 +0800602static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
Harald Welteb8a18b52009-06-10 12:08:54 +0800603{
604 u_int8_t in_len = lv[0];
605
606 if (in_len < 1)
607 return -EINVAL;
608
609 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800610 ccap->dtmf = lv[1] & 0x01;
611 ccap->pcp = (lv[1] & 0x02) >> 1;
Harald Welteb8a18b52009-06-10 12:08:54 +0800612
613 return 0;
614}
615
616/* decode 'called party BCD number' */
Harald Welte03740842009-06-10 23:11:52 +0800617static int decode_called(struct gsm_mncc_number *called,
618 const u_int8_t *lv)
Harald Welteb8a18b52009-06-10 12:08:54 +0800619{
620 u_int8_t in_len = lv[0];
621
622 if (in_len < 1)
623 return -EINVAL;
624
625 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800626 called->plan = lv[1] & 0x0f;
627 called->type = (lv[1] & 0x70) >> 4;
Harald Welteb8a18b52009-06-10 12:08:54 +0800628
629 /* octet 4..N */
Harald Welte03740842009-06-10 23:11:52 +0800630 decode_bcd_number(called->number, sizeof(called->number), lv, 1);
Harald Welteb8a18b52009-06-10 12:08:54 +0800631
632 return 0;
633}
634
635/* encode 'called party BCD number' */
Harald Welte03740842009-06-10 23:11:52 +0800636static int encode_called(struct msgb *msg,
637 const struct gsm_mncc_number *called)
Harald Welteb8a18b52009-06-10 12:08:54 +0800638{
639 u_int8_t lv[18];
640 int ret;
641
642 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800643 lv[1] = called->plan;
644 lv[1] |= called->type << 4;
Harald Welteb8a18b52009-06-10 12:08:54 +0800645
646 /* octet 4..N, octet 2 */
Harald Welte03740842009-06-10 23:11:52 +0800647 ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
Harald Welteb8a18b52009-06-10 12:08:54 +0800648 if (ret < 0)
649 return ret;
650
651 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
652
653 return 0;
654}
655
656/* encode callerid of various IEs */
Harald Welte03740842009-06-10 23:11:52 +0800657static int encode_callerid(struct msgb *msg, int ie,
658 const struct gsm_mncc_number *callerid)
Harald Welteb8a18b52009-06-10 12:08:54 +0800659{
660 u_int8_t lv[13];
661 int h_len = 1;
662 int ret;
663
664 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800665 lv[1] = callerid->plan;
666 lv[1] |= callerid->type << 4;
Harald Welteb8a18b52009-06-10 12:08:54 +0800667
Harald Welte03740842009-06-10 23:11:52 +0800668 if (callerid->present || callerid->screen) {
Harald Welteb8a18b52009-06-10 12:08:54 +0800669 /* octet 3a */
Harald Welte03740842009-06-10 23:11:52 +0800670 lv[2] = callerid->screen;
671 lv[2] |= callerid->present << 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800672 lv[2] |= 0x80;
673 h_len++;
674 } else
675 lv[1] |= 0x80;
676
677 /* octet 4..N, octet 2 */
Harald Welte03740842009-06-10 23:11:52 +0800678 ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
Harald Welteb8a18b52009-06-10 12:08:54 +0800679 if (ret < 0)
680 return ret;
681
682 msgb_tlv_put(msg, ie, lv[0], lv+1);
683
684 return 0;
685}
686
687/* decode 'cause' */
Harald Welte03740842009-06-10 23:11:52 +0800688static int decode_cause(struct gsm_mncc_cause *cause,
Harald Welteb8a18b52009-06-10 12:08:54 +0800689 const u_int8_t *lv)
690{
691 u_int8_t in_len = lv[0];
692 int i;
693
694 if (in_len < 2)
695 return -EINVAL;
696
Harald Welte03740842009-06-10 23:11:52 +0800697 cause->diag_len = 0;
Harald Welteb8a18b52009-06-10 12:08:54 +0800698
699 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800700 cause->location = lv[1] & 0x0f;
701 cause->coding = (lv[1] & 0x60) >> 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800702
703 i = 1;
704 if (!(lv[i] & 0x80)) {
705 i++; /* octet 3a */
706 if (in_len < i+1)
707 return 0;
Harald Welte03740842009-06-10 23:11:52 +0800708 cause->rec = 1;
709 cause->rec_val = lv[i] & 0x7f;
Harald Welteb8a18b52009-06-10 12:08:54 +0800710
711 }
712 i++;
713
714 /* octet 4 */
Harald Welte03740842009-06-10 23:11:52 +0800715 cause->value = lv[i] & 0x7f;
Harald Welteb8a18b52009-06-10 12:08:54 +0800716 i++;
717
718 if (in_len < i) /* no diag */
719 return 0;
720
721 if (in_len - (i-1) > 32) /* maximum 32 octets */
722 return 0;
723
724 /* octet 5-N */
Harald Welte03740842009-06-10 23:11:52 +0800725 memcpy(cause->diag, lv + i, in_len - (i-1));
726 cause->diag_len = in_len - (i-1);
Harald Welteb8a18b52009-06-10 12:08:54 +0800727
728 return 0;
729}
730
731/* encode 'cause' */
Harald Welte03740842009-06-10 23:11:52 +0800732static int encode_cause(struct msgb *msg, int lv_only,
733 const struct gsm_mncc_cause *cause)
Harald Welteb8a18b52009-06-10 12:08:54 +0800734{
735 u_int8_t lv[32+4];
736 int i;
737
Harald Welte03740842009-06-10 23:11:52 +0800738 if (cause->diag_len > 32)
Harald Welteb8a18b52009-06-10 12:08:54 +0800739 return -EINVAL;
740
741 /* octet 3 */
Harald Welte03740842009-06-10 23:11:52 +0800742 lv[1] = cause->location;
743 lv[1] |= cause->coding << 5;
Harald Welteb8a18b52009-06-10 12:08:54 +0800744
745 i = 1;
Harald Welte03740842009-06-10 23:11:52 +0800746 if (cause->rec) {
Harald Welteb8a18b52009-06-10 12:08:54 +0800747 i++; /* octet 3a */
Harald Welte03740842009-06-10 23:11:52 +0800748 lv[i] = cause->rec_val;
Harald Welteb8a18b52009-06-10 12:08:54 +0800749 }
750 lv[i] |= 0x80; /* end of octet 3 */
751
752 /* octet 4 */
753 i++;
Harald Welte03740842009-06-10 23:11:52 +0800754 lv[i] = 0x80 | cause->value;
Harald Welteb8a18b52009-06-10 12:08:54 +0800755
756 /* octet 5-N */
Harald Welte03740842009-06-10 23:11:52 +0800757 if (cause->diag_len) {
758 memcpy(lv + i, cause->diag, cause->diag_len);
759 i += cause->diag_len;
Harald Welteb8a18b52009-06-10 12:08:54 +0800760 }
761
762 lv[0] = i;
763 if (lv_only)
764 msgb_lv_put(msg, lv[0], lv+1);
765 else
766 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
767
768 return 0;
769}
770
771/* encode 'calling number' */
Harald Welte03740842009-06-10 23:11:52 +0800772static int encode_calling(struct msgb *msg,
773 const struct gsm_mncc_number *calling)
Harald Welteb8a18b52009-06-10 12:08:54 +0800774{
Harald Welte03740842009-06-10 23:11:52 +0800775 return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
Harald Welteb8a18b52009-06-10 12:08:54 +0800776}
777
778/* encode 'connected number' */
Harald Welte03740842009-06-10 23:11:52 +0800779static int encode_connected(struct msgb *msg,
780 const struct gsm_mncc_number *connected)
Harald Welteb8a18b52009-06-10 12:08:54 +0800781{
Harald Welte03740842009-06-10 23:11:52 +0800782 return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
Harald Welteb8a18b52009-06-10 12:08:54 +0800783}
784
785/* encode 'redirecting number' */
Harald Welte03740842009-06-10 23:11:52 +0800786static int encode_redirecting(struct msgb *msg,
787 const struct gsm_mncc_number *redirecting)
Harald Welteb8a18b52009-06-10 12:08:54 +0800788{
Harald Welte03740842009-06-10 23:11:52 +0800789 return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
Harald Welteb8a18b52009-06-10 12:08:54 +0800790}
791
792/* decode 'facility' */
Harald Welte03740842009-06-10 23:11:52 +0800793static int decode_facility(struct gsm_mncc_facility *facility,
Harald Welteb8a18b52009-06-10 12:08:54 +0800794 const u_int8_t *lv)
795{
796 u_int8_t in_len = lv[0];
797
798 if (in_len < 1)
799 return -EINVAL;
800
Harald Welte03740842009-06-10 23:11:52 +0800801 if (in_len > sizeof(facility->info))
Harald Welteb8a18b52009-06-10 12:08:54 +0800802 return -EINVAL;
803
Harald Welte03740842009-06-10 23:11:52 +0800804 memcpy(facility->info, lv+1, in_len);
805 facility->len = in_len;
Harald Welteb8a18b52009-06-10 12:08:54 +0800806
807 return 0;
808}
809
810/* encode 'facility' */
Harald Welte03740842009-06-10 23:11:52 +0800811static int encode_facility(struct msgb *msg, int lv_only,
812 const struct gsm_mncc_facility *facility)
Harald Welteb8a18b52009-06-10 12:08:54 +0800813{
814 u_int8_t lv[GSM_MAX_FACILITY + 1];
815
Harald Welte03740842009-06-10 23:11:52 +0800816 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
Harald Welteb8a18b52009-06-10 12:08:54 +0800817 return -EINVAL;
818
Harald Welte03740842009-06-10 23:11:52 +0800819 memcpy(lv+1, facility->info, facility->len);
820 lv[0] = facility->len;
Harald Welteb8a18b52009-06-10 12:08:54 +0800821 if (lv_only)
822 msgb_lv_put(msg, lv[0], lv+1);
823 else
824 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
825
826 return 0;
827}
828
829/* decode 'notify' */
830static int decode_notify(int *notify, const u_int8_t *v)
831{
832 *notify = v[0] & 0x7f;
833
834 return 0;
835}
836
837/* encode 'notify' */
838static int encode_notify(struct msgb *msg, int notify)
839{
840 msgb_v_put(msg, notify | 0x80);
841
842 return 0;
843}
844
845/* encode 'signal' */
846static int encode_signal(struct msgb *msg, int signal)
847{
848 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
849
850 return 0;
851}
852
853/* decode 'keypad' */
854static int decode_keypad(int *keypad, const u_int8_t *lv)
855{
856 u_int8_t in_len = lv[0];
857
858 if (in_len < 1)
859 return -EINVAL;
860
861 *keypad = lv[1] & 0x7f;
862
863 return 0;
864}
865
866/* encode 'keypad' */
867static int encode_keypad(struct msgb *msg, int keypad)
868{
869 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
870
871 return 0;
872}
873
874/* decode 'progress' */
Harald Welte03740842009-06-10 23:11:52 +0800875static int decode_progress(struct gsm_mncc_progress *progress,
Harald Welteb8a18b52009-06-10 12:08:54 +0800876 const u_int8_t *lv)
877{
878 u_int8_t in_len = lv[0];
879
880 if (in_len < 2)
881 return -EINVAL;
882
Harald Welte03740842009-06-10 23:11:52 +0800883 progress->coding = (lv[1] & 0x60) >> 5;
884 progress->location = lv[1] & 0x0f;
885 progress->descr = lv[2] & 0x7f;
Harald Welteb8a18b52009-06-10 12:08:54 +0800886
887 return 0;
888}
889
890/* encode 'progress' */
Harald Welte03740842009-06-10 23:11:52 +0800891static int encode_progress(struct msgb *msg, int lv_only,
892 const struct gsm_mncc_progress *p)
Harald Welteb8a18b52009-06-10 12:08:54 +0800893{
894 u_int8_t lv[3];
895
896 lv[0] = 2;
Harald Welte03740842009-06-10 23:11:52 +0800897 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
898 lv[2] = 0x80 | (p->descr & 0x7f);
Harald Welteb8a18b52009-06-10 12:08:54 +0800899 if (lv_only)
900 msgb_lv_put(msg, lv[0], lv+1);
901 else
902 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
903
904 return 0;
905}
906
907/* decode 'user-user' */
Harald Welte03740842009-06-10 23:11:52 +0800908static int decode_useruser(struct gsm_mncc_useruser *uu,
Harald Welteb8a18b52009-06-10 12:08:54 +0800909 const u_int8_t *lv)
910{
911 u_int8_t in_len = lv[0];
Harald Welte03740842009-06-10 23:11:52 +0800912 char *info = uu->info;
913 int info_len = sizeof(uu->info);
Harald Welteb8a18b52009-06-10 12:08:54 +0800914 int i;
915
916 if (in_len < 1)
917 return -EINVAL;
918
Harald Welte03740842009-06-10 23:11:52 +0800919 uu->proto = lv[1];
Harald Welteb8a18b52009-06-10 12:08:54 +0800920
921 for (i = 2; i <= in_len; i++) {
922 info_len--;
923 if (info_len <= 1)
924 break;
925 *info++ = lv[i];
926 }
927 if (info_len >= 1)
928 *info++ = '\0';
929
930 return 0;
931}
932
933/* encode 'useruser' */
Harald Welte03740842009-06-10 23:11:52 +0800934static int encode_useruser(struct msgb *msg, int lv_only,
935 const struct gsm_mncc_useruser *uu)
Harald Welteb8a18b52009-06-10 12:08:54 +0800936{
937 u_int8_t lv[GSM_MAX_USERUSER + 2];
938
Harald Welte03740842009-06-10 23:11:52 +0800939 if (strlen(uu->info) > GSM_MAX_USERUSER)
Harald Welteb8a18b52009-06-10 12:08:54 +0800940 return -EINVAL;
941
Harald Welte03740842009-06-10 23:11:52 +0800942 lv[0] = 1 + strlen(uu->info);
943 lv[1] = uu->proto;
944 memcpy(lv + 2, uu->info, strlen(uu->info));
Harald Welteb8a18b52009-06-10 12:08:54 +0800945 if (lv_only)
946 msgb_lv_put(msg, lv[0], lv+1);
947 else
948 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
949
950 return 0;
951}
952
953/* decode 'ss version' */
Harald Welte03740842009-06-10 23:11:52 +0800954static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
Harald Welteb8a18b52009-06-10 12:08:54 +0800955 const u_int8_t *lv)
956{
957 u_int8_t in_len = lv[0];
958
Harald Welte03740842009-06-10 23:11:52 +0800959 if (in_len < 1 || in_len < sizeof(ssv->info))
Harald Welteb8a18b52009-06-10 12:08:54 +0800960 return -EINVAL;
961
Harald Welte03740842009-06-10 23:11:52 +0800962 memcpy(ssv->info, lv + 1, in_len);
963 ssv->len = in_len;
Harald Welteb8a18b52009-06-10 12:08:54 +0800964
965 return 0;
966}
967
968/* encode 'more data' */
969static int encode_more(struct msgb *msg)
970{
971 u_int8_t *ie;
972
973 ie = msgb_put(msg, 1);
974 ie[0] = GSM48_IE_MORE_DATA;
975
976 return 0;
977}
978
Harald Welte59b04682009-06-10 05:40:52 +0800979struct msgb *gsm48_msgb_alloc(void)
980{
Harald Welte9cfc9352009-06-26 19:39:35 +0200981 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
982 "GSM 04.08");
Harald Welte59b04682009-06-10 05:40:52 +0800983}
984
Harald Welte36fe2e82009-07-23 21:13:03 +0200985int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
Harald Welte59b04682009-06-10 05:40:52 +0800986{
Harald Welte36fe2e82009-07-23 21:13:03 +0200987 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
988
989 /* if we get passed a transaction reference, do some common
990 * work that the caller no longer has to do */
991 if (trans) {
Harald Welte4861c822009-07-23 21:21:14 +0200992 gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
Harald Welte36fe2e82009-07-23 21:13:03 +0200993 msg->lchan = trans->lchan;
994 }
995
Harald Welte59b04682009-06-10 05:40:52 +0800996 if (msg->lchan) {
997 msg->trx = msg->lchan->ts->trx;
998
Harald Welte03740842009-06-10 23:11:52 +0800999 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
1000 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
1001 "Sending '%s' to MS.\n", msg->trx->bts->nr,
1002 msg->trx->nr, msg->lchan->ts->nr,
1003 gh->proto_discr & 0xf0,
1004 cc_msg_names[gh->msg_type & 0x3f]);
1005 else
1006 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
1007 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
1008 msg->trx->nr, msg->lchan->ts->nr,
1009 gh->proto_discr, gh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001010 }
1011
1012 msg->l3h = msg->data;
1013
1014 return rsl_data_request(msg, 0);
1015}
1016
Harald Welte59b04682009-06-10 05:40:52 +08001017/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
1018int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
1019{
1020 struct msgb *msg = gsm48_msgb_alloc();
1021 struct gsm48_hdr *gh;
1022
1023 msg->lchan = lchan;
1024
1025 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1026 gh->proto_discr = GSM48_PDISC_MM;
1027 gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
1028 gh->data[0] = cause;
1029
1030 DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
1031
Harald Welte36fe2e82009-07-23 21:13:03 +02001032 return gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001033}
1034
1035/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
1036int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
1037{
1038 struct gsm_bts *bts = lchan->ts->trx->bts;
1039 struct msgb *msg = gsm48_msgb_alloc();
1040 struct gsm48_hdr *gh;
1041 struct gsm48_loc_area_id *lai;
1042 u_int8_t *mid;
1043 int ret;
1044
1045 msg->lchan = lchan;
1046
1047 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1048 gh->proto_discr = GSM48_PDISC_MM;
1049 gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
1050
1051 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
1052 gsm0408_generate_lai(lai, bts->network->country_code,
1053 bts->network->network_code, bts->location_area_code);
1054
1055 mid = msgb_put(msg, MID_TMSI_LEN);
1056 generate_mid_from_tmsi(mid, tmsi);
1057
1058 DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
1059
Harald Welte36fe2e82009-07-23 21:13:03 +02001060 ret = gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001061
1062 ret = gsm48_tx_mm_info(lchan);
1063
1064 return ret;
1065}
1066
1067static char bcd2char(u_int8_t bcd)
1068{
1069 if (bcd < 0xa)
1070 return '0' + bcd;
1071 else
1072 return 'A' + (bcd - 0xa);
1073}
1074
1075/* Convert Mobile Identity (10.5.1.4) to string */
1076static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
1077{
1078 int i;
1079 u_int8_t mi_type;
1080 char *str_cur = string;
1081 u_int32_t tmsi;
1082
1083 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1084
1085 switch (mi_type) {
1086 case GSM_MI_TYPE_NONE:
1087 break;
1088 case GSM_MI_TYPE_TMSI:
1089 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
1090 if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
1091 memcpy(&tmsi, &mi[1], 4);
1092 tmsi = ntohl(tmsi);
1093 return snprintf(string, str_len, "%u", tmsi);
1094 }
1095 break;
1096 case GSM_MI_TYPE_IMSI:
1097 case GSM_MI_TYPE_IMEI:
1098 case GSM_MI_TYPE_IMEISV:
1099 *str_cur++ = bcd2char(mi[0] >> 4);
1100
1101 for (i = 1; i < mi_len; i++) {
1102 if (str_cur + 2 >= string + str_len)
1103 return str_cur - string;
1104 *str_cur++ = bcd2char(mi[i] & 0xf);
1105 /* skip last nibble in last input byte when GSM_EVEN */
1106 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
1107 *str_cur++ = bcd2char(mi[i] >> 4);
1108 }
1109 break;
1110 default:
1111 break;
1112 }
1113 *str_cur++ = '\0';
1114
1115 return str_cur - string;
1116}
1117
1118/* Transmit Chapter 9.2.10 Identity Request */
1119static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
1120{
1121 struct msgb *msg = gsm48_msgb_alloc();
1122 struct gsm48_hdr *gh;
1123
1124 msg->lchan = lchan;
1125
1126 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1127 gh->proto_discr = GSM48_PDISC_MM;
1128 gh->msg_type = GSM48_MT_MM_ID_REQ;
1129 gh->data[0] = id_type;
1130
Harald Welte36fe2e82009-07-23 21:13:03 +02001131 return gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001132}
1133
1134#define MI_SIZE 32
1135
1136/* Parse Chapter 9.2.11 Identity Response */
1137static int mm_rx_id_resp(struct msgb *msg)
1138{
1139 struct gsm48_hdr *gh = msgb_l3(msg);
1140 struct gsm_lchan *lchan = msg->lchan;
Harald Welteaae7a522009-07-23 19:21:02 +02001141 struct gsm_bts *bts = lchan->ts->trx->bts;
1142 struct gsm_network *net = bts->network;
Harald Welte59b04682009-06-10 05:40:52 +08001143 u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
1144 char mi_string[MI_SIZE];
1145
1146 mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
1147 DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
1148 mi_type, mi_string);
1149
Harald Welte59b04682009-06-10 05:40:52 +08001150 switch (mi_type) {
1151 case GSM_MI_TYPE_IMSI:
1152 if (!lchan->subscr)
Harald Welteaae7a522009-07-23 19:21:02 +02001153 lchan->subscr = db_create_subscriber(net, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001154 if (lchan->loc_operation)
1155 lchan->loc_operation->waiting_for_imsi = 0;
1156 break;
1157 case GSM_MI_TYPE_IMEI:
1158 case GSM_MI_TYPE_IMEISV:
1159 /* update subscribe <-> IMEI mapping */
1160 if (lchan->subscr)
1161 db_subscriber_assoc_imei(lchan->subscr, mi_string);
1162 if (lchan->loc_operation)
1163 lchan->loc_operation->waiting_for_imei = 0;
1164 break;
1165 }
1166
1167 /* Check if we can let the mobile station enter */
1168 return gsm0408_authorize(lchan, msg);
1169}
1170
1171
1172static void loc_upd_rej_cb(void *data)
1173{
1174 struct gsm_lchan *lchan = data;
1175
1176 release_loc_updating_req(lchan);
1177 gsm0408_loc_upd_rej(lchan, reject_cause);
1178 lchan_auto_release(lchan);
1179}
1180
1181static void schedule_reject(struct gsm_lchan *lchan)
1182{
1183 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1184 lchan->loc_operation->updating_timer.data = lchan;
1185 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
1186}
1187
1188static const char *lupd_name(u_int8_t type)
1189{
1190 switch (type) {
1191 case GSM48_LUPD_NORMAL:
1192 return "NORMAL";
1193 case GSM48_LUPD_PERIODIC:
1194 return "PEROIDOC";
1195 case GSM48_LUPD_IMSI_ATT:
1196 return "IMSI ATTACH";
1197 default:
1198 return "UNKNOWN";
1199 }
1200}
1201
1202#define MI_SIZE 32
1203/* Chapter 9.2.15: Receive Location Updating Request */
1204static int mm_rx_loc_upd_req(struct msgb *msg)
1205{
1206 struct gsm48_hdr *gh = msgb_l3(msg);
1207 struct gsm48_loc_upd_req *lu;
Harald Welte03740842009-06-10 23:11:52 +08001208 struct gsm_subscriber *subscr = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001209 struct gsm_lchan *lchan = msg->lchan;
Harald Welteaae7a522009-07-23 19:21:02 +02001210 struct gsm_bts *bts = lchan->ts->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +08001211 u_int8_t mi_type;
1212 char mi_string[MI_SIZE];
1213 int rc;
1214
1215 lu = (struct gsm48_loc_upd_req *) gh->data;
1216
1217 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
1218
1219 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1220
Harald Welte79639662009-06-27 02:58:43 +02001221 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte59b04682009-06-10 05:40:52 +08001222 lupd_name(lu->type));
1223
1224 /*
1225 * Pseudo Spoof detection: Just drop a second/concurrent
1226 * location updating request.
1227 */
1228 if (lchan->loc_operation) {
Harald Welte79639662009-06-27 02:58:43 +02001229 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Harald Welte59b04682009-06-10 05:40:52 +08001230 lchan->loc_operation);
1231 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1232 return 0;
1233 }
1234
1235 allocate_loc_updating_req(lchan);
1236
1237 switch (mi_type) {
1238 case GSM_MI_TYPE_IMSI:
Harald Welte79639662009-06-27 02:58:43 +02001239 DEBUGPC(DMM, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08001240 /* we always want the IMEI, too */
Harald Welte59b04682009-06-10 05:40:52 +08001241 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
1242 lchan->loc_operation->waiting_for_imei = 1;
1243
1244 /* look up subscriber based on IMSI */
Harald Welteaae7a522009-07-23 19:21:02 +02001245 subscr = db_create_subscriber(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001246 break;
1247 case GSM_MI_TYPE_TMSI:
Harald Welte79639662009-06-27 02:58:43 +02001248 DEBUGPC(DMM, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08001249 /* we always want the IMEI, too */
Harald Welte59b04682009-06-10 05:40:52 +08001250 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
1251 lchan->loc_operation->waiting_for_imei = 1;
1252
1253 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welteaae7a522009-07-23 19:21:02 +02001254 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001255 if (!subscr) {
1256 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte59b04682009-06-10 05:40:52 +08001257 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
1258 lchan->loc_operation->waiting_for_imsi = 1;
1259 }
1260 break;
1261 case GSM_MI_TYPE_IMEI:
1262 case GSM_MI_TYPE_IMEISV:
1263 /* no sim card... FIXME: what to do ? */
Harald Welte79639662009-06-27 02:58:43 +02001264 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte59b04682009-06-10 05:40:52 +08001265 break;
1266 default:
Harald Welte79639662009-06-27 02:58:43 +02001267 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte59b04682009-06-10 05:40:52 +08001268 break;
1269 }
1270
Harald Welteccd69362009-07-04 10:18:00 +02001271 /* schedule the reject timer */
1272 schedule_reject(lchan);
1273
Harald Welte03740842009-06-10 23:11:52 +08001274 if (!subscr) {
Harald Welte79639662009-06-27 02:58:43 +02001275 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte03740842009-06-10 23:11:52 +08001276 /* FIXME: request id? close channel? */
1277 return -EINVAL;
1278 }
1279
Harald Welte59b04682009-06-10 05:40:52 +08001280 lchan->subscr = subscr;
1281
Harald Welteccd69362009-07-04 10:18:00 +02001282 /* check if we can let the subscriber into our network immediately
1283 * or if we need to wait for identity responses. */
Harald Welte59b04682009-06-10 05:40:52 +08001284 return gsm0408_authorize(lchan, msg);
1285}
1286
1287/* 9.1.5 Channel mode modify */
1288int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1289{
1290 struct msgb *msg = gsm48_msgb_alloc();
1291 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1292 struct gsm48_chan_mode_modify *cmm =
1293 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
1294 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
1295
1296 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
1297
1298 lchan->tch_mode = mode;
1299 msg->lchan = lchan;
1300 gh->proto_discr = GSM48_PDISC_RR;
1301 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1302
1303 /* fill the channel information element, this code
1304 * should probably be shared with rsl_rx_chan_rqd() */
1305 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
1306 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
1307 cmm->chan_desc.h0.h = 0;
1308 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1309 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1310 cmm->mode = mode;
1311
Harald Welte36fe2e82009-07-23 21:13:03 +02001312 return gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001313}
1314
Harald Welte03740842009-06-10 23:11:52 +08001315#if 0
1316static u_int8_t to_bcd8(u_int8_t val)
1317{
1318 return ((val / 10) << 4) | (val % 10);
1319}
1320#endif
1321
Harald Welte59b04682009-06-10 05:40:52 +08001322/* Section 9.2.15a */
1323int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1324{
1325 struct msgb *msg = gsm48_msgb_alloc();
1326 struct gsm48_hdr *gh;
1327 struct gsm_network *net = lchan->ts->trx->bts->network;
1328 u_int8_t *ptr8;
1329 u_int16_t *ptr16;
1330 int name_len;
1331 int i;
Harald Welte03740842009-06-10 23:11:52 +08001332#if 0
1333 time_t cur_t;
1334 struct tm* cur_time;
1335 int tz15min;
1336#endif
Harald Welte59b04682009-06-10 05:40:52 +08001337
1338 msg->lchan = lchan;
1339
1340 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1341 gh->proto_discr = GSM48_PDISC_MM;
1342 gh->msg_type = GSM48_MT_MM_INFO;
1343
1344 if (net->name_long) {
1345 name_len = strlen(net->name_long);
1346 /* 10.5.3.5a */
1347 ptr8 = msgb_put(msg, 3);
1348 ptr8[0] = GSM48_IE_NAME_LONG;
1349 ptr8[1] = name_len*2 +1;
1350 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1351
1352 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1353 for (i = 0; i < name_len; i++)
1354 ptr16[i] = htons(net->name_long[i]);
1355
1356 /* FIXME: Use Cell Broadcast, not UCS-2, since
1357 * UCS-2 is only supported by later revisions of the spec */
1358 }
1359
1360 if (net->name_short) {
1361 name_len = strlen(net->name_short);
1362 /* 10.5.3.5a */
1363 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Weltef6284712009-07-19 17:51:36 +02001364 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Welte59b04682009-06-10 05:40:52 +08001365 ptr8[1] = name_len*2 + 1;
1366 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1367
1368 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1369 for (i = 0; i < name_len; i++)
1370 ptr16[i] = htons(net->name_short[i]);
1371 }
1372
1373#if 0
Harald Welte59b04682009-06-10 05:40:52 +08001374 /* Section 10.5.3.9 */
1375 cur_t = time(NULL);
Harald Welte03740842009-06-10 23:11:52 +08001376 cur_time = gmtime(&cur_t);
Harald Welte59b04682009-06-10 05:40:52 +08001377 ptr8 = msgb_put(msg, 8);
1378 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1379 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1380 ptr8[2] = to_bcd8(cur_time->tm_mon);
1381 ptr8[3] = to_bcd8(cur_time->tm_mday);
1382 ptr8[4] = to_bcd8(cur_time->tm_hour);
1383 ptr8[5] = to_bcd8(cur_time->tm_min);
1384 ptr8[6] = to_bcd8(cur_time->tm_sec);
1385 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1386 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte03740842009-06-10 23:11:52 +08001387 ptr8[7] = to_bcd8(tz15min);
Harald Welte59b04682009-06-10 05:40:52 +08001388 if (tz15min < 0)
Harald Welte03740842009-06-10 23:11:52 +08001389 ptr8[7] |= 0x80;
Harald Welte59b04682009-06-10 05:40:52 +08001390#endif
1391
Harald Welte36fe2e82009-07-23 21:13:03 +02001392 return gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001393}
1394
1395static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1396{
1397 DEBUGP(DMM, "-> CM SERVICE ACK\n");
1398 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
1399}
1400
1401/* 9.2.6 CM service reject */
1402static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1403 enum gsm48_reject_value value)
1404{
1405 struct msgb *msg = gsm48_msgb_alloc();
1406 struct gsm48_hdr *gh;
1407
1408 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1409
1410 msg->lchan = lchan;
1411 use_lchan(lchan);
1412
1413 gh->proto_discr = GSM48_PDISC_MM;
1414 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1415 gh->data[0] = value;
1416 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1417
Harald Welte36fe2e82009-07-23 21:13:03 +02001418 return gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001419}
1420
1421
1422/*
1423 * Handle CM Service Requests
1424 * a) Verify that the packet is long enough to contain the information
1425 * we require otherwsie reject with INCORRECT_MESSAGE
1426 * b) Try to parse the TMSI. If we do not have one reject
1427 * c) Check that we know the subscriber with the TMSI otherwise reject
1428 * with a HLR cause
1429 * d) Set the subscriber on the gsm_lchan and accept
1430 */
1431static int gsm48_rx_mm_serv_req(struct msgb *msg)
1432{
1433 u_int8_t mi_type;
1434 char mi_string[MI_SIZE];
1435
Harald Welteaae7a522009-07-23 19:21:02 +02001436 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +08001437 struct gsm_subscriber *subscr;
1438 struct gsm48_hdr *gh = msgb_l3(msg);
1439 struct gsm48_service_request *req =
1440 (struct gsm48_service_request *)gh->data;
1441 /* unfortunately in Phase1 the classmar2 length is variable */
1442 u_int8_t classmark2_len = gh->data[1];
1443 u_int8_t *classmark2 = gh->data+2;
1444 u_int8_t mi_len = *(classmark2 + classmark2_len);
1445 u_int8_t *mi = (classmark2 + classmark2_len + 1);
1446
1447 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
1448 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
1449 DEBUGPC(DMM, "wrong sized message\n");
1450 return gsm48_tx_mm_serv_rej(msg->lchan,
1451 GSM48_REJECT_INCORRECT_MESSAGE);
1452 }
1453
1454 if (msg->data_len < req->mi_len + 6) {
1455 DEBUGPC(DMM, "does not fit in packet\n");
1456 return gsm48_tx_mm_serv_rej(msg->lchan,
1457 GSM48_REJECT_INCORRECT_MESSAGE);
1458 }
1459
1460 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1461 if (mi_type != GSM_MI_TYPE_TMSI) {
1462 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
1463 return gsm48_tx_mm_serv_rej(msg->lchan,
1464 GSM48_REJECT_INCORRECT_MESSAGE);
1465 }
1466
1467 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
1468 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
1469 req->cm_service_type, mi_type, mi_string);
1470
Harald Welteaae7a522009-07-23 19:21:02 +02001471 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001472
1473 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
1474 if (!subscr)
1475 return gsm48_tx_mm_serv_rej(msg->lchan,
1476 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1477
1478 if (!msg->lchan->subscr)
1479 msg->lchan->subscr = subscr;
1480 else if (msg->lchan->subscr != subscr) {
1481 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1482 subscr_put(subscr);
1483 }
1484
Harald Weltef6845a72009-07-05 14:08:13 +02001485 subscr->equipment.classmark2_len = classmark2_len;
1486 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1487 db_sync_equipment(&subscr->equipment);
Harald Welte59b04682009-06-10 05:40:52 +08001488
1489 return gsm48_tx_mm_serv_ack(msg->lchan);
1490}
1491
1492static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1493{
Harald Welteaae7a522009-07-23 19:21:02 +02001494 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +08001495 struct gsm48_hdr *gh = msgb_l3(msg);
1496 struct gsm48_imsi_detach_ind *idi =
1497 (struct gsm48_imsi_detach_ind *) gh->data;
1498 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1499 char mi_string[MI_SIZE];
Harald Welte03740842009-06-10 23:11:52 +08001500 struct gsm_subscriber *subscr = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001501
1502 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1503 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1504 mi_type, mi_string);
1505
1506 switch (mi_type) {
1507 case GSM_MI_TYPE_TMSI:
Harald Welteaae7a522009-07-23 19:21:02 +02001508 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001509 break;
1510 case GSM_MI_TYPE_IMSI:
Harald Welteaae7a522009-07-23 19:21:02 +02001511 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001512 break;
1513 case GSM_MI_TYPE_IMEI:
1514 case GSM_MI_TYPE_IMEISV:
1515 /* no sim card... FIXME: what to do ? */
1516 DEBUGPC(DMM, "unimplemented mobile identity type\n");
1517 break;
1518 default:
1519 DEBUGPC(DMM, "unknown mobile identity type\n");
1520 break;
1521 }
1522
1523 if (subscr) {
1524 subscr_update(subscr, msg->trx->bts,
1525 GSM_SUBSCRIBER_UPDATE_DETACHED);
1526 DEBUGP(DMM, "Subscriber: %s\n",
1527 subscr->name ? subscr->name : subscr->imsi);
1528 subscr_put(subscr);
1529 } else
1530 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1531
Harald Welte59b04682009-06-10 05:40:52 +08001532 return 0;
1533}
1534
1535static int gsm48_rx_mm_status(struct msgb *msg)
1536{
1537 struct gsm48_hdr *gh = msgb_l3(msg);
1538
1539 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1540
1541 return 0;
1542}
1543
1544/* Receive a GSM 04.08 Mobility Management (MM) message */
1545static int gsm0408_rcv_mm(struct msgb *msg)
1546{
1547 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte03740842009-06-10 23:11:52 +08001548 int rc = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001549
1550 switch (gh->msg_type & 0xbf) {
1551 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Welte79639662009-06-27 02:58:43 +02001552 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte59b04682009-06-10 05:40:52 +08001553 rc = mm_rx_loc_upd_req(msg);
1554 break;
1555 case GSM48_MT_MM_ID_RESP:
1556 rc = mm_rx_id_resp(msg);
1557 break;
1558 case GSM48_MT_MM_CM_SERV_REQ:
1559 rc = gsm48_rx_mm_serv_req(msg);
1560 break;
1561 case GSM48_MT_MM_STATUS:
1562 rc = gsm48_rx_mm_status(msg);
1563 break;
1564 case GSM48_MT_MM_TMSI_REALL_COMPL:
1565 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1566 msg->lchan->subscr ?
1567 msg->lchan->subscr->imsi :
1568 "unknown subscriber");
1569 break;
1570 case GSM48_MT_MM_IMSI_DETACH_IND:
1571 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1572 break;
1573 case GSM48_MT_MM_CM_REEST_REQ:
1574 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1575 break;
1576 case GSM48_MT_MM_AUTH_RESP:
1577 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
1578 break;
1579 default:
1580 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1581 gh->msg_type);
1582 break;
1583 }
1584
1585 return rc;
1586}
1587
1588/* Receive a PAGING RESPONSE message from the MS */
1589static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1590{
Harald Welteaae7a522009-07-23 19:21:02 +02001591 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +08001592 struct gsm48_hdr *gh = msgb_l3(msg);
1593 u_int8_t *classmark2_lv = gh->data + 1;
1594 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1595 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
1596 char mi_string[MI_SIZE];
Harald Welte03740842009-06-10 23:11:52 +08001597 struct gsm_subscriber *subscr = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001598 struct paging_signal_data sig_data;
1599 int rc = 0;
1600
1601 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
1602 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1603 mi_type, mi_string);
1604 switch (mi_type) {
1605 case GSM_MI_TYPE_TMSI:
Harald Welteaae7a522009-07-23 19:21:02 +02001606 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001607 break;
1608 case GSM_MI_TYPE_IMSI:
Harald Welteaae7a522009-07-23 19:21:02 +02001609 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte59b04682009-06-10 05:40:52 +08001610 break;
1611 }
1612
1613 if (!subscr) {
1614 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
1615 /* FIXME: request id? close channel? */
1616 return -EINVAL;
1617 }
1618 DEBUGP(DRR, "<- Channel was requested by %s\n",
1619 subscr->name ? subscr->name : subscr->imsi);
1620
Harald Weltef6845a72009-07-05 14:08:13 +02001621 subscr->equipment.classmark2_len = *classmark2_lv;
1622 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1623 db_sync_equipment(&subscr->equipment);
Harald Welte59b04682009-06-10 05:40:52 +08001624
1625 if (!msg->lchan->subscr) {
1626 msg->lchan->subscr = subscr;
1627 } else if (msg->lchan->subscr != subscr) {
1628 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1629 subscr_put(subscr);
1630 return -EINVAL;
1631 } else {
1632 DEBUGP(DRR, "<- Channel already owned by us\n");
1633 subscr_put(subscr);
1634 subscr = msg->lchan->subscr;
1635 }
1636
1637 sig_data.subscr = subscr;
1638 sig_data.bts = msg->lchan->ts->trx->bts;
1639 sig_data.lchan = msg->lchan;
1640
1641 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Welte876312f2009-06-10 11:21:55 +08001642
1643 /* Stop paging on the bts we received the paging response */
Harald Welte59b04682009-06-10 05:40:52 +08001644 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
1645
1646 /* FIXME: somehow signal the completion of the PAGING to
1647 * the entity that requested the paging */
1648
1649 return rc;
1650}
1651
1652static int gsm48_rx_rr_classmark(struct msgb *msg)
1653{
1654 struct gsm48_hdr *gh = msgb_l3(msg);
1655 struct gsm_subscriber *subscr = msg->lchan->subscr;
1656 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1657 u_int8_t cm2_len, cm3_len = 0;
1658 u_int8_t *cm2, *cm3 = NULL;
1659
1660 DEBUGP(DRR, "CLASSMARK CHANGE ");
1661
1662 /* classmark 2 */
1663 cm2_len = gh->data[0];
1664 cm2 = &gh->data[1];
1665 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1666
1667 if (payload_len > cm2_len + 1) {
1668 /* we must have a classmark3 */
1669 if (gh->data[cm2_len+1] != 0x20) {
1670 DEBUGPC(DRR, "ERR CM3 TAG\n");
1671 return -EINVAL;
1672 }
1673 if (cm2_len > 3) {
1674 DEBUGPC(DRR, "CM2 too long!\n");
1675 return -EINVAL;
1676 }
1677
1678 cm3_len = gh->data[cm2_len+2];
1679 cm3 = &gh->data[cm2_len+3];
1680 if (cm3_len > 14) {
1681 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1682 return -EINVAL;
1683 }
1684 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1685 }
1686 if (subscr) {
Harald Weltef6845a72009-07-05 14:08:13 +02001687 subscr->equipment.classmark2_len = cm2_len;
1688 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Welte59b04682009-06-10 05:40:52 +08001689 if (cm3) {
Harald Weltef6845a72009-07-05 14:08:13 +02001690 subscr->equipment.classmark3_len = cm3_len;
1691 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Welte59b04682009-06-10 05:40:52 +08001692 }
Harald Weltef6845a72009-07-05 14:08:13 +02001693 db_sync_equipment(&subscr->equipment);
Harald Welte59b04682009-06-10 05:40:52 +08001694 }
1695
Harald Welte59b04682009-06-10 05:40:52 +08001696 return 0;
1697}
1698
1699static int gsm48_rx_rr_status(struct msgb *msg)
1700{
1701 struct gsm48_hdr *gh = msgb_l3(msg);
1702
1703 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1704 rr_cause_name(gh->data[0]));
1705
1706 return 0;
1707}
1708
1709static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1710{
1711 struct gsm48_hdr *gh = msgb_l3(msg);
1712 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1713 static struct gsm_meas_rep meas_rep;
1714
Harald Welte02993682009-06-27 02:53:10 +02001715 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Welte59b04682009-06-10 05:40:52 +08001716 parse_meas_rep(&meas_rep, gh->data, payload_len);
1717 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte02993682009-06-27 02:53:10 +02001718 DEBUGPC(DMEAS, "DTX ");
Harald Welte59b04682009-06-10 05:40:52 +08001719 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte02993682009-06-27 02:53:10 +02001720 DEBUGPC(DMEAS, "BA1 ");
Harald Welte59b04682009-06-10 05:40:52 +08001721 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte02993682009-06-27 02:53:10 +02001722 DEBUGPC(DMEAS, "NOT VALID ");
Harald Welte59b04682009-06-10 05:40:52 +08001723 else
Harald Welte02993682009-06-27 02:53:10 +02001724 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Welte59b04682009-06-10 05:40:52 +08001725 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1726 meas_rep.rxqual_sub);
1727
Harald Welte02993682009-06-27 02:53:10 +02001728 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Welte59b04682009-06-10 05:40:52 +08001729
1730 /* FIXME: put the results somwhere */
1731
1732 return 0;
1733}
1734
1735/* Receive a GSM 04.08 Radio Resource (RR) message */
1736static int gsm0408_rcv_rr(struct msgb *msg)
1737{
1738 struct gsm48_hdr *gh = msgb_l3(msg);
1739 int rc = 0;
1740
1741 switch (gh->msg_type) {
1742 case GSM48_MT_RR_CLSM_CHG:
1743 rc = gsm48_rx_rr_classmark(msg);
1744 break;
1745 case GSM48_MT_RR_GPRS_SUSP_REQ:
1746 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1747 break;
1748 case GSM48_MT_RR_PAG_RESP:
1749 rc = gsm48_rr_rx_pag_resp(msg);
1750 break;
1751 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1752 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
1753 rc = rsl_chan_mode_modify_req(msg->lchan);
1754 break;
1755 case GSM48_MT_RR_STATUS:
1756 rc = gsm48_rx_rr_status(msg);
1757 break;
1758 case GSM48_MT_RR_MEAS_REP:
1759 rc = gsm48_rx_rr_meas_rep(msg);
1760 break;
1761 default:
1762 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
1763 gh->msg_type);
1764 break;
1765 }
1766
1767 return rc;
1768}
1769
1770/* 7.1.7 and 9.1.7 Channel release*/
1771int gsm48_send_rr_release(struct gsm_lchan *lchan)
1772{
1773 struct msgb *msg = gsm48_msgb_alloc();
1774 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1775 u_int8_t *cause;
1776
1777 msg->lchan = lchan;
1778 gh->proto_discr = GSM48_PDISC_RR;
1779 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1780
1781 cause = msgb_put(msg, 1);
1782 cause[0] = GSM48_RR_CAUSE_NORMAL;
1783
1784 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1785 lchan->nr, lchan->type);
1786
Harald Welteafe3c232009-07-19 18:36:49 +02001787 /* Send actual release request to MS */
Harald Welte36fe2e82009-07-23 21:13:03 +02001788 gsm48_sendmsg(msg, NULL);
Harald Welteafe3c232009-07-19 18:36:49 +02001789
1790 /* Deactivate the SACCH on the BTS side */
1791 return rsl_deact_sacch(lchan);
Harald Welte59b04682009-06-10 05:40:52 +08001792}
1793
1794/* Call Control */
1795
1796/* The entire call control code is written in accordance with Figure 7.10c
1797 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1798 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1799 * it for voice */
1800
Harald Welte03740842009-06-10 23:11:52 +08001801static void new_cc_state(struct gsm_trans *trans, int state)
1802{
1803 if (state > 31 || state < 0)
1804 return;
1805
1806 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltea54b48d2009-07-23 18:56:43 +02001807 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte03740842009-06-10 23:11:52 +08001808
Harald Weltea54b48d2009-07-23 18:56:43 +02001809 trans->cc.state = state;
Harald Welte03740842009-06-10 23:11:52 +08001810}
1811
1812static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte59b04682009-06-10 05:40:52 +08001813{
1814 struct msgb *msg = gsm48_msgb_alloc();
1815 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1816 u_int8_t *cause, *call_state;
1817
Harald Welte59b04682009-06-10 05:40:52 +08001818 gh->msg_type = GSM48_MT_CC_STATUS;
1819
1820 cause = msgb_put(msg, 3);
1821 cause[0] = 2;
1822 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1823 cause[2] = 0x80 | 30; /* response to status inquiry */
1824
1825 call_state = msgb_put(msg, 1);
1826 call_state[0] = 0xc0 | 0x00;
1827
Harald Welte36fe2e82009-07-23 21:13:03 +02001828 return gsm48_sendmsg(msg, trans);
Harald Welte59b04682009-06-10 05:40:52 +08001829}
1830
1831static int gsm48_tx_simple(struct gsm_lchan *lchan,
1832 u_int8_t pdisc, u_int8_t msg_type)
1833{
1834 struct msgb *msg = gsm48_msgb_alloc();
1835 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1836
1837 msg->lchan = lchan;
1838
1839 gh->proto_discr = pdisc;
1840 gh->msg_type = msg_type;
1841
Harald Welte36fe2e82009-07-23 21:13:03 +02001842 return gsm48_sendmsg(msg, NULL);
Harald Welte59b04682009-06-10 05:40:52 +08001843}
1844
Harald Welte03740842009-06-10 23:11:52 +08001845static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1846{
Harald Weltea54b48d2009-07-23 18:56:43 +02001847 if (bsc_timer_pending(&trans->cc.timer)) {
1848 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1849 bsc_del_timer(&trans->cc.timer);
1850 trans->cc.Tcurrent = 0;
Harald Welte03740842009-06-10 23:11:52 +08001851 }
1852}
1853
1854static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1855 int msg_type, struct gsm_mncc *mncc)
1856{
1857 struct msgb *msg;
1858
1859 if (trans)
1860 if (trans->lchan)
Harald Welte4861c822009-07-23 21:21:14 +02001861 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte03740842009-06-10 23:11:52 +08001862 "Sending '%s' to MNCC.\n",
1863 trans->lchan->ts->trx->bts->nr,
1864 trans->lchan->ts->trx->nr,
1865 trans->lchan->ts->nr, trans->transaction_id,
1866 (trans->subscr)?(trans->subscr->extension):"-",
1867 get_mncc_name(msg_type));
1868 else
1869 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1870 "Sending '%s' to MNCC.\n",
1871 (trans->subscr)?(trans->subscr->extension):"-",
1872 get_mncc_name(msg_type));
1873 else
1874 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1875 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1876
1877 mncc->msg_type = msg_type;
1878
Harald Welte9cfc9352009-06-26 19:39:35 +02001879 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte03740842009-06-10 23:11:52 +08001880 if (!msg)
1881 return -ENOMEM;
1882 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1883 msgb_enqueue(&net->upqueue, msg);
1884
1885 return 0;
1886}
1887
1888int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1889 u_int32_t callref, int location, int value)
1890{
1891 struct gsm_mncc rel;
1892
Harald Weltecb0595f2009-06-12 01:54:08 +08001893 memset(&rel, 0, sizeof(rel));
Harald Welte03740842009-06-10 23:11:52 +08001894 rel.callref = callref;
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08001895 mncc_set_cause(&rel, location, value);
Harald Welte03740842009-06-10 23:11:52 +08001896 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1897}
1898
Harald Weltea54b48d2009-07-23 18:56:43 +02001899/* Call Control Specific transaction release.
1900 * gets called by trans_free, DO NOT CALL YOURSELF! */
1901void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte03740842009-06-10 23:11:52 +08001902{
Harald Welte03740842009-06-10 23:11:52 +08001903 gsm48_stop_cc_timer(trans);
1904
1905 /* send release to L4, if callref still exists */
1906 if (trans->callref) {
1907 /* Ressource unavailable */
Harald Welte8dd09d62009-07-23 19:06:52 +02001908 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08001909 GSM48_CAUSE_LOC_PRN_S_LU,
1910 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte03740842009-06-10 23:11:52 +08001911 }
Harald Weltea54b48d2009-07-23 18:56:43 +02001912 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte03740842009-06-10 23:11:52 +08001913 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltea54b48d2009-07-23 18:56:43 +02001914 if (trans->lchan)
1915 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte03740842009-06-10 23:11:52 +08001916}
1917
1918static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1919
Harald Welte59b04682009-06-10 05:40:52 +08001920/* call-back from paging the B-end of the connection */
1921static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
1922 struct msgb *msg, void *_lchan, void *param)
1923{
1924 struct gsm_lchan *lchan = _lchan;
Harald Welte03740842009-06-10 23:11:52 +08001925 struct gsm_subscriber *subscr = param;
1926 struct gsm_trans *transt, *tmp;
1927 struct gsm_network *net;
Harald Welte1ff81b52009-06-26 20:17:06 +02001928
Harald Welte59b04682009-06-10 05:40:52 +08001929 if (hooknum != GSM_HOOK_RR_PAGING)
1930 return -EINVAL;
Harald Welte03740842009-06-10 23:11:52 +08001931
1932 if (!subscr)
1933 return -EINVAL;
1934 net = subscr->net;
1935 if (!net) {
1936 DEBUGP(DCC, "Error Network not set!\n");
1937 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08001938 }
1939
Harald Welte03740842009-06-10 23:11:52 +08001940 /* check all tranactions (without lchan) for subscriber */
1941 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1942 if (transt->subscr != subscr || transt->lchan)
1943 continue;
1944 switch (event) {
1945 case GSM_PAGING_SUCCEEDED:
1946 if (!lchan) // paranoid
1947 break;
1948 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1949 subscr->extension);
1950 /* Assign lchan */
1951 if (!transt->lchan) {
1952 transt->lchan = lchan;
1953 use_lchan(lchan);
1954 }
1955 /* send SETUP request to called party */
Harald Weltea54b48d2009-07-23 18:56:43 +02001956 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte03740842009-06-10 23:11:52 +08001957 if (is_ipaccess_bts(lchan->ts->trx->bts))
1958 rsl_ipacc_bind(lchan);
1959 break;
1960 case GSM_PAGING_EXPIRED:
1961 DEBUGP(DCC, "Paging subscr %s expired!\n",
1962 subscr->extension);
1963 /* Temporarily out of order */
Harald Welte8dd09d62009-07-23 19:06:52 +02001964 mncc_release_ind(transt->subscr->net, transt,
1965 transt->callref,
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08001966 GSM48_CAUSE_LOC_PRN_S_LU,
1967 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte03740842009-06-10 23:11:52 +08001968 transt->callref = 0;
Harald Weltea54b48d2009-07-23 18:56:43 +02001969 trans_free(transt);
Harald Welte03740842009-06-10 23:11:52 +08001970 break;
1971 }
1972 }
Harald Welte59b04682009-06-10 05:40:52 +08001973 return 0;
1974}
1975
Harald Welte59b04682009-06-10 05:40:52 +08001976/* map two ipaccess RTP streams onto each other */
1977static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
1978{
1979 struct gsm_bts *bts = lchan->ts->trx->bts;
1980 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
1981 struct gsm_bts_trx_ts *ts;
1982
1983 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
1984 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
1985 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
1986
1987 if (bts->type != remote_bts->type) {
1988 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
1989 return -EINVAL;
1990 }
1991
1992 switch (bts->type) {
1993 case GSM_BTS_TYPE_NANOBTS_900:
1994 case GSM_BTS_TYPE_NANOBTS_1800:
1995 ts = remote_lchan->ts;
Harald Welte8cdeaad2009-07-12 09:50:35 +02001996 rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
1997 ts->abis_ip.bound_port,
1998 lchan->ts->abis_ip.conn_id,
1999 ts->abis_ip.rtp_payload2);
Harald Welte59b04682009-06-10 05:40:52 +08002000
2001 ts = lchan->ts;
Harald Welte8cdeaad2009-07-12 09:50:35 +02002002 rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2003 ts->abis_ip.bound_port,
2004 remote_lchan->ts->abis_ip.conn_id,
2005 ts->abis_ip.rtp_payload2);
Harald Welte59b04682009-06-10 05:40:52 +08002006 break;
2007 case GSM_BTS_TYPE_BS11:
2008 trau_mux_map_lchan(lchan, remote_lchan);
2009 break;
2010 default:
2011 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
2012 break;
2013 }
2014
2015 return 0;
2016}
2017
Harald Welte03740842009-06-10 23:11:52 +08002018/* bridge channels of two transactions */
2019static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte59b04682009-06-10 05:40:52 +08002020{
Harald Weltea54b48d2009-07-23 18:56:43 +02002021 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2022 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte59b04682009-06-10 05:40:52 +08002023
Harald Welte03740842009-06-10 23:11:52 +08002024 if (!trans1 || !trans2)
Harald Welte59b04682009-06-10 05:40:52 +08002025 return -EIO;
2026
Harald Welte03740842009-06-10 23:11:52 +08002027 if (!trans1->lchan || !trans2->lchan)
2028 return -EIO;
2029
2030 /* through-connect channel */
2031 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte59b04682009-06-10 05:40:52 +08002032}
2033
Harald Welte03740842009-06-10 23:11:52 +08002034/* enable receive of channels to upqueue */
2035static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2036{
2037 struct gsm_trans *trans;
Harald Welte59b04682009-06-10 05:40:52 +08002038
Harald Welte03740842009-06-10 23:11:52 +08002039 /* Find callref */
Harald Weltea54b48d2009-07-23 18:56:43 +02002040 trans = trans_find_by_callref(net, data->callref);
Harald Welte03740842009-06-10 23:11:52 +08002041 if (!trans)
2042 return -EIO;
2043 if (!trans->lchan)
2044 return 0;
2045
2046 // todo IPACCESS
2047 if (enable)
2048 return trau_recv_lchan(trans->lchan, data->callref);
2049 return trau_mux_unmap(NULL, data->callref);
2050}
2051
2052/* send a frame to channel */
2053static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2054{
2055 struct gsm_trans *trans;
2056
2057 /* Find callref */
Harald Weltea54b48d2009-07-23 18:56:43 +02002058 trans = trans_find_by_callref(net, frame->callref);
Harald Welte03740842009-06-10 23:11:52 +08002059 if (!trans)
2060 return -EIO;
2061 if (!trans->lchan)
2062 return 0;
2063 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2064 trans->lchan->type != GSM_LCHAN_TCH_H)
2065 return 0;
2066
2067 // todo IPACCESS
2068 return trau_send_lchan(trans->lchan,
2069 (struct decoded_trau_frame *)frame->data);
2070}
2071
2072
2073static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2074{
2075 DEBUGP(DCC, "-> STATUS ENQ\n");
2076 return gsm48_cc_tx_status(trans, msg);
2077}
2078
2079static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2080static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2081
2082static void gsm48_cc_timeout(void *arg)
2083{
2084 struct gsm_trans *trans = arg;
2085 int disconnect = 0, release = 0;
Harald Weltebbc636a2009-06-11 14:23:20 +08002086 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2087 int mo_location = GSM48_CAUSE_LOC_USER;
2088 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2089 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte03740842009-06-10 23:11:52 +08002090 struct gsm_mncc mo_rel, l4_rel;
2091
2092 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2093 mo_rel.callref = trans->callref;
2094 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2095 l4_rel.callref = trans->callref;
2096
Harald Weltea54b48d2009-07-23 18:56:43 +02002097 switch(trans->cc.Tcurrent) {
Harald Welte03740842009-06-10 23:11:52 +08002098 case 0x303:
2099 release = 1;
Harald Weltebbc636a2009-06-11 14:23:20 +08002100 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte03740842009-06-10 23:11:52 +08002101 break;
2102 case 0x310:
2103 disconnect = 1;
Harald Weltebbc636a2009-06-11 14:23:20 +08002104 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte03740842009-06-10 23:11:52 +08002105 break;
2106 case 0x313:
2107 disconnect = 1;
2108 /* unknown, did not find it in the specs */
2109 break;
2110 case 0x301:
2111 disconnect = 1;
Harald Weltebbc636a2009-06-11 14:23:20 +08002112 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte03740842009-06-10 23:11:52 +08002113 break;
2114 case 0x308:
Harald Weltea54b48d2009-07-23 18:56:43 +02002115 if (!trans->cc.T308_second) {
Harald Welte03740842009-06-10 23:11:52 +08002116 /* restart T308 a second time */
Harald Weltea54b48d2009-07-23 18:56:43 +02002117 gsm48_cc_tx_release(trans, &trans->cc.msg);
2118 trans->cc.T308_second = 1;
Harald Welte03740842009-06-10 23:11:52 +08002119 break; /* stay in release state */
2120 }
Harald Weltea54b48d2009-07-23 18:56:43 +02002121 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08002122 return;
2123// release = 1;
2124// l4_cause = 14;
2125// break;
2126 case 0x306:
2127 release = 1;
Harald Weltea54b48d2009-07-23 18:56:43 +02002128 mo_cause = trans->cc.msg.cause.value;
2129 mo_location = trans->cc.msg.cause.location;
Harald Welte03740842009-06-10 23:11:52 +08002130 break;
2131 case 0x323:
2132 disconnect = 1;
2133 break;
2134 default:
2135 release = 1;
2136 }
2137
2138 if (release && trans->callref) {
2139 /* process release towards layer 4 */
Harald Welte8dd09d62009-07-23 19:06:52 +02002140 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte03740842009-06-10 23:11:52 +08002141 l4_location, l4_cause);
2142 trans->callref = 0;
2143 }
2144
2145 if (disconnect && trans->callref) {
2146 /* process disconnect towards layer 4 */
2147 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte8dd09d62009-07-23 19:06:52 +02002148 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte03740842009-06-10 23:11:52 +08002149 }
2150
2151 /* process disconnect towards mobile station */
2152 if (disconnect || release) {
2153 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltea54b48d2009-07-23 18:56:43 +02002154 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2155 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2156 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte03740842009-06-10 23:11:52 +08002157 mo_rel.cause.diag_len = 3;
2158
2159 if (disconnect)
2160 gsm48_cc_tx_disconnect(trans, &mo_rel);
2161 if (release)
2162 gsm48_cc_tx_release(trans, &mo_rel);
2163 }
2164
2165}
2166
2167static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2168 int sec, int micro)
2169{
2170 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltea54b48d2009-07-23 18:56:43 +02002171 trans->cc.timer.cb = gsm48_cc_timeout;
2172 trans->cc.timer.data = trans;
2173 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2174 trans->cc.Tcurrent = current;
Harald Welte03740842009-06-10 23:11:52 +08002175}
2176
2177static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2178{
2179 struct gsm48_hdr *gh = msgb_l3(msg);
2180 u_int8_t msg_type = gh->msg_type & 0xbf;
2181 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2182 struct tlv_parsed tp;
2183 struct gsm_mncc setup;
2184
2185 memset(&setup, 0, sizeof(struct gsm_mncc));
2186 setup.callref = trans->callref;
2187 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2188 /* emergency setup is identified by msg_type */
2189 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2190 setup.emergency = 1;
2191
2192 /* use subscriber as calling party number */
2193 if (trans->subscr) {
2194 setup.fields |= MNCC_F_CALLING;
2195 strncpy(setup.calling.number, trans->subscr->extension,
2196 sizeof(setup.calling.number)-1);
Andreas Eversberg9eaa5da2009-06-15 23:22:09 +02002197 strncpy(setup.imsi, trans->subscr->imsi,
2198 sizeof(setup.imsi)-1);
Harald Welte03740842009-06-10 23:11:52 +08002199 }
2200 /* bearer capability */
2201 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2202 setup.fields |= MNCC_F_BEARER_CAP;
2203 decode_bearer_cap(&setup.bearer_cap,
2204 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2205 }
2206 /* facility */
2207 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2208 setup.fields |= MNCC_F_FACILITY;
2209 decode_facility(&setup.facility,
2210 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2211 }
2212 /* called party bcd number */
2213 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2214 setup.fields |= MNCC_F_CALLED;
2215 decode_called(&setup.called,
2216 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2217 }
2218 /* user-user */
2219 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2220 setup.fields |= MNCC_F_USERUSER;
2221 decode_useruser(&setup.useruser,
2222 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2223 }
2224 /* ss-version */
2225 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2226 setup.fields |= MNCC_F_SSVERSION;
2227 decode_ssversion(&setup.ssversion,
2228 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2229 }
2230 /* CLIR suppression */
2231 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2232 setup.clir.sup = 1;
2233 /* CLIR invocation */
2234 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2235 setup.clir.inv = 1;
2236 /* cc cap */
2237 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2238 setup.fields |= MNCC_F_CCCAP;
2239 decode_cccap(&setup.cccap,
2240 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2241 }
2242
2243 if (is_ipaccess_bts(msg->trx->bts))
2244 rsl_ipacc_bind(msg->lchan);
2245
2246 new_cc_state(trans, GSM_CSTATE_INITIATED);
2247
2248 /* indicate setup to MNCC */
Harald Welte8dd09d62009-07-23 19:06:52 +02002249 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte03740842009-06-10 23:11:52 +08002250
2251 return 0;
2252}
2253
2254static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte59b04682009-06-10 05:40:52 +08002255{
2256 struct msgb *msg = gsm48_msgb_alloc();
2257 struct gsm48_hdr *gh;
Harald Welte03740842009-06-10 23:11:52 +08002258 struct gsm_mncc *setup = arg;
Harald Welte419c0472009-07-23 21:36:44 +02002259 int rc, trans_id;
Harald Welte59b04682009-06-10 05:40:52 +08002260
2261 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2262
Harald Welte03740842009-06-10 23:11:52 +08002263 /* transaction id must not be assigned */
2264 if (trans->transaction_id != 0xff) { /* unasssigned */
2265 DEBUGP(DCC, "TX Setup with assigned transaction. "
2266 "This is not allowed!\n");
2267 /* Temporarily out of order */
Harald Welte8dd09d62009-07-23 19:06:52 +02002268 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08002269 GSM48_CAUSE_LOC_PRN_S_LU,
2270 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte03740842009-06-10 23:11:52 +08002271 trans->callref = 0;
Harald Weltea54b48d2009-07-23 18:56:43 +02002272 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08002273 return rc;
2274 }
2275
2276 /* Get free transaction_id */
Harald Welte419c0472009-07-23 21:36:44 +02002277 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2278 if (trans_id < 0) {
Harald Welte03740842009-06-10 23:11:52 +08002279 /* no free transaction ID */
Harald Welte8dd09d62009-07-23 19:06:52 +02002280 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08002281 GSM48_CAUSE_LOC_PRN_S_LU,
2282 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte03740842009-06-10 23:11:52 +08002283 trans->callref = 0;
Harald Weltea54b48d2009-07-23 18:56:43 +02002284 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08002285 return rc;
2286 }
Harald Welte419c0472009-07-23 21:36:44 +02002287 trans->transaction_id = trans_id;
Harald Welte59b04682009-06-10 05:40:52 +08002288
Harald Welte59b04682009-06-10 05:40:52 +08002289 gh->msg_type = GSM48_MT_CC_SETUP;
2290
Harald Welte03740842009-06-10 23:11:52 +08002291 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte59b04682009-06-10 05:40:52 +08002292
Harald Welte03740842009-06-10 23:11:52 +08002293 /* bearer capability */
2294 if (setup->fields & MNCC_F_BEARER_CAP)
2295 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2296 /* facility */
2297 if (setup->fields & MNCC_F_FACILITY)
2298 encode_facility(msg, 0, &setup->facility);
2299 /* progress */
2300 if (setup->fields & MNCC_F_PROGRESS)
2301 encode_progress(msg, 0, &setup->progress);
2302 /* calling party BCD number */
2303 if (setup->fields & MNCC_F_CALLING)
2304 encode_calling(msg, &setup->calling);
2305 /* called party BCD number */
2306 if (setup->fields & MNCC_F_CALLED)
2307 encode_called(msg, &setup->called);
2308 /* user-user */
2309 if (setup->fields & MNCC_F_USERUSER)
2310 encode_useruser(msg, 0, &setup->useruser);
2311 /* redirecting party BCD number */
2312 if (setup->fields & MNCC_F_REDIRECTING)
2313 encode_redirecting(msg, &setup->redirecting);
2314 /* signal */
2315 if (setup->fields & MNCC_F_SIGNAL)
2316 encode_signal(msg, setup->signal);
2317
2318 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte59b04682009-06-10 05:40:52 +08002319
Harald Welte36fe2e82009-07-23 21:13:03 +02002320 return gsm48_sendmsg(msg, trans);
Harald Welte59b04682009-06-10 05:40:52 +08002321}
2322
Harald Welte03740842009-06-10 23:11:52 +08002323static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2324{
2325 struct gsm48_hdr *gh = msgb_l3(msg);
2326 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2327 struct tlv_parsed tp;
2328 struct gsm_mncc call_conf;
2329
2330 gsm48_stop_cc_timer(trans);
2331 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2332
2333 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2334 call_conf.callref = trans->callref;
2335 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2336#if 0
2337 /* repeat */
2338 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2339 call_conf.repeat = 1;
2340 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2341 call_conf.repeat = 2;
2342#endif
2343 /* bearer capability */
2344 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2345 call_conf.fields |= MNCC_F_BEARER_CAP;
2346 decode_bearer_cap(&call_conf.bearer_cap,
2347 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2348 }
2349 /* cause */
2350 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2351 call_conf.fields |= MNCC_F_CAUSE;
2352 decode_cause(&call_conf.cause,
2353 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2354 }
2355 /* cc cap */
2356 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2357 call_conf.fields |= MNCC_F_CCCAP;
2358 decode_cccap(&call_conf.cccap,
2359 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2360 }
2361
2362 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2363
Harald Welte8dd09d62009-07-23 19:06:52 +02002364 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2365 &call_conf);
Harald Welte03740842009-06-10 23:11:52 +08002366}
2367
2368static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2369{
2370 struct gsm_mncc *proceeding = arg;
2371 struct msgb *msg = gsm48_msgb_alloc();
2372 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2373
Harald Welte03740842009-06-10 23:11:52 +08002374 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2375
2376 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2377
2378 /* bearer capability */
2379 if (proceeding->fields & MNCC_F_BEARER_CAP)
2380 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2381 /* facility */
2382 if (proceeding->fields & MNCC_F_FACILITY)
2383 encode_facility(msg, 0, &proceeding->facility);
2384 /* progress */
2385 if (proceeding->fields & MNCC_F_PROGRESS)
2386 encode_progress(msg, 0, &proceeding->progress);
2387
Harald Welte36fe2e82009-07-23 21:13:03 +02002388 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002389}
2390
2391static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2392{
2393 struct gsm48_hdr *gh = msgb_l3(msg);
2394 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2395 struct tlv_parsed tp;
2396 struct gsm_mncc alerting;
2397
2398 gsm48_stop_cc_timer(trans);
2399 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2400
2401 memset(&alerting, 0, sizeof(struct gsm_mncc));
2402 alerting.callref = trans->callref;
2403 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2404 /* facility */
2405 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2406 alerting.fields |= MNCC_F_FACILITY;
2407 decode_facility(&alerting.facility,
2408 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2409 }
2410
2411 /* progress */
2412 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2413 alerting.fields |= MNCC_F_PROGRESS;
2414 decode_progress(&alerting.progress,
2415 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2416 }
2417 /* ss-version */
2418 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2419 alerting.fields |= MNCC_F_SSVERSION;
2420 decode_ssversion(&alerting.ssversion,
2421 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2422 }
2423
2424 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2425
Harald Welte8dd09d62009-07-23 19:06:52 +02002426 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2427 &alerting);
Harald Welte03740842009-06-10 23:11:52 +08002428}
2429
2430static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2431{
2432 struct gsm_mncc *alerting = arg;
2433 struct msgb *msg = gsm48_msgb_alloc();
2434 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2435
Harald Welte03740842009-06-10 23:11:52 +08002436 gh->msg_type = GSM48_MT_CC_ALERTING;
2437
2438 /* facility */
2439 if (alerting->fields & MNCC_F_FACILITY)
2440 encode_facility(msg, 0, &alerting->facility);
2441 /* progress */
2442 if (alerting->fields & MNCC_F_PROGRESS)
2443 encode_progress(msg, 0, &alerting->progress);
2444 /* user-user */
2445 if (alerting->fields & MNCC_F_USERUSER)
2446 encode_useruser(msg, 0, &alerting->useruser);
2447
2448 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2449
Harald Welte36fe2e82009-07-23 21:13:03 +02002450 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002451}
2452
2453static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2454{
2455 struct gsm_mncc *progress = arg;
2456 struct msgb *msg = gsm48_msgb_alloc();
2457 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2458
Harald Welte03740842009-06-10 23:11:52 +08002459 gh->msg_type = GSM48_MT_CC_PROGRESS;
2460
2461 /* progress */
2462 encode_progress(msg, 1, &progress->progress);
2463 /* user-user */
2464 if (progress->fields & MNCC_F_USERUSER)
2465 encode_useruser(msg, 0, &progress->useruser);
2466
Harald Welte36fe2e82009-07-23 21:13:03 +02002467 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002468}
2469
2470static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2471{
2472 struct gsm_mncc *connect = arg;
2473 struct msgb *msg = gsm48_msgb_alloc();
2474 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2475
Harald Welte03740842009-06-10 23:11:52 +08002476 gh->msg_type = GSM48_MT_CC_CONNECT;
2477
2478 gsm48_stop_cc_timer(trans);
2479 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2480
2481 /* facility */
2482 if (connect->fields & MNCC_F_FACILITY)
2483 encode_facility(msg, 0, &connect->facility);
2484 /* progress */
2485 if (connect->fields & MNCC_F_PROGRESS)
2486 encode_progress(msg, 0, &connect->progress);
2487 /* connected number */
2488 if (connect->fields & MNCC_F_CONNECTED)
2489 encode_connected(msg, &connect->connected);
2490 /* user-user */
2491 if (connect->fields & MNCC_F_USERUSER)
2492 encode_useruser(msg, 0, &connect->useruser);
2493
2494 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2495
Harald Welte36fe2e82009-07-23 21:13:03 +02002496 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002497}
2498
2499static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2500{
2501 struct gsm48_hdr *gh = msgb_l3(msg);
2502 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2503 struct tlv_parsed tp;
2504 struct gsm_mncc connect;
2505
2506 gsm48_stop_cc_timer(trans);
2507
2508 memset(&connect, 0, sizeof(struct gsm_mncc));
2509 connect.callref = trans->callref;
2510 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2511 /* use subscriber as connected party number */
2512 if (trans->subscr) {
2513 connect.fields |= MNCC_F_CONNECTED;
2514 strncpy(connect.connected.number, trans->subscr->extension,
2515 sizeof(connect.connected.number)-1);
Andreas Eversberg9eaa5da2009-06-15 23:22:09 +02002516 strncpy(connect.imsi, trans->subscr->imsi,
2517 sizeof(connect.imsi)-1);
Harald Welte03740842009-06-10 23:11:52 +08002518 }
2519 /* facility */
2520 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2521 connect.fields |= MNCC_F_FACILITY;
2522 decode_facility(&connect.facility,
2523 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2524 }
2525 /* user-user */
2526 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2527 connect.fields |= MNCC_F_USERUSER;
2528 decode_useruser(&connect.useruser,
2529 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2530 }
2531 /* ss-version */
2532 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2533 connect.fields |= MNCC_F_SSVERSION;
2534 decode_ssversion(&connect.ssversion,
2535 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2536 }
2537
2538 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2539
Harald Welte8dd09d62009-07-23 19:06:52 +02002540 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte03740842009-06-10 23:11:52 +08002541}
2542
2543
2544static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2545{
2546 struct gsm_mncc connect_ack;
2547
2548 gsm48_stop_cc_timer(trans);
2549
2550 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2551
2552 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2553 connect_ack.callref = trans->callref;
Harald Welte8dd09d62009-07-23 19:06:52 +02002554 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte03740842009-06-10 23:11:52 +08002555 &connect_ack);
2556}
2557
2558static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2559{
2560 struct msgb *msg = gsm48_msgb_alloc();
2561 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2562
Harald Welte03740842009-06-10 23:11:52 +08002563 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2564
2565 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2566
Harald Welte36fe2e82009-07-23 21:13:03 +02002567 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002568}
2569
2570static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2571{
2572 struct gsm48_hdr *gh = msgb_l3(msg);
2573 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2574 struct tlv_parsed tp;
2575 struct gsm_mncc disc;
2576
2577 gsm48_stop_cc_timer(trans);
2578
2579 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2580
2581 memset(&disc, 0, sizeof(struct gsm_mncc));
2582 disc.callref = trans->callref;
2583 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2584 /* cause */
2585 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2586 disc.fields |= MNCC_F_CAUSE;
2587 decode_cause(&disc.cause,
2588 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2589 }
2590 /* facility */
2591 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2592 disc.fields |= MNCC_F_FACILITY;
2593 decode_facility(&disc.facility,
2594 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2595 }
2596 /* user-user */
2597 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2598 disc.fields |= MNCC_F_USERUSER;
2599 decode_useruser(&disc.useruser,
2600 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2601 }
2602 /* ss-version */
2603 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2604 disc.fields |= MNCC_F_SSVERSION;
2605 decode_ssversion(&disc.ssversion,
2606 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2607 }
2608
Harald Welte8dd09d62009-07-23 19:06:52 +02002609 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte03740842009-06-10 23:11:52 +08002610
2611}
2612
Harald Weltebbc636a2009-06-11 14:23:20 +08002613static struct gsm_mncc_cause default_cause = {
2614 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2615 .coding = 0,
2616 .rec = 0,
2617 .rec_val = 0,
2618 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2619 .diag_len = 0,
2620 .diag = { 0 },
2621};
Harald Welte03740842009-06-10 23:11:52 +08002622
2623static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2624{
2625 struct gsm_mncc *disc = arg;
2626 struct msgb *msg = gsm48_msgb_alloc();
2627 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2628
Harald Welte03740842009-06-10 23:11:52 +08002629 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2630
2631 gsm48_stop_cc_timer(trans);
2632 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2633
2634 /* cause */
2635 if (disc->fields & MNCC_F_CAUSE)
2636 encode_cause(msg, 1, &disc->cause);
2637 else
2638 encode_cause(msg, 1, &default_cause);
2639
2640 /* facility */
2641 if (disc->fields & MNCC_F_FACILITY)
2642 encode_facility(msg, 0, &disc->facility);
2643 /* progress */
2644 if (disc->fields & MNCC_F_PROGRESS)
2645 encode_progress(msg, 0, &disc->progress);
2646 /* user-user */
2647 if (disc->fields & MNCC_F_USERUSER)
2648 encode_useruser(msg, 0, &disc->useruser);
2649
2650 /* store disconnect cause for T306 expiry */
Harald Weltea54b48d2009-07-23 18:56:43 +02002651 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte03740842009-06-10 23:11:52 +08002652
2653 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2654
Harald Welte36fe2e82009-07-23 21:13:03 +02002655 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002656}
2657
2658static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2659{
2660 struct gsm48_hdr *gh = msgb_l3(msg);
2661 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2662 struct tlv_parsed tp;
2663 struct gsm_mncc rel;
2664 int rc;
2665
2666 gsm48_stop_cc_timer(trans);
2667
2668 memset(&rel, 0, sizeof(struct gsm_mncc));
2669 rel.callref = trans->callref;
2670 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2671 /* cause */
2672 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2673 rel.fields |= MNCC_F_CAUSE;
2674 decode_cause(&rel.cause,
2675 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2676 }
2677 /* facility */
2678 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2679 rel.fields |= MNCC_F_FACILITY;
2680 decode_facility(&rel.facility,
2681 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2682 }
2683 /* user-user */
2684 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2685 rel.fields |= MNCC_F_USERUSER;
2686 decode_useruser(&rel.useruser,
2687 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2688 }
2689 /* ss-version */
2690 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2691 rel.fields |= MNCC_F_SSVERSION;
2692 decode_ssversion(&rel.ssversion,
2693 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2694 }
2695
Harald Weltea54b48d2009-07-23 18:56:43 +02002696 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte03740842009-06-10 23:11:52 +08002697 /* release collision 5.4.5 */
Harald Welte8dd09d62009-07-23 19:06:52 +02002698 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte03740842009-06-10 23:11:52 +08002699 } else {
Harald Welte8dd09d62009-07-23 19:06:52 +02002700 rc = gsm48_tx_simple(msg->lchan,
Harald Welte4861c822009-07-23 21:21:14 +02002701 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte8dd09d62009-07-23 19:06:52 +02002702 GSM48_MT_CC_RELEASE_COMPL);
2703 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte03740842009-06-10 23:11:52 +08002704 }
2705
2706 new_cc_state(trans, GSM_CSTATE_NULL);
2707
2708 trans->callref = 0;
Harald Weltea54b48d2009-07-23 18:56:43 +02002709 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08002710
2711 return rc;
2712}
2713
2714static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2715{
2716 struct gsm_mncc *rel = arg;
2717 struct msgb *msg = gsm48_msgb_alloc();
2718 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2719
Harald Welte03740842009-06-10 23:11:52 +08002720 gh->msg_type = GSM48_MT_CC_RELEASE;
2721
2722 trans->callref = 0;
2723
2724 gsm48_stop_cc_timer(trans);
2725 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2726
2727 /* cause */
2728 if (rel->fields & MNCC_F_CAUSE)
2729 encode_cause(msg, 0, &rel->cause);
2730 /* facility */
2731 if (rel->fields & MNCC_F_FACILITY)
2732 encode_facility(msg, 0, &rel->facility);
2733 /* user-user */
2734 if (rel->fields & MNCC_F_USERUSER)
2735 encode_useruser(msg, 0, &rel->useruser);
2736
Harald Weltea54b48d2009-07-23 18:56:43 +02002737 trans->cc.T308_second = 0;
2738 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte03740842009-06-10 23:11:52 +08002739
Harald Weltea54b48d2009-07-23 18:56:43 +02002740 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte03740842009-06-10 23:11:52 +08002741 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2742
Harald Welte36fe2e82009-07-23 21:13:03 +02002743 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002744}
2745
2746static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2747{
2748 struct gsm48_hdr *gh = msgb_l3(msg);
2749 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2750 struct tlv_parsed tp;
2751 struct gsm_mncc rel;
2752 int rc = 0;
2753
2754 gsm48_stop_cc_timer(trans);
2755
2756 memset(&rel, 0, sizeof(struct gsm_mncc));
2757 rel.callref = trans->callref;
2758 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2759 /* cause */
2760 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2761 rel.fields |= MNCC_F_CAUSE;
2762 decode_cause(&rel.cause,
2763 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2764 }
2765 /* facility */
2766 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2767 rel.fields |= MNCC_F_FACILITY;
2768 decode_facility(&rel.facility,
2769 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2770 }
2771 /* user-user */
2772 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2773 rel.fields |= MNCC_F_USERUSER;
2774 decode_useruser(&rel.useruser,
2775 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2776 }
2777 /* ss-version */
2778 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2779 rel.fields |= MNCC_F_SSVERSION;
2780 decode_ssversion(&rel.ssversion,
2781 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2782 }
2783
2784 if (trans->callref) {
Harald Weltea54b48d2009-07-23 18:56:43 +02002785 switch (trans->cc.state) {
Harald Welte03740842009-06-10 23:11:52 +08002786 case GSM_CSTATE_CALL_PRESENT:
Harald Welte8dd09d62009-07-23 19:06:52 +02002787 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte03740842009-06-10 23:11:52 +08002788 MNCC_REJ_IND, &rel);
2789 break;
2790 case GSM_CSTATE_RELEASE_REQ:
Harald Welte8dd09d62009-07-23 19:06:52 +02002791 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte03740842009-06-10 23:11:52 +08002792 MNCC_REL_CNF, &rel);
2793 break;
2794 default:
Harald Welte8dd09d62009-07-23 19:06:52 +02002795 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte03740842009-06-10 23:11:52 +08002796 MNCC_REL_IND, &rel);
2797 }
2798 }
2799
2800 trans->callref = 0;
Harald Weltea54b48d2009-07-23 18:56:43 +02002801 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08002802
2803 return rc;
2804}
2805
2806static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2807{
2808 struct gsm_mncc *rel = arg;
2809 struct msgb *msg = gsm48_msgb_alloc();
2810 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2811
Harald Welte03740842009-06-10 23:11:52 +08002812 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2813
2814 trans->callref = 0;
2815
2816 gsm48_stop_cc_timer(trans);
2817
2818 /* cause */
2819 if (rel->fields & MNCC_F_CAUSE)
2820 encode_cause(msg, 0, &rel->cause);
2821 /* facility */
2822 if (rel->fields & MNCC_F_FACILITY)
2823 encode_facility(msg, 0, &rel->facility);
2824 /* user-user */
2825 if (rel->fields & MNCC_F_USERUSER)
2826 encode_useruser(msg, 0, &rel->useruser);
2827
Harald Weltea54b48d2009-07-23 18:56:43 +02002828 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08002829
Harald Welte36fe2e82009-07-23 21:13:03 +02002830 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002831}
2832
2833static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2834{
2835 struct gsm48_hdr *gh = msgb_l3(msg);
2836 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2837 struct tlv_parsed tp;
2838 struct gsm_mncc fac;
2839
2840 memset(&fac, 0, sizeof(struct gsm_mncc));
2841 fac.callref = trans->callref;
2842 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2843 /* facility */
2844 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2845 fac.fields |= MNCC_F_FACILITY;
2846 decode_facility(&fac.facility,
2847 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2848 }
2849 /* ss-version */
2850 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2851 fac.fields |= MNCC_F_SSVERSION;
2852 decode_ssversion(&fac.ssversion,
2853 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2854 }
2855
Harald Welte8dd09d62009-07-23 19:06:52 +02002856 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte03740842009-06-10 23:11:52 +08002857}
2858
2859static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2860{
2861 struct gsm_mncc *fac = arg;
2862 struct msgb *msg = gsm48_msgb_alloc();
2863 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2864
Harald Welte03740842009-06-10 23:11:52 +08002865 gh->msg_type = GSM48_MT_CC_FACILITY;
2866
2867 /* facility */
2868 encode_facility(msg, 1, &fac->facility);
2869
Harald Welte36fe2e82009-07-23 21:13:03 +02002870 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002871}
2872
2873static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2874{
2875 struct gsm_mncc hold;
2876
2877 memset(&hold, 0, sizeof(struct gsm_mncc));
2878 hold.callref = trans->callref;
Harald Welte8dd09d62009-07-23 19:06:52 +02002879 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte03740842009-06-10 23:11:52 +08002880}
2881
2882static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2883{
2884 struct msgb *msg = gsm48_msgb_alloc();
2885 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2886
Harald Welte03740842009-06-10 23:11:52 +08002887 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
2888
Harald Welte36fe2e82009-07-23 21:13:03 +02002889 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002890}
2891
2892static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
2893{
2894 struct gsm_mncc *hold_rej = arg;
2895 struct msgb *msg = gsm48_msgb_alloc();
2896 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2897
Harald Welte03740842009-06-10 23:11:52 +08002898 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
2899
2900 /* cause */
2901 if (hold_rej->fields & MNCC_F_CAUSE)
2902 encode_cause(msg, 1, &hold_rej->cause);
2903 else
2904 encode_cause(msg, 1, &default_cause);
2905
Harald Welte36fe2e82009-07-23 21:13:03 +02002906 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002907}
2908
2909static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
2910{
2911 struct gsm_mncc retrieve;
2912
2913 memset(&retrieve, 0, sizeof(struct gsm_mncc));
2914 retrieve.callref = trans->callref;
Harald Welte8dd09d62009-07-23 19:06:52 +02002915 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
2916 &retrieve);
Harald Welte03740842009-06-10 23:11:52 +08002917}
2918
2919static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
2920{
2921 struct msgb *msg = gsm48_msgb_alloc();
2922 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2923
Harald Welte03740842009-06-10 23:11:52 +08002924 gh->msg_type = GSM48_MT_CC_RETR_ACK;
2925
Harald Welte36fe2e82009-07-23 21:13:03 +02002926 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002927}
2928
2929static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
2930{
2931 struct gsm_mncc *retrieve_rej = arg;
2932 struct msgb *msg = gsm48_msgb_alloc();
2933 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2934
Harald Welte03740842009-06-10 23:11:52 +08002935 gh->msg_type = GSM48_MT_CC_RETR_REJ;
2936
2937 /* cause */
2938 if (retrieve_rej->fields & MNCC_F_CAUSE)
2939 encode_cause(msg, 1, &retrieve_rej->cause);
2940 else
2941 encode_cause(msg, 1, &default_cause);
2942
Harald Welte36fe2e82009-07-23 21:13:03 +02002943 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002944}
2945
2946static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
2947{
2948 struct gsm48_hdr *gh = msgb_l3(msg);
2949 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2950 struct tlv_parsed tp;
2951 struct gsm_mncc dtmf;
2952
2953 memset(&dtmf, 0, sizeof(struct gsm_mncc));
2954 dtmf.callref = trans->callref;
2955 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2956 /* keypad facility */
2957 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
2958 dtmf.fields |= MNCC_F_KEYPAD;
2959 decode_keypad(&dtmf.keypad,
2960 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
2961 }
2962
Harald Welte8dd09d62009-07-23 19:06:52 +02002963 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte03740842009-06-10 23:11:52 +08002964}
2965
2966static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
2967{
2968 struct gsm_mncc *dtmf = arg;
2969 struct msgb *msg = gsm48_msgb_alloc();
2970 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2971
Harald Welte03740842009-06-10 23:11:52 +08002972 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
2973
2974 /* keypad */
2975 if (dtmf->fields & MNCC_F_KEYPAD)
2976 encode_keypad(msg, dtmf->keypad);
2977
Harald Welte36fe2e82009-07-23 21:13:03 +02002978 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002979}
2980
2981static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
2982{
2983 struct gsm_mncc *dtmf = arg;
2984 struct msgb *msg = gsm48_msgb_alloc();
2985 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2986
Harald Welte03740842009-06-10 23:11:52 +08002987 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
2988
2989 /* cause */
2990 if (dtmf->fields & MNCC_F_CAUSE)
2991 encode_cause(msg, 1, &dtmf->cause);
2992 else
2993 encode_cause(msg, 1, &default_cause);
2994
Harald Welte36fe2e82009-07-23 21:13:03 +02002995 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08002996}
2997
2998static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
2999{
3000 struct msgb *msg = gsm48_msgb_alloc();
3001 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3002
Harald Welte03740842009-06-10 23:11:52 +08003003 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3004
Harald Welte36fe2e82009-07-23 21:13:03 +02003005 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08003006}
3007
3008static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3009{
3010 struct gsm_mncc dtmf;
3011
3012 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3013 dtmf.callref = trans->callref;
3014
Harald Welte8dd09d62009-07-23 19:06:52 +02003015 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte03740842009-06-10 23:11:52 +08003016}
3017
3018static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3019{
3020 struct gsm48_hdr *gh = msgb_l3(msg);
3021 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3022 struct tlv_parsed tp;
3023 struct gsm_mncc modify;
3024
3025 memset(&modify, 0, sizeof(struct gsm_mncc));
3026 modify.callref = trans->callref;
3027 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3028 /* bearer capability */
3029 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3030 modify.fields |= MNCC_F_BEARER_CAP;
3031 decode_bearer_cap(&modify.bearer_cap,
3032 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3033 }
3034
3035 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3036
Harald Welte8dd09d62009-07-23 19:06:52 +02003037 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte03740842009-06-10 23:11:52 +08003038}
3039
3040static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3041{
3042 struct gsm_mncc *modify = arg;
3043 struct msgb *msg = gsm48_msgb_alloc();
3044 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3045
Harald Welte03740842009-06-10 23:11:52 +08003046 gh->msg_type = GSM48_MT_CC_MODIFY;
3047
3048 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3049
3050 /* bearer capability */
3051 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3052
3053 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3054
Harald Welte36fe2e82009-07-23 21:13:03 +02003055 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08003056}
3057
3058static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3059{
3060 struct gsm48_hdr *gh = msgb_l3(msg);
3061 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3062 struct tlv_parsed tp;
3063 struct gsm_mncc modify;
3064
3065 gsm48_stop_cc_timer(trans);
3066
3067 memset(&modify, 0, sizeof(struct gsm_mncc));
3068 modify.callref = trans->callref;
3069 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3070 /* bearer capability */
3071 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3072 modify.fields |= MNCC_F_BEARER_CAP;
3073 decode_bearer_cap(&modify.bearer_cap,
3074 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3075 }
3076
3077 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3078
Harald Welte8dd09d62009-07-23 19:06:52 +02003079 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte03740842009-06-10 23:11:52 +08003080}
3081
3082static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3083{
3084 struct gsm_mncc *modify = arg;
3085 struct msgb *msg = gsm48_msgb_alloc();
3086 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3087
Harald Welte03740842009-06-10 23:11:52 +08003088 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3089
3090 /* bearer capability */
3091 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3092
3093 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3094
Harald Welte36fe2e82009-07-23 21:13:03 +02003095 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08003096}
3097
3098static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3099{
3100 struct gsm48_hdr *gh = msgb_l3(msg);
3101 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3102 struct tlv_parsed tp;
3103 struct gsm_mncc modify;
3104
3105 gsm48_stop_cc_timer(trans);
3106
3107 memset(&modify, 0, sizeof(struct gsm_mncc));
3108 modify.callref = trans->callref;
3109 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3110 /* bearer capability */
3111 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3112 modify.fields |= GSM48_IE_BEARER_CAP;
3113 decode_bearer_cap(&modify.bearer_cap,
3114 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3115 }
3116 /* cause */
3117 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3118 modify.fields |= MNCC_F_CAUSE;
3119 decode_cause(&modify.cause,
3120 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3121 }
3122
3123 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3124
Harald Welte8dd09d62009-07-23 19:06:52 +02003125 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte03740842009-06-10 23:11:52 +08003126}
3127
3128static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3129{
3130 struct gsm_mncc *modify = arg;
3131 struct msgb *msg = gsm48_msgb_alloc();
3132 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3133
Harald Welte03740842009-06-10 23:11:52 +08003134 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3135
3136 /* bearer capability */
3137 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3138 /* cause */
3139 encode_cause(msg, 1, &modify->cause);
3140
3141 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3142
Harald Welte36fe2e82009-07-23 21:13:03 +02003143 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08003144}
3145
3146static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3147{
3148 struct gsm_mncc *notify = arg;
3149 struct msgb *msg = gsm48_msgb_alloc();
3150 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3151
Harald Welte03740842009-06-10 23:11:52 +08003152 gh->msg_type = GSM48_MT_CC_NOTIFY;
3153
3154 /* notify */
3155 encode_notify(msg, notify->notify);
3156
Harald Welte36fe2e82009-07-23 21:13:03 +02003157 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08003158}
3159
3160static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3161{
3162 struct gsm48_hdr *gh = msgb_l3(msg);
3163 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3164// struct tlv_parsed tp;
3165 struct gsm_mncc notify;
3166
3167 memset(&notify, 0, sizeof(struct gsm_mncc));
3168 notify.callref = trans->callref;
3169// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3170 if (payload_len >= 1)
3171 decode_notify(&notify.notify, gh->data);
3172
Harald Welte8dd09d62009-07-23 19:06:52 +02003173 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte03740842009-06-10 23:11:52 +08003174}
3175
3176static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3177{
3178 struct gsm_mncc *user = arg;
3179 struct msgb *msg = gsm48_msgb_alloc();
3180 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3181
Harald Welte03740842009-06-10 23:11:52 +08003182 gh->msg_type = GSM48_MT_CC_USER_INFO;
3183
3184 /* user-user */
3185 if (user->fields & MNCC_F_USERUSER)
3186 encode_useruser(msg, 1, &user->useruser);
3187 /* more data */
3188 if (user->more)
3189 encode_more(msg);
3190
Harald Welte36fe2e82009-07-23 21:13:03 +02003191 return gsm48_sendmsg(msg, trans);
Harald Welte03740842009-06-10 23:11:52 +08003192}
3193
3194static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3195{
3196 struct gsm48_hdr *gh = msgb_l3(msg);
3197 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3198 struct tlv_parsed tp;
3199 struct gsm_mncc user;
3200
3201 memset(&user, 0, sizeof(struct gsm_mncc));
3202 user.callref = trans->callref;
3203 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3204 /* user-user */
3205 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3206 user.fields |= MNCC_F_USERUSER;
3207 decode_useruser(&user.useruser,
3208 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3209 }
3210 /* more data */
3211 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3212 user.more = 1;
3213
Harald Welte8dd09d62009-07-23 19:06:52 +02003214 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte03740842009-06-10 23:11:52 +08003215}
3216
3217static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3218{
3219 struct gsm_mncc *mode = arg;
3220
3221 return gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3222}
3223
3224static struct downstate {
3225 u_int32_t states;
3226 int type;
3227 int (*rout) (struct gsm_trans *trans, void *arg);
3228} downstatelist[] = {
3229 /* mobile originating call establishment */
3230 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3231 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3232 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3233 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3234 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) | SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.2 | 5.2.1.6 | 5.2.1.6 */
3235 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3236 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3237 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3238 /* mobile terminating call establishment */
3239 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3240 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3241 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3242 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3243 /* signalling during call */
3244 {SBIT(GSM_CSTATE_ACTIVE),
3245 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3246 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3247 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3248 {ALL_STATES,
3249 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3250 {ALL_STATES,
3251 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3252 {ALL_STATES,
3253 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3254 {SBIT(GSM_CSTATE_ACTIVE),
3255 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3256 {SBIT(GSM_CSTATE_ACTIVE),
3257 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3258 {SBIT(GSM_CSTATE_ACTIVE),
3259 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3260 {SBIT(GSM_CSTATE_ACTIVE),
3261 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3262 {SBIT(GSM_CSTATE_ACTIVE),
3263 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3264 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3265 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3266 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3267 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3268 {SBIT(GSM_CSTATE_ACTIVE),
3269 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3270 /* clearing */
3271 {SBIT(GSM_CSTATE_INITIATED),
3272 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3273 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3274 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3275 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3276 MNCC_REL_REQ, gsm48_cc_tx_release},
3277 /* special */
3278 {ALL_STATES,
3279 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3280};
3281
3282#define DOWNSLLEN \
3283 (sizeof(downstatelist) / sizeof(struct downstate))
3284
3285
3286int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3287{
3288 int i, j, k, l, rc = 0;
3289 struct gsm_trans *trans = NULL, *transt;
3290 struct gsm_subscriber *subscr;
3291 struct gsm_lchan *lchan = NULL, *lchant;
3292 struct gsm_bts *bts = NULL;
3293 struct gsm_bts_trx *trx;
3294 struct gsm_bts_trx_ts *ts;
3295 struct gsm_mncc *data = arg, rel;
3296
3297 /* handle special messages */
3298 switch(msg_type) {
3299 case MNCC_BRIDGE:
3300 return tch_bridge(net, arg);
3301 case MNCC_FRAME_DROP:
3302 return tch_recv(net, arg, 0);
3303 case MNCC_FRAME_RECV:
3304 return tch_recv(net, arg, 1);
3305 case GSM_TRAU_FRAME:
3306 return tch_frame(net, arg);
3307 }
3308
3309 memset(&rel, 0, sizeof(struct gsm_mncc));
3310 rel.callref = data->callref;
3311
3312 /* Find callref */
Harald Weltea54b48d2009-07-23 18:56:43 +02003313 trans = trans_find_by_callref(net, data->callref);
Harald Welte03740842009-06-10 23:11:52 +08003314
3315 /* Callref unknown */
3316 if (!trans) {
Harald Welte6e1536e2009-07-04 10:11:24 +02003317 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte03740842009-06-10 23:11:52 +08003318 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3319 "Received '%s' from MNCC with "
3320 "unknown callref %d\n", data->called.number,
3321 get_mncc_name(msg_type), data->callref);
3322 /* Invalid call reference */
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08003323 return mncc_release_ind(net, NULL, data->callref,
3324 GSM48_CAUSE_LOC_PRN_S_LU,
3325 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte03740842009-06-10 23:11:52 +08003326 }
Andreas Eversberg9eaa5da2009-06-15 23:22:09 +02003327 if (!data->called.number[0] && !data->imsi[0]) {
3328 DEBUGP(DCC, "(bts - trx - ts - ti) "
3329 "Received '%s' from MNCC with "
3330 "no number or IMSI\n", get_mncc_name(msg_type));
3331 /* Invalid number */
3332 return mncc_release_ind(net, NULL, data->callref,
3333 GSM48_CAUSE_LOC_PRN_S_LU,
3334 GSM48_CC_CAUSE_INV_NR_FORMAT);
3335 }
Harald Welte03740842009-06-10 23:11:52 +08003336 /* New transaction due to setup, find subscriber */
Andreas Eversberg9eaa5da2009-06-15 23:22:09 +02003337 if (data->called.number[0])
Harald Welteaae7a522009-07-23 19:21:02 +02003338 subscr = subscr_get_by_extension(net,
3339 data->called.number);
Andreas Eversberg9eaa5da2009-06-15 23:22:09 +02003340 else
Harald Welteaae7a522009-07-23 19:21:02 +02003341 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte03740842009-06-10 23:11:52 +08003342 /* If subscriber is not found */
3343 if (!subscr) {
3344 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3345 "Received '%s' from MNCC with "
3346 "unknown subscriber %s\n", data->called.number,
3347 get_mncc_name(msg_type), data->called.number);
3348 /* Unknown subscriber */
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08003349 return mncc_release_ind(net, NULL, data->callref,
3350 GSM48_CAUSE_LOC_PRN_S_LU,
3351 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte03740842009-06-10 23:11:52 +08003352 }
3353 /* If subscriber is not "attached" */
3354 if (!subscr->lac) {
3355 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3356 "Received '%s' from MNCC with "
3357 "detached subscriber %s\n", data->called.number,
3358 get_mncc_name(msg_type), data->called.number);
3359 subscr_put(subscr);
3360 /* Temporarily out of order */
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08003361 return mncc_release_ind(net, NULL, data->callref,
3362 GSM48_CAUSE_LOC_PRN_S_LU,
3363 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte03740842009-06-10 23:11:52 +08003364 }
3365 /* Create transaction */
Harald Weltea54b48d2009-07-23 18:56:43 +02003366 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3367 if (!trans) {
Harald Welte03740842009-06-10 23:11:52 +08003368 DEBUGP(DCC, "No memory for trans.\n");
3369 subscr_put(subscr);
3370 /* Ressource unavailable */
Andreas Eversbergb992a8a2009-06-14 22:14:12 +08003371 mncc_release_ind(net, NULL, data->callref,
3372 GSM48_CAUSE_LOC_PRN_S_LU,
3373 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte03740842009-06-10 23:11:52 +08003374 return -ENOMEM;
3375 }
Harald Welte03740842009-06-10 23:11:52 +08003376 /* Find lchan */
3377 for (i = 0; i < net->num_bts; i++) {
Harald Weltee712a5f2009-06-21 16:17:15 +02003378 bts = gsm_bts_num(net, i);
Harald Welte03740842009-06-10 23:11:52 +08003379 for (j = 0; j < bts->num_trx; j++) {
Harald Weltee712a5f2009-06-21 16:17:15 +02003380 trx = gsm_bts_trx_num(bts, j);
Harald Welte03740842009-06-10 23:11:52 +08003381 for (k = 0; k < TRX_NR_TS; k++) {
3382 ts = &trx->ts[k];
3383 for (l = 0; l < TS_MAX_LCHAN; l++) {
3384 lchant = &ts->lchan[l];
3385 if (lchant->subscr == subscr) {
3386 lchan = lchant;
3387 break;
3388 }
3389 }
3390 }
3391 }
3392 }
3393
3394 /* If subscriber has no lchan */
3395 if (!lchan) {
3396 /* find transaction with this subscriber already paging */
3397 llist_for_each_entry(transt, &net->trans_list, entry) {
3398 /* Transaction of our lchan? */
3399 if (transt == trans ||
3400 transt->subscr != subscr)
3401 continue;
3402 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3403 "Received '%s' from MNCC with "
3404 "unallocated channel, paging already "
3405 "started.\n", bts->nr,
3406 data->called.number,
3407 get_mncc_name(msg_type));
3408 return 0;
3409 }
3410 /* store setup informations until paging was successfull */
Harald Weltea54b48d2009-07-23 18:56:43 +02003411 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Welte03740842009-06-10 23:11:52 +08003412 /* start paging subscriber on all BTS with her location */
3413 subscr->net = net;
3414 bts = NULL;
3415 do {
3416 bts = gsm_bts_by_lac(net, subscr->lac, bts);
3417 if (!bts)
3418 break;
3419 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3420 "Received '%s' from MNCC with "
3421 "unallocated channel, paging.\n",
3422 bts->nr, data->called.number,
3423 get_mncc_name(msg_type));
3424 /* Trigger paging */
Harald Weltecb0595f2009-06-12 01:54:08 +08003425 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
Harald Welte03740842009-06-10 23:11:52 +08003426 setup_trig_pag_evt, subscr);
3427 } while (1);
3428 return 0;
3429 }
3430 /* Assign lchan */
3431 trans->lchan = lchan;
3432 use_lchan(lchan);
3433 }
3434 lchan = trans->lchan;
3435
3436 /* if paging did not respond yet */
3437 if (!lchan) {
3438 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3439 "Received '%s' from MNCC in paging state\n",
3440 (trans->subscr)?(trans->subscr->extension):"-",
3441 get_mncc_name(msg_type));
Harald Weltebbc636a2009-06-11 14:23:20 +08003442 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3443 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte03740842009-06-10 23:11:52 +08003444 if (msg_type == MNCC_REL_REQ)
3445 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3446 else
3447 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3448 trans->callref = 0;
Harald Weltea54b48d2009-07-23 18:56:43 +02003449 trans_free(trans);
Harald Welte03740842009-06-10 23:11:52 +08003450 return rc;
3451 }
3452
3453 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3454 "Received '%s' from MNCC in state %d (%s)\n",
3455 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3456 trans->transaction_id,
3457 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltea54b48d2009-07-23 18:56:43 +02003458 get_mncc_name(msg_type), trans->cc.state,
3459 cc_state_names[trans->cc.state]);
Harald Welte03740842009-06-10 23:11:52 +08003460
3461 /* Find function for current state and message */
3462 for (i = 0; i < DOWNSLLEN; i++)
3463 if ((msg_type == downstatelist[i].type)
Harald Weltea54b48d2009-07-23 18:56:43 +02003464 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte03740842009-06-10 23:11:52 +08003465 break;
3466 if (i == DOWNSLLEN) {
3467 DEBUGP(DCC, "Message unhandled at this state.\n");
3468 return 0;
3469 }
3470
3471 rc = downstatelist[i].rout(trans, arg);
3472
3473 return rc;
3474}
3475
3476
3477static struct datastate {
3478 u_int32_t states;
3479 int type;
3480 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3481} datastatelist[] = {
3482 /* mobile originating call establishment */
3483 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3484 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3485 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3486 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3487 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3488 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3489 /* mobile terminating call establishment */
3490 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3491 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3492 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3493 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3494 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */
3495 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3496 /* signalling during call */
3497 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3498 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3499 {SBIT(GSM_CSTATE_ACTIVE),
3500 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3501 {ALL_STATES,
3502 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3503 {ALL_STATES,
3504 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3505 {ALL_STATES,
3506 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3507 {SBIT(GSM_CSTATE_ACTIVE),
3508 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3509 {SBIT(GSM_CSTATE_ACTIVE),
3510 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3511 {SBIT(GSM_CSTATE_ACTIVE),
3512 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3513 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3514 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3515 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3516 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3517 {SBIT(GSM_CSTATE_ACTIVE),
3518 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3519 /* clearing */
3520 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3521 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3522 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3523 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3524 {ALL_STATES, /* 5.4.3.4 */
3525 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3526};
3527
3528#define DATASLLEN \
3529 (sizeof(datastatelist) / sizeof(struct datastate))
3530
Harald Welte59b04682009-06-10 05:40:52 +08003531static int gsm0408_rcv_cc(struct msgb *msg)
3532{
3533 struct gsm48_hdr *gh = msgb_l3(msg);
3534 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte4861c822009-07-23 21:21:14 +02003535 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte03740842009-06-10 23:11:52 +08003536 struct gsm_lchan *lchan = msg->lchan;
Harald Weltea54b48d2009-07-23 18:56:43 +02003537 struct gsm_trans *trans = NULL;
Harald Welte03740842009-06-10 23:11:52 +08003538 int i, rc = 0;
Harald Welte59b04682009-06-10 05:40:52 +08003539
Harald Welte03740842009-06-10 23:11:52 +08003540 if (msg_type & 0x80) {
3541 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3542 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08003543 }
Harald Welte03740842009-06-10 23:11:52 +08003544
3545 /* Find transaction */
Harald Weltea54b48d2009-07-23 18:56:43 +02003546 trans = trans_find_by_id(lchan, transaction_id);
3547
Harald Welte4861c822009-07-23 21:21:14 +02003548 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte03740842009-06-10 23:11:52 +08003549 "Received '%s' from MS in state %d (%s)\n",
3550 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3551 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltea54b48d2009-07-23 18:56:43 +02003552 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3553 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte03740842009-06-10 23:11:52 +08003554
3555 /* Create transaction */
3556 if (!trans) {
Harald Welte4861c822009-07-23 21:21:14 +02003557 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte03740842009-06-10 23:11:52 +08003558 "creating new trans.\n", transaction_id);
3559 /* Create transaction */
Harald Weltea54b48d2009-07-23 18:56:43 +02003560 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3561 transaction_id, new_callref++);
3562 if (!trans) {
Harald Welte03740842009-06-10 23:11:52 +08003563 DEBUGP(DCC, "No memory for trans.\n");
3564 rc = gsm48_tx_simple(msg->lchan,
Harald Welte4861c822009-07-23 21:21:14 +02003565 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte03740842009-06-10 23:11:52 +08003566 GSM48_MT_CC_RELEASE_COMPL);
3567 return -ENOMEM;
3568 }
Harald Welte03740842009-06-10 23:11:52 +08003569 /* Assign transaction */
Harald Welte03740842009-06-10 23:11:52 +08003570 trans->lchan = lchan;
3571 use_lchan(lchan);
Harald Welte03740842009-06-10 23:11:52 +08003572 }
3573
3574 /* find function for current state and message */
3575 for (i = 0; i < DATASLLEN; i++)
3576 if ((msg_type == datastatelist[i].type)
Harald Weltea54b48d2009-07-23 18:56:43 +02003577 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte03740842009-06-10 23:11:52 +08003578 break;
3579 if (i == DATASLLEN) {
3580 DEBUGP(DCC, "Message unhandled at this state.\n");
3581 return 0;
3582 }
3583
3584 rc = datastatelist[i].rout(trans, msg);
Harald Welte59b04682009-06-10 05:40:52 +08003585
3586 return rc;
3587}
3588
3589/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3590int gsm0408_rcvmsg(struct msgb *msg)
3591{
3592 struct gsm48_hdr *gh = msgb_l3(msg);
3593 u_int8_t pdisc = gh->proto_discr & 0x0f;
3594 int rc = 0;
3595
3596 switch (pdisc) {
3597 case GSM48_PDISC_CC:
3598 rc = gsm0408_rcv_cc(msg);
3599 break;
3600 case GSM48_PDISC_MM:
3601 rc = gsm0408_rcv_mm(msg);
3602 break;
3603 case GSM48_PDISC_RR:
3604 rc = gsm0408_rcv_rr(msg);
3605 break;
3606 case GSM48_PDISC_SMS:
3607 rc = gsm0411_rcv_sms(msg);
3608 break;
3609 case GSM48_PDISC_MM_GPRS:
3610 case GSM48_PDISC_SM_GPRS:
3611 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3612 pdisc);
3613 break;
3614 default:
3615 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3616 pdisc);
3617 break;
3618 }
3619
3620 return rc;
3621}
3622
Harald Welte59b04682009-06-10 05:40:52 +08003623/* Section 9.1.8 / Table 9.9 */
3624struct chreq {
3625 u_int8_t val;
3626 u_int8_t mask;
3627 enum chreq_type type;
3628};
3629
3630/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3631static const struct chreq chreq_type_neci1[] = {
3632 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3633 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3634 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3635 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3636 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3637 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3638 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3639 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3640 { 0x10, 0xf0, CHREQ_T_SDCCH },
3641 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3642 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3643 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3644};
3645
3646/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3647static const struct chreq chreq_type_neci0[] = {
3648 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3649 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3650 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3651 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3652 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3653 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3654 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3655 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3656};
3657
3658static const enum gsm_chan_t ctype_by_chreq[] = {
3659 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3660 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3661 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3662 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3663 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3664 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3665 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3666 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3667 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3668 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3669 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3670 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3671};
3672
3673static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3674 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3675 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3676 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3677 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3678 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3679 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3680 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3681 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3682 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3683 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3684 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3685 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3686};
3687
3688enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3689{
3690 int i;
3691 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3692
3693 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3694 const struct chreq *chr = &chreq_type_neci0[i];
3695 if ((ra & chr->mask) == chr->val)
3696 return ctype_by_chreq[chr->type];
3697 }
3698 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3699 return GSM_LCHAN_SDCCH;
3700}
3701
3702enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3703{
3704 int i;
3705 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3706
3707 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3708 const struct chreq *chr = &chreq_type_neci0[i];
3709 if ((ra & chr->mask) == chr->val)
3710 return reason_by_chreq[chr->type];
3711 }
3712 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3713 return GSM_CHREQ_REASON_OTHER;
3714}
Harald Welte03740842009-06-10 23:11:52 +08003715
3716/* dequeue messages to layer 4 */
3717int bsc_upqueue(struct gsm_network *net)
3718{
3719 struct gsm_mncc *mncc;
3720 struct msgb *msg;
3721 int work = 0;
3722
3723 if (net)
3724 while ((msg = msgb_dequeue(&net->upqueue))) {
3725 mncc = (struct gsm_mncc *)msg->data;
3726 if (net->mncc_recv)
3727 net->mncc_recv(net, mncc->msg_type, mncc);
3728 work = 1; /* work done */
Harald Weltebaf4d3a2009-06-26 19:40:48 +02003729 talloc_free(msg);
Harald Welte03740842009-06-10 23:11:52 +08003730 }
3731
3732 return work;
3733}
Harald Weltea54b48d2009-07-23 18:56:43 +02003734