blob: 4359f870984a1887f2f6cbfbc4e8a29d8de10417 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* 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
Harald Weltebf5e8df2009-02-03 12:59:45 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte498b0bb2009-01-09 21:27:43 +00005 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte8470bf22008-12-25 23:28:35 +00006 *
Harald Welte52b1f982008-12-23 20:25:15 +00007 * 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>
Harald Weltedb253af2008-12-30 17:56:55 +000030#include <time.h>
Harald Welte4b634542008-12-27 01:55:51 +000031#include <netinet/in.h>
Harald Welte52b1f982008-12-23 20:25:15 +000032
Harald Welte75a983f2008-12-27 21:34:06 +000033#include <openbsc/db.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <openbsc/msgb.h>
Harald Welte7584aea2009-02-11 11:44:12 +000035#include <openbsc/tlv.h>
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <openbsc/debug.h>
37#include <openbsc/gsm_data.h>
38#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000039#include <openbsc/gsm_04_11.h>
Harald Welte8470bf22008-12-25 23:28:35 +000040#include <openbsc/gsm_04_08.h>
41#include <openbsc/abis_rsl.h>
Holger Freytherca362a62009-01-04 21:05:01 +000042#include <openbsc/chan_alloc.h>
Harald Welte0b4c34e2009-02-09 17:54:43 +000043#include <openbsc/paging.h>
Holger Freyther053e09d2009-02-14 22:51:06 +000044#include <openbsc/signal.h>
Harald Welte45b407a2009-05-23 15:51:12 +000045#include <openbsc/trau_frame.h>
Harald Welte11fa29c2009-02-19 17:24:39 +000046#include <openbsc/trau_mux.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020047#include <openbsc/talloc.h>
Harald Welteaa0b29c2009-07-23 18:56:43 +020048#include <openbsc/transaction.h>
Harald Welte52b1f982008-12-23 20:25:15 +000049
Harald Welte8470bf22008-12-25 23:28:35 +000050#define GSM48_ALLOC_SIZE 1024
51#define GSM48_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000052
Harald Welte0c389302009-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 Welte2cf161b2009-06-20 22:36:41 +020057static void *tall_locop_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020058
Harald Welte09e38af2009-02-16 22:52:23 +000059static 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 Welte0c389302009-06-10 12:08:54 +080075 [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
Harald Welte09e38af2009-02-16 22:52:23 +000076 [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
77 [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
Harald Welte0c389302009-06-10 12:08:54 +080078 [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
79 [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
Harald Welte09e38af2009-02-16 22:52:23 +000080 [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 Welte0c389302009-06-10 12:08:54 +080094 [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
95 [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
Harald Welte09e38af2009-02-16 22:52:23 +000096 /* FIXME: more elements */
97 },
98};
Harald Weltecf5b3592009-05-01 18:28:42 +000099
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 Welte4bfdfe72009-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 Weltecf5b3592009-05-01 18:28:42 +0000222static 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
Harald Weltef7c43522009-06-09 20:24:21 +0000234static 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
Holger Freytherd51524f2009-06-09 08:27:07 +0000291int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
Harald Welte65e74cc2008-12-29 01:55:35 +0000292static int gsm48_tx_simple(struct gsm_lchan *lchan,
293 u_int8_t pdisc, u_int8_t msg_type);
Holger Freytherb7193e42008-12-29 17:44:08 +0000294static void schedule_reject(struct gsm_lchan *lchan);
Harald Welte65e74cc2008-12-29 01:55:35 +0000295
Harald Welte52b1f982008-12-23 20:25:15 +0000296struct gsm_lai {
297 u_int16_t mcc;
298 u_int16_t mnc;
299 u_int16_t lac;
300};
301
Holger Freyther89824fc2008-12-30 16:18:18 +0000302static int authorize_everonye = 0;
303void gsm0408_allow_everyone(int everyone)
304{
305 printf("Allowing everyone?\n");
306 authorize_everonye = everyone;
307}
308
Holger Freythere97f7fb2008-12-31 18:52:11 +0000309static int reject_cause = 0;
310void gsm0408_set_reject_cause(int cause)
311{
312 reject_cause = cause;
313}
314
Harald Welte4bfdfe72009-06-10 23:11:52 +0800315static u_int32_t new_callref = 0x80000001;
316
Holger Freyther73487a22008-12-31 18:53:57 +0000317static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
318 struct gsm_subscriber *subscriber)
Holger Freyther89824fc2008-12-30 16:18:18 +0000319{
320 if (!subscriber)
321 return 0;
322
Holger Freyther73487a22008-12-31 18:53:57 +0000323 /*
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
Holger Freyther89824fc2008-12-30 16:18:18 +0000331 if (authorize_everonye)
332 return 1;
333
334 return subscriber->authorized;
335}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000336
Holger Freyther73487a22008-12-31 18:53:57 +0000337static void release_loc_updating_req(struct gsm_lchan *lchan)
338{
Harald Welte179f0642008-12-31 23:59:18 +0000339 if (!lchan->loc_operation)
Holger Freyther73487a22008-12-31 18:53:57 +0000340 return;
341
Harald Welteff117a82009-05-23 05:22:08 +0000342 bsc_del_timer(&lchan->loc_operation->updating_timer);
Harald Welte2cf161b2009-06-20 22:36:41 +0200343 talloc_free(lchan->loc_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000344 lchan->loc_operation = 0;
Holger Freyther3eaa7922009-01-01 02:59:03 +0000345 put_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000346}
347
348static void allocate_loc_updating_req(struct gsm_lchan *lchan)
349{
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000350 use_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000351 release_loc_updating_req(lchan);
352
Harald Welte2cf161b2009-06-20 22:36:41 +0200353 if (!tall_locop_ctx)
354 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
355 "loc_updating_oper");
Harald Welte470ec292009-06-26 20:25:23 +0200356 lchan->loc_operation = talloc_zero(tall_locop_ctx,
357 struct gsm_loc_updating_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000358}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000359
Holger Freytherd51524f2009-06-09 08:27:07 +0000360static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
361{
362 u_int32_t tmsi;
363
364 if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
365 db_subscriber_alloc_tmsi(lchan->subscr);
366 subscr_update(lchan->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED);
367 tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
368 release_loc_updating_req(lchan);
369 return gsm0408_loc_upd_acc(msg->lchan, tmsi);
370 }
371
372 return 0;
373}
374
Holger Freyther7c19f742009-06-06 13:54:35 +0000375static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
376 void *handler_data, void *signal_data)
377{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800378 struct gsm_trans *trans, *temp;
379
Holger Freyther7c19f742009-06-06 13:54:35 +0000380 if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
381 return 0;
382
383 /*
384 * Cancel any outstanding location updating request
385 * operation taking place on the lchan.
386 */
Harald Welte1a5c6bd2009-07-04 09:35:21 +0200387 struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
Harald Weltec05677b2009-06-26 20:17:06 +0200388 if (!lchan)
389 return 0;
390
Holger Freyther7c19f742009-06-06 13:54:35 +0000391 release_loc_updating_req(lchan);
392
Harald Welte4bfdfe72009-06-10 23:11:52 +0800393 /* Free all transactions that are associated with the released lchan */
Harald Welteaa0b29c2009-07-23 18:56:43 +0200394 /* FIXME: this is not neccessarily the right thing to do, we should
395 * only set trans->lchan to NULL and wait for another lchan to be
396 * established to the same MM entity (phone/subscriber) */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800397 llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
398 if (trans->lchan == lchan)
Harald Welteaa0b29c2009-07-23 18:56:43 +0200399 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800400 }
401
Holger Freyther7c19f742009-06-06 13:54:35 +0000402 return 0;
403}
404
405/*
406 * This will be ran by the linker when loading the DSO. We use it to
407 * do system initialization, e.g. registration of signal handlers.
408 */
409static __attribute__((constructor)) void on_dso_load_0408(void)
410{
411 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
412}
413
Harald Welte52b1f982008-12-23 20:25:15 +0000414static void to_bcd(u_int8_t *bcd, u_int16_t val)
415{
Harald Welte4b634542008-12-27 01:55:51 +0000416 bcd[2] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000417 val = val / 10;
418 bcd[1] = val % 10;
419 val = val / 10;
Harald Welte4b634542008-12-27 01:55:51 +0000420 bcd[0] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000421 val = val / 10;
422}
423
Holger Freyther17746612008-12-28 16:32:44 +0000424void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
Harald Welte52b1f982008-12-23 20:25:15 +0000425 u_int16_t mnc, u_int16_t lac)
426{
427 u_int8_t bcd[3];
428
429 to_bcd(bcd, mcc);
430 lai48->digits[0] = bcd[0] | (bcd[1] << 4);
431 lai48->digits[1] = bcd[2];
432
433 to_bcd(bcd, mnc);
Harald Welte4b634542008-12-27 01:55:51 +0000434 /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
435#if 0
Harald Welte8470bf22008-12-25 23:28:35 +0000436 lai48->digits[1] |= bcd[2] << 4;
437 lai48->digits[2] = bcd[0] | (bcd[1] << 4);
Harald Welte4b634542008-12-27 01:55:51 +0000438#else
439 lai48->digits[1] |= 0xf << 4;
440 lai48->digits[2] = bcd[1] | (bcd[2] << 4);
441#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000442
Harald Welte4b634542008-12-27 01:55:51 +0000443 lai48->lac = htons(lac);
Harald Welte52b1f982008-12-23 20:25:15 +0000444}
445
Harald Welte255539c2008-12-28 02:26:27 +0000446#define TMSI_LEN 5
Harald Welte52b1f982008-12-23 20:25:15 +0000447#define MID_TMSI_LEN (TMSI_LEN + 2)
448
Harald Welte255539c2008-12-28 02:26:27 +0000449int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +0000450{
Harald Welte65e74cc2008-12-29 01:55:35 +0000451 u_int32_t *tptr = (u_int32_t *) &buf[3];
Harald Welte255539c2008-12-28 02:26:27 +0000452
Harald Welte4b634542008-12-27 01:55:51 +0000453 buf[0] = GSM48_IE_MOBILE_ID;
Harald Welte1a412182008-12-27 22:13:43 +0000454 buf[1] = TMSI_LEN;
Harald Welte4b634542008-12-27 01:55:51 +0000455 buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
Harald Welte255539c2008-12-28 02:26:27 +0000456 *tptr = htonl(tmsi);
457
458 return 7;
Harald Welte52b1f982008-12-23 20:25:15 +0000459}
460
Harald Welte09e38af2009-02-16 22:52:23 +0000461static const char bcd_num_digits[] = {
462 '0', '1', '2', '3', '4', '5', '6', '7',
463 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
464};
465
Harald Welte0c389302009-06-10 12:08:54 +0800466/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
467int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
468 int h_len)
Harald Welte09e38af2009-02-16 22:52:23 +0000469{
470 u_int8_t in_len = bcd_lv[0];
471 int i;
472
Harald Welte0c389302009-06-10 12:08:54 +0800473 for (i = 1 + h_len; i <= in_len; i++) {
Harald Welte09e38af2009-02-16 22:52:23 +0000474 /* lower nibble */
475 output_len--;
476 if (output_len <= 1)
477 break;
478 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
479
480 /* higher nibble */
481 output_len--;
482 if (output_len <= 1)
483 break;
484 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
485 }
486 if (output_len >= 1)
487 *output++ = '\0';
488
Harald Welte0c389302009-06-10 12:08:54 +0800489 return 0;
Harald Welte09e38af2009-02-16 22:52:23 +0000490}
491
492/* convert a single ASCII character to call-control BCD */
493static int asc_to_bcd(const char asc)
494{
495 int i;
496
497 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
498 if (bcd_num_digits[i] == asc)
499 return i;
500 }
501 return -EINVAL;
502}
503
Harald Welte0c389302009-06-10 12:08:54 +0800504/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
Harald Welte09e38af2009-02-16 22:52:23 +0000505int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
Harald Welte0c389302009-06-10 12:08:54 +0800506 int h_len, const char *input)
Harald Welte09e38af2009-02-16 22:52:23 +0000507{
508 int in_len = strlen(input);
509 int i;
Harald Welte0c389302009-06-10 12:08:54 +0800510 u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000511
512 /* two digits per byte, plus type byte */
Harald Welte0c389302009-06-10 12:08:54 +0800513 bcd_lv[0] = in_len/2 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000514 if (in_len % 2)
515 bcd_lv[0]++;
516
Harald Welte0c389302009-06-10 12:08:54 +0800517 if (bcd_lv[0] > max_len)
518 return -EIO;
Harald Welte09e38af2009-02-16 22:52:23 +0000519
520 for (i = 0; i < in_len; i++) {
521 int rc = asc_to_bcd(input[i]);
522 if (rc < 0)
523 return rc;
524 if (i % 2 == 0)
525 *bcd_cur = rc;
526 else
527 *bcd_cur++ |= (rc << 4);
528 }
529 /* append padding nibble in case of odd length */
530 if (i % 2)
531 *bcd_cur++ |= 0xf0;
532
533 /* return how many bytes we used */
534 return (bcd_cur - bcd_lv);
535}
536
Harald Welte0c389302009-06-10 12:08:54 +0800537/* decode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800538static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
Harald Welte0c389302009-06-10 12:08:54 +0800539 const u_int8_t *lv)
540{
541 u_int8_t in_len = lv[0];
542 int i, s;
543
544 if (in_len < 1)
545 return -EINVAL;
546
Harald Welte4bfdfe72009-06-10 23:11:52 +0800547 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
Harald Welte0c389302009-06-10 12:08:54 +0800548
549 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800550 bcap->transfer = lv[1] & 0x07;
551 bcap->mode = (lv[1] & 0x08) >> 3;
552 bcap->coding = (lv[1] & 0x10) >> 4;
553 bcap->radio = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800554
555 i = 1;
556 s = 0;
557 while(!(lv[i] & 0x80)) {
558 i++; /* octet 3a etc */
559 if (in_len < i)
560 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800561 bcap->speech_ver[s++] = lv[i] & 0x0f;
562 bcap->speech_ver[s] = -1; /* end of list */
Harald Welte0c389302009-06-10 12:08:54 +0800563 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800564 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800565 if (s == 7) /* maximum speech versions + end of list */
566 return 0;
567 }
568
569 return 0;
570}
571
572/* encode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800573static int encode_bearer_cap(struct msgb *msg, int lv_only,
574 const struct gsm_mncc_bearer_cap *bcap)
Harald Welte0c389302009-06-10 12:08:54 +0800575{
576 u_int8_t lv[32 + 1];
577 int i, s;
578
Harald Welte4bfdfe72009-06-10 23:11:52 +0800579 lv[1] = bcap->transfer;
580 lv[1] |= bcap->mode << 3;
581 lv[1] |= bcap->coding << 4;
582 lv[1] |= bcap->radio << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800583
584 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800585 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
Harald Welte0c389302009-06-10 12:08:54 +0800586 i++; /* octet 3a etc */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800587 lv[i] = bcap->speech_ver[s];
Harald Welte0c389302009-06-10 12:08:54 +0800588 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800589 lv[i] |= bcap->speech_ctm << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800590 }
591 lv[i] |= 0x80; /* last IE of octet 3 etc */
592
593 lv[0] = i;
594 if (lv_only)
595 msgb_lv_put(msg, lv[0], lv+1);
596 else
597 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
598
599 return 0;
600}
601
602/* decode 'call control cap' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800603static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800604{
605 u_int8_t in_len = lv[0];
606
607 if (in_len < 1)
608 return -EINVAL;
609
610 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800611 ccap->dtmf = lv[1] & 0x01;
612 ccap->pcp = (lv[1] & 0x02) >> 1;
Harald Welte0c389302009-06-10 12:08:54 +0800613
614 return 0;
615}
616
617/* decode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800618static int decode_called(struct gsm_mncc_number *called,
619 const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800620{
621 u_int8_t in_len = lv[0];
622
623 if (in_len < 1)
624 return -EINVAL;
625
626 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800627 called->plan = lv[1] & 0x0f;
628 called->type = (lv[1] & 0x70) >> 4;
Harald Welte0c389302009-06-10 12:08:54 +0800629
630 /* octet 4..N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800631 decode_bcd_number(called->number, sizeof(called->number), lv, 1);
Harald Welte0c389302009-06-10 12:08:54 +0800632
633 return 0;
634}
635
636/* encode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800637static int encode_called(struct msgb *msg,
638 const struct gsm_mncc_number *called)
Harald Welte0c389302009-06-10 12:08:54 +0800639{
640 u_int8_t lv[18];
641 int ret;
642
643 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800644 lv[1] = called->plan;
645 lv[1] |= called->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800646
647 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800648 ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
Harald Welte0c389302009-06-10 12:08:54 +0800649 if (ret < 0)
650 return ret;
651
652 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
653
654 return 0;
655}
656
657/* encode callerid of various IEs */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800658static int encode_callerid(struct msgb *msg, int ie,
659 const struct gsm_mncc_number *callerid)
Harald Welte0c389302009-06-10 12:08:54 +0800660{
661 u_int8_t lv[13];
662 int h_len = 1;
663 int ret;
664
665 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800666 lv[1] = callerid->plan;
667 lv[1] |= callerid->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800668
Harald Welte4bfdfe72009-06-10 23:11:52 +0800669 if (callerid->present || callerid->screen) {
Harald Welte0c389302009-06-10 12:08:54 +0800670 /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800671 lv[2] = callerid->screen;
672 lv[2] |= callerid->present << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800673 lv[2] |= 0x80;
674 h_len++;
675 } else
676 lv[1] |= 0x80;
677
678 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800679 ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
Harald Welte0c389302009-06-10 12:08:54 +0800680 if (ret < 0)
681 return ret;
682
683 msgb_tlv_put(msg, ie, lv[0], lv+1);
684
685 return 0;
686}
687
688/* decode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800689static int decode_cause(struct gsm_mncc_cause *cause,
Harald Welte0c389302009-06-10 12:08:54 +0800690 const u_int8_t *lv)
691{
692 u_int8_t in_len = lv[0];
693 int i;
694
695 if (in_len < 2)
696 return -EINVAL;
697
Harald Welte4bfdfe72009-06-10 23:11:52 +0800698 cause->diag_len = 0;
Harald Welte0c389302009-06-10 12:08:54 +0800699
700 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800701 cause->location = lv[1] & 0x0f;
702 cause->coding = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800703
704 i = 1;
705 if (!(lv[i] & 0x80)) {
706 i++; /* octet 3a */
707 if (in_len < i+1)
708 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800709 cause->rec = 1;
710 cause->rec_val = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800711
712 }
713 i++;
714
715 /* octet 4 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800716 cause->value = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800717 i++;
718
719 if (in_len < i) /* no diag */
720 return 0;
721
722 if (in_len - (i-1) > 32) /* maximum 32 octets */
723 return 0;
724
725 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800726 memcpy(cause->diag, lv + i, in_len - (i-1));
727 cause->diag_len = in_len - (i-1);
Harald Welte0c389302009-06-10 12:08:54 +0800728
729 return 0;
730}
731
732/* encode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800733static int encode_cause(struct msgb *msg, int lv_only,
734 const struct gsm_mncc_cause *cause)
Harald Welte0c389302009-06-10 12:08:54 +0800735{
736 u_int8_t lv[32+4];
737 int i;
738
Harald Welte4bfdfe72009-06-10 23:11:52 +0800739 if (cause->diag_len > 32)
Harald Welte0c389302009-06-10 12:08:54 +0800740 return -EINVAL;
741
742 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800743 lv[1] = cause->location;
744 lv[1] |= cause->coding << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800745
746 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800747 if (cause->rec) {
Harald Welte0c389302009-06-10 12:08:54 +0800748 i++; /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800749 lv[i] = cause->rec_val;
Harald Welte0c389302009-06-10 12:08:54 +0800750 }
751 lv[i] |= 0x80; /* end of octet 3 */
752
753 /* octet 4 */
754 i++;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800755 lv[i] = 0x80 | cause->value;
Harald Welte0c389302009-06-10 12:08:54 +0800756
757 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800758 if (cause->diag_len) {
759 memcpy(lv + i, cause->diag, cause->diag_len);
760 i += cause->diag_len;
Harald Welte0c389302009-06-10 12:08:54 +0800761 }
762
763 lv[0] = i;
764 if (lv_only)
765 msgb_lv_put(msg, lv[0], lv+1);
766 else
767 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
768
769 return 0;
770}
771
772/* encode 'calling number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800773static int encode_calling(struct msgb *msg,
774 const struct gsm_mncc_number *calling)
Harald Welte0c389302009-06-10 12:08:54 +0800775{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800776 return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
Harald Welte0c389302009-06-10 12:08:54 +0800777}
778
779/* encode 'connected number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800780static int encode_connected(struct msgb *msg,
781 const struct gsm_mncc_number *connected)
Harald Welte0c389302009-06-10 12:08:54 +0800782{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800783 return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
Harald Welte0c389302009-06-10 12:08:54 +0800784}
785
786/* encode 'redirecting number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800787static int encode_redirecting(struct msgb *msg,
788 const struct gsm_mncc_number *redirecting)
Harald Welte0c389302009-06-10 12:08:54 +0800789{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800790 return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
Harald Welte0c389302009-06-10 12:08:54 +0800791}
792
793/* decode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800794static int decode_facility(struct gsm_mncc_facility *facility,
Harald Welte0c389302009-06-10 12:08:54 +0800795 const u_int8_t *lv)
796{
797 u_int8_t in_len = lv[0];
798
799 if (in_len < 1)
800 return -EINVAL;
801
Harald Welte4bfdfe72009-06-10 23:11:52 +0800802 if (in_len > sizeof(facility->info))
Harald Welte0c389302009-06-10 12:08:54 +0800803 return -EINVAL;
804
Harald Welte4bfdfe72009-06-10 23:11:52 +0800805 memcpy(facility->info, lv+1, in_len);
806 facility->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800807
808 return 0;
809}
810
811/* encode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800812static int encode_facility(struct msgb *msg, int lv_only,
813 const struct gsm_mncc_facility *facility)
Harald Welte0c389302009-06-10 12:08:54 +0800814{
815 u_int8_t lv[GSM_MAX_FACILITY + 1];
816
Harald Welte4bfdfe72009-06-10 23:11:52 +0800817 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
Harald Welte0c389302009-06-10 12:08:54 +0800818 return -EINVAL;
819
Harald Welte4bfdfe72009-06-10 23:11:52 +0800820 memcpy(lv+1, facility->info, facility->len);
821 lv[0] = facility->len;
Harald Welte0c389302009-06-10 12:08:54 +0800822 if (lv_only)
823 msgb_lv_put(msg, lv[0], lv+1);
824 else
825 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
826
827 return 0;
828}
829
830/* decode 'notify' */
831static int decode_notify(int *notify, const u_int8_t *v)
832{
833 *notify = v[0] & 0x7f;
834
835 return 0;
836}
837
838/* encode 'notify' */
839static int encode_notify(struct msgb *msg, int notify)
840{
841 msgb_v_put(msg, notify | 0x80);
842
843 return 0;
844}
845
846/* encode 'signal' */
847static int encode_signal(struct msgb *msg, int signal)
848{
849 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
850
851 return 0;
852}
853
854/* decode 'keypad' */
855static int decode_keypad(int *keypad, const u_int8_t *lv)
856{
857 u_int8_t in_len = lv[0];
858
859 if (in_len < 1)
860 return -EINVAL;
861
862 *keypad = lv[1] & 0x7f;
863
864 return 0;
865}
866
867/* encode 'keypad' */
868static int encode_keypad(struct msgb *msg, int keypad)
869{
870 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
871
872 return 0;
873}
874
875/* decode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800876static int decode_progress(struct gsm_mncc_progress *progress,
Harald Welte0c389302009-06-10 12:08:54 +0800877 const u_int8_t *lv)
878{
879 u_int8_t in_len = lv[0];
880
881 if (in_len < 2)
882 return -EINVAL;
883
Harald Welte4bfdfe72009-06-10 23:11:52 +0800884 progress->coding = (lv[1] & 0x60) >> 5;
885 progress->location = lv[1] & 0x0f;
886 progress->descr = lv[2] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800887
888 return 0;
889}
890
891/* encode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800892static int encode_progress(struct msgb *msg, int lv_only,
893 const struct gsm_mncc_progress *p)
Harald Welte0c389302009-06-10 12:08:54 +0800894{
895 u_int8_t lv[3];
896
897 lv[0] = 2;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800898 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
899 lv[2] = 0x80 | (p->descr & 0x7f);
Harald Welte0c389302009-06-10 12:08:54 +0800900 if (lv_only)
901 msgb_lv_put(msg, lv[0], lv+1);
902 else
903 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
904
905 return 0;
906}
907
908/* decode 'user-user' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800909static int decode_useruser(struct gsm_mncc_useruser *uu,
Harald Welte0c389302009-06-10 12:08:54 +0800910 const u_int8_t *lv)
911{
912 u_int8_t in_len = lv[0];
Harald Welte4bfdfe72009-06-10 23:11:52 +0800913 char *info = uu->info;
914 int info_len = sizeof(uu->info);
Harald Welte0c389302009-06-10 12:08:54 +0800915 int i;
916
917 if (in_len < 1)
918 return -EINVAL;
919
Harald Welte4bfdfe72009-06-10 23:11:52 +0800920 uu->proto = lv[1];
Harald Welte0c389302009-06-10 12:08:54 +0800921
922 for (i = 2; i <= in_len; i++) {
923 info_len--;
924 if (info_len <= 1)
925 break;
926 *info++ = lv[i];
927 }
928 if (info_len >= 1)
929 *info++ = '\0';
930
931 return 0;
932}
933
934/* encode 'useruser' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800935static int encode_useruser(struct msgb *msg, int lv_only,
936 const struct gsm_mncc_useruser *uu)
Harald Welte0c389302009-06-10 12:08:54 +0800937{
938 u_int8_t lv[GSM_MAX_USERUSER + 2];
939
Harald Welte4bfdfe72009-06-10 23:11:52 +0800940 if (strlen(uu->info) > GSM_MAX_USERUSER)
Harald Welte0c389302009-06-10 12:08:54 +0800941 return -EINVAL;
942
Harald Welte4bfdfe72009-06-10 23:11:52 +0800943 lv[0] = 1 + strlen(uu->info);
944 lv[1] = uu->proto;
945 memcpy(lv + 2, uu->info, strlen(uu->info));
Harald Welte0c389302009-06-10 12:08:54 +0800946 if (lv_only)
947 msgb_lv_put(msg, lv[0], lv+1);
948 else
949 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
950
951 return 0;
952}
953
954/* decode 'ss version' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800955static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
Harald Welte0c389302009-06-10 12:08:54 +0800956 const u_int8_t *lv)
957{
958 u_int8_t in_len = lv[0];
959
Harald Welte4bfdfe72009-06-10 23:11:52 +0800960 if (in_len < 1 || in_len < sizeof(ssv->info))
Harald Welte0c389302009-06-10 12:08:54 +0800961 return -EINVAL;
962
Harald Welte4bfdfe72009-06-10 23:11:52 +0800963 memcpy(ssv->info, lv + 1, in_len);
964 ssv->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800965
966 return 0;
967}
968
969/* encode 'more data' */
970static int encode_more(struct msgb *msg)
971{
972 u_int8_t *ie;
973
974 ie = msgb_put(msg, 1);
975 ie[0] = GSM48_IE_MORE_DATA;
976
977 return 0;
978}
979
Holger Freyther819dd202009-01-04 03:52:50 +0000980struct msgb *gsm48_msgb_alloc(void)
Harald Welte8470bf22008-12-25 23:28:35 +0000981{
Harald Welte966636f2009-06-26 19:39:35 +0200982 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
983 "GSM 04.08");
Harald Welte8470bf22008-12-25 23:28:35 +0000984}
985
Holger Freyther3e2c3232009-01-04 03:55:31 +0000986int gsm48_sendmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000987{
Harald Welte65e74cc2008-12-29 01:55:35 +0000988 if (msg->lchan) {
Harald Welte4bfdfe72009-06-10 23:11:52 +0800989 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000990 msg->trx = msg->lchan->ts->trx;
Harald Welte52b1f982008-12-23 20:25:15 +0000991
Harald Welte4bfdfe72009-06-10 23:11:52 +0800992 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
993 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
994 "Sending '%s' to MS.\n", msg->trx->bts->nr,
995 msg->trx->nr, msg->lchan->ts->nr,
996 gh->proto_discr & 0xf0,
997 cc_msg_names[gh->msg_type & 0x3f]);
998 else
999 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
1000 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
1001 msg->trx->nr, msg->lchan->ts->nr,
1002 gh->proto_discr, gh->msg_type);
Harald Welte65e74cc2008-12-29 01:55:35 +00001003 }
1004
Harald Welte4b634542008-12-27 01:55:51 +00001005 msg->l3h = msg->data;
1006
Harald Welte8470bf22008-12-25 23:28:35 +00001007 return rsl_data_request(msg, 0);
Harald Welte52b1f982008-12-23 20:25:15 +00001008}
1009
Holger Freyther429e7762008-12-30 13:28:30 +00001010/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
Harald Welte8470bf22008-12-25 23:28:35 +00001011int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
Harald Welte52b1f982008-12-23 20:25:15 +00001012{
Harald Welte8470bf22008-12-25 23:28:35 +00001013 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001014 struct gsm48_hdr *gh;
1015
Harald Welte8470bf22008-12-25 23:28:35 +00001016 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001017
1018 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1019 gh->proto_discr = GSM48_PDISC_MM;
Harald Welte10b487b2008-12-27 19:53:37 +00001020 gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
Harald Welte52b1f982008-12-23 20:25:15 +00001021 gh->data[0] = cause;
1022
Harald Weltedb253af2008-12-30 17:56:55 +00001023 DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
1024
Harald Welte65e74cc2008-12-29 01:55:35 +00001025 return gsm48_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001026}
1027
1028/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
Harald Welte75a983f2008-12-27 21:34:06 +00001029int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +00001030{
Harald Welte8470bf22008-12-25 23:28:35 +00001031 struct gsm_bts *bts = lchan->ts->trx->bts;
1032 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001033 struct gsm48_hdr *gh;
1034 struct gsm48_loc_area_id *lai;
1035 u_int8_t *mid;
Holger Freyther07cc8d82008-12-29 06:23:46 +00001036 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001037
Harald Welte8470bf22008-12-25 23:28:35 +00001038 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001039
1040 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1041 gh->proto_discr = GSM48_PDISC_MM;
1042 gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
1043
1044 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
Holger Freyther17746612008-12-28 16:32:44 +00001045 gsm0408_generate_lai(lai, bts->network->country_code,
Harald Welte52b1f982008-12-23 20:25:15 +00001046 bts->network->network_code, bts->location_area_code);
1047
1048 mid = msgb_put(msg, MID_TMSI_LEN);
1049 generate_mid_from_tmsi(mid, tmsi);
1050
1051 DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
1052
Harald Weltedb253af2008-12-30 17:56:55 +00001053 ret = gsm48_sendmsg(msg);
1054
Harald Weltedb253af2008-12-30 17:56:55 +00001055 ret = gsm48_tx_mm_info(lchan);
Harald Weltedb253af2008-12-30 17:56:55 +00001056
Holger Freyther07cc8d82008-12-29 06:23:46 +00001057 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001058}
1059
Harald Weltefc977a82008-12-27 10:19:37 +00001060static char bcd2char(u_int8_t bcd)
1061{
1062 if (bcd < 0xa)
1063 return '0' + bcd;
1064 else
1065 return 'A' + (bcd - 0xa);
1066}
1067
Harald Weltebf5e8df2009-02-03 12:59:45 +00001068/* Convert Mobile Identity (10.5.1.4) to string */
Harald Weltefc977a82008-12-27 10:19:37 +00001069static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
1070{
1071 int i;
1072 u_int8_t mi_type;
1073 char *str_cur = string;
Harald Welte4ed0e922009-01-10 03:17:30 +00001074 u_int32_t tmsi;
Harald Weltefc977a82008-12-27 10:19:37 +00001075
1076 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1077
1078 switch (mi_type) {
1079 case GSM_MI_TYPE_NONE:
1080 break;
1081 case GSM_MI_TYPE_TMSI:
Harald Welte4ed0e922009-01-10 03:17:30 +00001082 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
1083 if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
1084 memcpy(&tmsi, &mi[1], 4);
1085 tmsi = ntohl(tmsi);
1086 return snprintf(string, str_len, "%u", tmsi);
Harald Weltefc977a82008-12-27 10:19:37 +00001087 }
1088 break;
1089 case GSM_MI_TYPE_IMSI:
1090 case GSM_MI_TYPE_IMEI:
1091 case GSM_MI_TYPE_IMEISV:
Harald Weltedb253af2008-12-30 17:56:55 +00001092 *str_cur++ = bcd2char(mi[0] >> 4);
1093
1094 for (i = 1; i < mi_len; i++) {
Harald Weltefc977a82008-12-27 10:19:37 +00001095 if (str_cur + 2 >= string + str_len)
1096 return str_cur - string;
1097 *str_cur++ = bcd2char(mi[i] & 0xf);
Harald Weltedb253af2008-12-30 17:56:55 +00001098 /* skip last nibble in last input byte when GSM_EVEN */
1099 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
1100 *str_cur++ = bcd2char(mi[i] >> 4);
Harald Weltefc977a82008-12-27 10:19:37 +00001101 }
1102 break;
1103 default:
1104 break;
1105 }
Harald Weltefc977a82008-12-27 10:19:37 +00001106 *str_cur++ = '\0';
Harald Weltedb253af2008-12-30 17:56:55 +00001107
Harald Weltefc977a82008-12-27 10:19:37 +00001108 return str_cur - string;
1109}
1110
Harald Weltebf5e8df2009-02-03 12:59:45 +00001111/* Transmit Chapter 9.2.10 Identity Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001112static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
1113{
1114 struct msgb *msg = gsm48_msgb_alloc();
1115 struct gsm48_hdr *gh;
Harald Weltefc977a82008-12-27 10:19:37 +00001116
Harald Welte231ad4f2008-12-27 11:15:38 +00001117 msg->lchan = lchan;
1118
1119 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1120 gh->proto_discr = GSM48_PDISC_MM;
1121 gh->msg_type = GSM48_MT_MM_ID_REQ;
1122 gh->data[0] = id_type;
1123
Harald Welte65e74cc2008-12-29 01:55:35 +00001124 return gsm48_sendmsg(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001125}
1126
1127#define MI_SIZE 32
1128
Harald Weltebf5e8df2009-02-03 12:59:45 +00001129/* Parse Chapter 9.2.11 Identity Response */
Harald Welte231ad4f2008-12-27 11:15:38 +00001130static int mm_rx_id_resp(struct msgb *msg)
1131{
1132 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte75a983f2008-12-27 21:34:06 +00001133 struct gsm_lchan *lchan = msg->lchan;
Harald Welte231ad4f2008-12-27 11:15:38 +00001134 u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
1135 char mi_string[MI_SIZE];
1136
1137 mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
Harald Welte61253062008-12-27 11:25:50 +00001138 DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
Harald Welte231ad4f2008-12-27 11:15:38 +00001139 mi_type, mi_string);
1140
Harald Welte75a983f2008-12-27 21:34:06 +00001141 switch (mi_type) {
1142 case GSM_MI_TYPE_IMSI:
1143 if (!lchan->subscr)
1144 lchan->subscr = db_create_subscriber(mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001145 if (lchan->loc_operation)
1146 lchan->loc_operation->waiting_for_imsi = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001147 break;
1148 case GSM_MI_TYPE_IMEI:
Harald Welte255539c2008-12-28 02:26:27 +00001149 case GSM_MI_TYPE_IMEISV:
Harald Welte75a983f2008-12-27 21:34:06 +00001150 /* update subscribe <-> IMEI mapping */
1151 if (lchan->subscr)
1152 db_subscriber_assoc_imei(lchan->subscr, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001153 if (lchan->loc_operation)
1154 lchan->loc_operation->waiting_for_imei = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001155 break;
1156 }
Holger Freyther73487a22008-12-31 18:53:57 +00001157
1158 /* Check if we can let the mobile station enter */
Holger Freytherd51524f2009-06-09 08:27:07 +00001159 return gsm0408_authorize(lchan, msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001160}
1161
Harald Welte255539c2008-12-28 02:26:27 +00001162
1163static void loc_upd_rej_cb(void *data)
1164{
1165 struct gsm_lchan *lchan = data;
1166
Holger Freyther73487a22008-12-31 18:53:57 +00001167 release_loc_updating_req(lchan);
Holger Freythere97f7fb2008-12-31 18:52:11 +00001168 gsm0408_loc_upd_rej(lchan, reject_cause);
Holger Freyther67b4b9a2009-01-01 03:46:11 +00001169 lchan_auto_release(lchan);
Harald Welte255539c2008-12-28 02:26:27 +00001170}
1171
Holger Freytherb7193e42008-12-29 17:44:08 +00001172static void schedule_reject(struct gsm_lchan *lchan)
1173{
Holger Freyther73487a22008-12-31 18:53:57 +00001174 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1175 lchan->loc_operation->updating_timer.data = lchan;
Harald Welteff117a82009-05-23 05:22:08 +00001176 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
Holger Freytherb7193e42008-12-29 17:44:08 +00001177}
1178
Harald Welte2a139372009-02-22 21:14:55 +00001179static const char *lupd_name(u_int8_t type)
1180{
1181 switch (type) {
1182 case GSM48_LUPD_NORMAL:
1183 return "NORMAL";
1184 case GSM48_LUPD_PERIODIC:
1185 return "PEROIDOC";
1186 case GSM48_LUPD_IMSI_ATT:
1187 return "IMSI ATTACH";
1188 default:
1189 return "UNKNOWN";
1190 }
1191}
1192
Harald Welte231ad4f2008-12-27 11:15:38 +00001193#define MI_SIZE 32
Harald Weltebf5e8df2009-02-03 12:59:45 +00001194/* Chapter 9.2.15: Receive Location Updating Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001195static int mm_rx_loc_upd_req(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001196{
Harald Welte8470bf22008-12-25 23:28:35 +00001197 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001198 struct gsm48_loc_upd_req *lu;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001199 struct gsm_subscriber *subscr = NULL;
Harald Welte255539c2008-12-28 02:26:27 +00001200 struct gsm_lchan *lchan = msg->lchan;
Harald Welte8470bf22008-12-25 23:28:35 +00001201 u_int8_t mi_type;
Harald Welte231ad4f2008-12-27 11:15:38 +00001202 char mi_string[MI_SIZE];
1203 int rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001204
Harald Welte8470bf22008-12-25 23:28:35 +00001205 lu = (struct gsm48_loc_upd_req *) gh->data;
1206
1207 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
Harald Welte52b1f982008-12-23 20:25:15 +00001208
Harald Weltefc977a82008-12-27 10:19:37 +00001209 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1210
Harald Weltea0368542009-06-27 02:58:43 +02001211 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte2a139372009-02-22 21:14:55 +00001212 lupd_name(lu->type));
Holger Freyther73487a22008-12-31 18:53:57 +00001213
Holger Freythereaf04692009-06-06 13:54:44 +00001214 /*
1215 * Pseudo Spoof detection: Just drop a second/concurrent
1216 * location updating request.
1217 */
1218 if (lchan->loc_operation) {
Harald Weltea0368542009-06-27 02:58:43 +02001219 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Holger Freythereaf04692009-06-06 13:54:44 +00001220 lchan->loc_operation);
1221 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1222 return 0;
1223 }
1224
Holger Freyther73487a22008-12-31 18:53:57 +00001225 allocate_loc_updating_req(lchan);
1226
Harald Welte52b1f982008-12-23 20:25:15 +00001227 switch (mi_type) {
1228 case GSM_MI_TYPE_IMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001229 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001230 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001231 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001232 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001233
Harald Welte52b1f982008-12-23 20:25:15 +00001234 /* look up subscriber based on IMSI */
Harald Welte75a983f2008-12-27 21:34:06 +00001235 subscr = db_create_subscriber(mi_string);
Harald Welte4b634542008-12-27 01:55:51 +00001236 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001237 case GSM_MI_TYPE_TMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001238 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001239 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001240 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001241 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001242
Harald Welte52b1f982008-12-23 20:25:15 +00001243 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welteba4cf162009-01-10 01:49:35 +00001244 subscr = subscr_get_by_tmsi(mi_string);
Harald Welte52b1f982008-12-23 20:25:15 +00001245 if (!subscr) {
Harald Welte231ad4f2008-12-27 11:15:38 +00001246 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte255539c2008-12-28 02:26:27 +00001247 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
Holger Freyther73487a22008-12-31 18:53:57 +00001248 lchan->loc_operation->waiting_for_imsi = 1;
Harald Welte52b1f982008-12-23 20:25:15 +00001249 }
1250 break;
1251 case GSM_MI_TYPE_IMEI:
1252 case GSM_MI_TYPE_IMEISV:
1253 /* no sim card... FIXME: what to do ? */
Harald Weltea0368542009-06-27 02:58:43 +02001254 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001255 break;
1256 default:
Harald Weltea0368542009-06-27 02:58:43 +02001257 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001258 break;
1259 }
1260
Harald Welte24516ea2009-07-04 10:18:00 +02001261 /* schedule the reject timer */
1262 schedule_reject(lchan);
1263
Harald Welte4bfdfe72009-06-10 23:11:52 +08001264 if (!subscr) {
Harald Weltea0368542009-06-27 02:58:43 +02001265 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001266 /* FIXME: request id? close channel? */
1267 return -EINVAL;
1268 }
1269
Harald Welte255539c2008-12-28 02:26:27 +00001270 lchan->subscr = subscr;
1271
Harald Welte24516ea2009-07-04 10:18:00 +02001272 /* check if we can let the subscriber into our network immediately
1273 * or if we need to wait for identity responses. */
Holger Freytherd51524f2009-06-09 08:27:07 +00001274 return gsm0408_authorize(lchan, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001275}
1276
Harald Welte7584aea2009-02-11 11:44:12 +00001277/* 9.1.5 Channel mode modify */
1278int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1279{
1280 struct msgb *msg = gsm48_msgb_alloc();
1281 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1282 struct gsm48_chan_mode_modify *cmm =
1283 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
Harald Welte4a543e82009-02-28 13:17:55 +00001284 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
Harald Welte7584aea2009-02-11 11:44:12 +00001285
Harald Welte4a543e82009-02-28 13:17:55 +00001286 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
Harald Welte7ccf7782009-02-17 01:43:01 +00001287
Harald Welte45b407a2009-05-23 15:51:12 +00001288 lchan->tch_mode = mode;
Harald Welte7584aea2009-02-11 11:44:12 +00001289 msg->lchan = lchan;
1290 gh->proto_discr = GSM48_PDISC_RR;
1291 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1292
1293 /* fill the channel information element, this code
1294 * should probably be shared with rsl_rx_chan_rqd() */
1295 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte02b0e092009-02-28 13:11:07 +00001296 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
Harald Welte7584aea2009-02-11 11:44:12 +00001297 cmm->chan_desc.h0.h = 0;
1298 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1299 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1300 cmm->mode = mode;
1301
1302 return gsm48_sendmsg(msg);
1303}
1304
Harald Welte4bfdfe72009-06-10 23:11:52 +08001305#if 0
1306static u_int8_t to_bcd8(u_int8_t val)
1307{
1308 return ((val / 10) << 4) | (val % 10);
1309}
1310#endif
1311
Harald Weltedb253af2008-12-30 17:56:55 +00001312/* Section 9.2.15a */
1313int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1314{
1315 struct msgb *msg = gsm48_msgb_alloc();
1316 struct gsm48_hdr *gh;
1317 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Weltedb253af2008-12-30 17:56:55 +00001318 u_int8_t *ptr8;
1319 u_int16_t *ptr16;
1320 int name_len;
Harald Weltedb253af2008-12-30 17:56:55 +00001321 int i;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001322#if 0
1323 time_t cur_t;
1324 struct tm* cur_time;
1325 int tz15min;
1326#endif
Harald Weltedb253af2008-12-30 17:56:55 +00001327
1328 msg->lchan = lchan;
1329
1330 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1331 gh->proto_discr = GSM48_PDISC_MM;
1332 gh->msg_type = GSM48_MT_MM_INFO;
1333
1334 if (net->name_long) {
1335 name_len = strlen(net->name_long);
1336 /* 10.5.3.5a */
1337 ptr8 = msgb_put(msg, 3);
1338 ptr8[0] = GSM48_IE_NAME_LONG;
1339 ptr8[1] = name_len*2 +1;
1340 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1341
1342 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1343 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001344 ptr16[i] = htons(net->name_long[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001345
1346 /* FIXME: Use Cell Broadcast, not UCS-2, since
1347 * UCS-2 is only supported by later revisions of the spec */
1348 }
1349
1350 if (net->name_short) {
1351 name_len = strlen(net->name_short);
1352 /* 10.5.3.5a */
1353 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Welte7543eb72009-07-19 17:51:36 +02001354 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Weltedb253af2008-12-30 17:56:55 +00001355 ptr8[1] = name_len*2 + 1;
1356 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1357
Harald Weltee872cb12009-01-01 00:33:37 +00001358 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
Harald Weltedb253af2008-12-30 17:56:55 +00001359 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001360 ptr16[i] = htons(net->name_short[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001361 }
1362
1363#if 0
1364 /* Section 10.5.3.9 */
1365 cur_t = time(NULL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001366 cur_time = gmtime(&cur_t);
Harald Weltedb253af2008-12-30 17:56:55 +00001367 ptr8 = msgb_put(msg, 8);
1368 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1369 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1370 ptr8[2] = to_bcd8(cur_time->tm_mon);
1371 ptr8[3] = to_bcd8(cur_time->tm_mday);
1372 ptr8[4] = to_bcd8(cur_time->tm_hour);
1373 ptr8[5] = to_bcd8(cur_time->tm_min);
1374 ptr8[6] = to_bcd8(cur_time->tm_sec);
1375 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1376 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001377 ptr8[7] = to_bcd8(tz15min);
Harald Weltedb253af2008-12-30 17:56:55 +00001378 if (tz15min < 0)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001379 ptr8[7] |= 0x80;
Harald Weltedb253af2008-12-30 17:56:55 +00001380#endif
1381
1382 return gsm48_sendmsg(msg);
1383}
1384
Harald Welte4b634542008-12-27 01:55:51 +00001385static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1386{
Harald Welte4b634542008-12-27 01:55:51 +00001387 DEBUGP(DMM, "-> CM SERVICE ACK\n");
Harald Welte65e74cc2008-12-29 01:55:35 +00001388 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
Harald Welte4b634542008-12-27 01:55:51 +00001389}
Harald Welteba4cf162009-01-10 01:49:35 +00001390
1391/* 9.2.6 CM service reject */
1392static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1393 enum gsm48_reject_value value)
1394{
1395 struct msgb *msg = gsm48_msgb_alloc();
1396 struct gsm48_hdr *gh;
1397
1398 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1399
1400 msg->lchan = lchan;
1401 use_lchan(lchan);
1402
1403 gh->proto_discr = GSM48_PDISC_MM;
1404 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1405 gh->data[0] = value;
1406 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1407
1408 return gsm48_sendmsg(msg);
1409}
1410
Harald Welte4ed0e922009-01-10 03:17:30 +00001411
1412/*
1413 * Handle CM Service Requests
1414 * a) Verify that the packet is long enough to contain the information
1415 * we require otherwsie reject with INCORRECT_MESSAGE
1416 * b) Try to parse the TMSI. If we do not have one reject
1417 * c) Check that we know the subscriber with the TMSI otherwise reject
1418 * with a HLR cause
1419 * d) Set the subscriber on the gsm_lchan and accept
1420 */
Harald Welte4b634542008-12-27 01:55:51 +00001421static int gsm48_rx_mm_serv_req(struct msgb *msg)
1422{
Harald Welteba4cf162009-01-10 01:49:35 +00001423 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001424 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001425
Harald Welteba4cf162009-01-10 01:49:35 +00001426 struct gsm_subscriber *subscr;
1427 struct gsm48_hdr *gh = msgb_l3(msg);
1428 struct gsm48_service_request *req =
1429 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001430 /* unfortunately in Phase1 the classmar2 length is variable */
1431 u_int8_t classmark2_len = gh->data[1];
1432 u_int8_t *classmark2 = gh->data+2;
1433 u_int8_t mi_len = *(classmark2 + classmark2_len);
1434 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001435
Harald Weltec9e02182009-05-01 19:07:53 +00001436 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001437 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001438 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001439 return gsm48_tx_mm_serv_rej(msg->lchan,
1440 GSM48_REJECT_INCORRECT_MESSAGE);
1441 }
1442
1443 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001444 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001445 return gsm48_tx_mm_serv_rej(msg->lchan,
1446 GSM48_REJECT_INCORRECT_MESSAGE);
1447 }
1448
Harald Weltec9e02182009-05-01 19:07:53 +00001449 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001450 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001451 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001452 return gsm48_tx_mm_serv_rej(msg->lchan,
1453 GSM48_REJECT_INCORRECT_MESSAGE);
1454 }
1455
Harald Weltec9e02182009-05-01 19:07:53 +00001456 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001457 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001458 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001459
Holger Freythereb443982009-06-04 13:58:42 +00001460 subscr = subscr_get_by_tmsi(mi_string);
1461
Harald Welte2a139372009-02-22 21:14:55 +00001462 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001463 if (!subscr)
1464 return gsm48_tx_mm_serv_rej(msg->lchan,
1465 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1466
1467 if (!msg->lchan->subscr)
1468 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001469 else if (msg->lchan->subscr != subscr) {
1470 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1471 subscr_put(subscr);
1472 }
1473
Harald Weltec2e302d2009-07-05 14:08:13 +02001474 subscr->equipment.classmark2_len = classmark2_len;
1475 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1476 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001477
Harald Welte4b634542008-12-27 01:55:51 +00001478 return gsm48_tx_mm_serv_ack(msg->lchan);
1479}
1480
Harald Welte2a139372009-02-22 21:14:55 +00001481static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1482{
1483 struct gsm48_hdr *gh = msgb_l3(msg);
1484 struct gsm48_imsi_detach_ind *idi =
1485 (struct gsm48_imsi_detach_ind *) gh->data;
1486 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1487 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001488 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001489
1490 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1491 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1492 mi_type, mi_string);
1493
1494 switch (mi_type) {
1495 case GSM_MI_TYPE_TMSI:
1496 subscr = subscr_get_by_tmsi(mi_string);
1497 break;
1498 case GSM_MI_TYPE_IMSI:
1499 subscr = subscr_get_by_imsi(mi_string);
1500 break;
1501 case GSM_MI_TYPE_IMEI:
1502 case GSM_MI_TYPE_IMEISV:
1503 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001504 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001505 break;
1506 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001507 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001508 break;
1509 }
1510
Holger Freyther4a49e772009-04-12 05:37:29 +00001511 if (subscr) {
1512 subscr_update(subscr, msg->trx->bts,
1513 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001514 DEBUGP(DMM, "Subscriber: %s\n",
1515 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001516 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001517 } else
Harald Welte2a139372009-02-22 21:14:55 +00001518 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1519
Harald Welte2a139372009-02-22 21:14:55 +00001520 return 0;
1521}
1522
Harald Welted2a7f5a2009-06-05 20:08:20 +00001523static int gsm48_rx_mm_status(struct msgb *msg)
1524{
1525 struct gsm48_hdr *gh = msgb_l3(msg);
1526
1527 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1528
1529 return 0;
1530}
1531
Harald Weltebf5e8df2009-02-03 12:59:45 +00001532/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001533static int gsm0408_rcv_mm(struct msgb *msg)
1534{
1535 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001536 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001537
1538 switch (gh->msg_type & 0xbf) {
1539 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001540 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001541 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001542 break;
1543 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001544 rc = mm_rx_id_resp(msg);
1545 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001546 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001547 rc = gsm48_rx_mm_serv_req(msg);
1548 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001549 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001550 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001551 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001552 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001553 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1554 msg->lchan->subscr ?
1555 msg->lchan->subscr->imsi :
1556 "unknown subscriber");
1557 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001558 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001559 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1560 break;
1561 case GSM48_MT_MM_CM_REEST_REQ:
1562 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1563 break;
1564 case GSM48_MT_MM_AUTH_RESP:
1565 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001566 break;
1567 default:
1568 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1569 gh->msg_type);
1570 break;
1571 }
1572
1573 return rc;
1574}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001575
Harald Welte2d35ae62009-02-06 12:02:13 +00001576/* Receive a PAGING RESPONSE message from the MS */
1577static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1578{
1579 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001580 u_int8_t *classmark2_lv = gh->data + 1;
1581 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1582 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001583 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001584 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001585 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001586 int rc = 0;
1587
Harald Welte61548982009-02-22 21:26:29 +00001588 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001589 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1590 mi_type, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001591 switch (mi_type) {
1592 case GSM_MI_TYPE_TMSI:
1593 subscr = subscr_get_by_tmsi(mi_string);
1594 break;
1595 case GSM_MI_TYPE_IMSI:
1596 subscr = subscr_get_by_imsi(mi_string);
1597 break;
1598 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001599
1600 if (!subscr) {
1601 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001602 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001603 return -EINVAL;
1604 }
1605 DEBUGP(DRR, "<- Channel was requested by %s\n",
1606 subscr->name ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001607
Harald Weltec2e302d2009-07-05 14:08:13 +02001608 subscr->equipment.classmark2_len = *classmark2_lv;
1609 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1610 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001611
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001612 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001613 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001614 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001615 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1616 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001617 return -EINVAL;
1618 } else {
1619 DEBUGP(DRR, "<- Channel already owned by us\n");
1620 subscr_put(subscr);
1621 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001622 }
1623
Harald Welte595ad7b2009-02-16 22:05:44 +00001624 sig_data.subscr = subscr;
1625 sig_data.bts = msg->lchan->ts->trx->bts;
1626 sig_data.lchan = msg->lchan;
1627
1628 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001629
1630 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001631 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001632
Harald Welte7584aea2009-02-11 11:44:12 +00001633 /* FIXME: somehow signal the completion of the PAGING to
1634 * the entity that requested the paging */
1635
Harald Welte2d35ae62009-02-06 12:02:13 +00001636 return rc;
1637}
1638
Harald Weltef7c43522009-06-09 20:24:21 +00001639static int gsm48_rx_rr_classmark(struct msgb *msg)
1640{
1641 struct gsm48_hdr *gh = msgb_l3(msg);
1642 struct gsm_subscriber *subscr = msg->lchan->subscr;
1643 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1644 u_int8_t cm2_len, cm3_len = 0;
1645 u_int8_t *cm2, *cm3 = NULL;
1646
1647 DEBUGP(DRR, "CLASSMARK CHANGE ");
1648
1649 /* classmark 2 */
1650 cm2_len = gh->data[0];
1651 cm2 = &gh->data[1];
1652 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1653
1654 if (payload_len > cm2_len + 1) {
1655 /* we must have a classmark3 */
1656 if (gh->data[cm2_len+1] != 0x20) {
1657 DEBUGPC(DRR, "ERR CM3 TAG\n");
1658 return -EINVAL;
1659 }
1660 if (cm2_len > 3) {
1661 DEBUGPC(DRR, "CM2 too long!\n");
1662 return -EINVAL;
1663 }
1664
1665 cm3_len = gh->data[cm2_len+2];
1666 cm3 = &gh->data[cm2_len+3];
1667 if (cm3_len > 14) {
1668 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1669 return -EINVAL;
1670 }
1671 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1672 }
1673 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001674 subscr->equipment.classmark2_len = cm2_len;
1675 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001676 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001677 subscr->equipment.classmark3_len = cm3_len;
1678 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001679 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001680 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001681 }
1682
Harald Weltef7c43522009-06-09 20:24:21 +00001683 return 0;
1684}
1685
Harald Weltecf5b3592009-05-01 18:28:42 +00001686static int gsm48_rx_rr_status(struct msgb *msg)
1687{
1688 struct gsm48_hdr *gh = msgb_l3(msg);
1689
1690 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1691 rr_cause_name(gh->data[0]));
1692
1693 return 0;
1694}
1695
Harald Weltef7c43522009-06-09 20:24:21 +00001696static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1697{
1698 struct gsm48_hdr *gh = msgb_l3(msg);
1699 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1700 static struct gsm_meas_rep meas_rep;
1701
Harald Welte10d0e672009-06-27 02:53:10 +02001702 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001703 parse_meas_rep(&meas_rep, gh->data, payload_len);
1704 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001705 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001706 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001707 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001708 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001709 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001710 else
Harald Welte10d0e672009-06-27 02:53:10 +02001711 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001712 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1713 meas_rep.rxqual_sub);
1714
Harald Welte10d0e672009-06-27 02:53:10 +02001715 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001716
1717 /* FIXME: put the results somwhere */
1718
1719 return 0;
1720}
1721
Harald Weltebf5e8df2009-02-03 12:59:45 +00001722/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001723static int gsm0408_rcv_rr(struct msgb *msg)
1724{
1725 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001726 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001727
1728 switch (gh->msg_type) {
1729 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001730 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001731 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001732 case GSM48_MT_RR_GPRS_SUSP_REQ:
1733 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1734 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001735 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001736 rc = gsm48_rr_rx_pag_resp(msg);
1737 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001738 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1739 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte2c38aa82009-02-18 03:44:24 +00001740 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001741 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001742 case GSM48_MT_RR_STATUS:
1743 rc = gsm48_rx_rr_status(msg);
1744 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001745 case GSM48_MT_RR_MEAS_REP:
1746 rc = gsm48_rx_rr_meas_rep(msg);
1747 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001748 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001749 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001750 gh->msg_type);
1751 break;
1752 }
1753
Harald Welte2d35ae62009-02-06 12:02:13 +00001754 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001755}
1756
Holger Freythere64a7a32009-02-06 21:55:37 +00001757/* 7.1.7 and 9.1.7 Channel release*/
1758int gsm48_send_rr_release(struct gsm_lchan *lchan)
1759{
1760 struct msgb *msg = gsm48_msgb_alloc();
1761 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1762 u_int8_t *cause;
1763
1764 msg->lchan = lchan;
1765 gh->proto_discr = GSM48_PDISC_RR;
1766 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1767
1768 cause = msgb_put(msg, 1);
1769 cause[0] = GSM48_RR_CAUSE_NORMAL;
1770
1771 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1772 lchan->nr, lchan->type);
1773
Harald Welteae0f2362009-07-19 18:36:49 +02001774 /* Send actual release request to MS */
1775 gsm48_sendmsg(msg);
1776
1777 /* Deactivate the SACCH on the BTS side */
1778 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001779}
1780
Harald Welte4bc90a12008-12-27 16:32:52 +00001781/* Call Control */
1782
Harald Welte7584aea2009-02-11 11:44:12 +00001783/* The entire call control code is written in accordance with Figure 7.10c
1784 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1785 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1786 * it for voice */
1787
Harald Welte4bfdfe72009-06-10 23:11:52 +08001788static void new_cc_state(struct gsm_trans *trans, int state)
1789{
1790 if (state > 31 || state < 0)
1791 return;
1792
1793 DEBUGP(DCC, "new state %s -> %s\n",
Harald Welteaa0b29c2009-07-23 18:56:43 +02001794 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001795
Harald Welteaa0b29c2009-07-23 18:56:43 +02001796 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001797}
1798
1799static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001800{
1801 struct msgb *msg = gsm48_msgb_alloc();
1802 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1803 u_int8_t *cause, *call_state;
1804
Harald Welte4bfdfe72009-06-10 23:11:52 +08001805 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
1806 msg->lchan = trans->lchan;
Harald Welte4bc90a12008-12-27 16:32:52 +00001807 gh->msg_type = GSM48_MT_CC_STATUS;
1808
1809 cause = msgb_put(msg, 3);
1810 cause[0] = 2;
1811 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1812 cause[2] = 0x80 | 30; /* response to status inquiry */
1813
1814 call_state = msgb_put(msg, 1);
1815 call_state[0] = 0xc0 | 0x00;
1816
Harald Welte65e74cc2008-12-29 01:55:35 +00001817 return gsm48_sendmsg(msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00001818}
1819
Harald Welte6f4b7532008-12-29 00:39:37 +00001820static int gsm48_tx_simple(struct gsm_lchan *lchan,
1821 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001822{
1823 struct msgb *msg = gsm48_msgb_alloc();
1824 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1825
1826 msg->lchan = lchan;
1827
Harald Welte6f4b7532008-12-29 00:39:37 +00001828 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001829 gh->msg_type = msg_type;
1830
Harald Welte65e74cc2008-12-29 01:55:35 +00001831 return gsm48_sendmsg(msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00001832}
1833
Harald Welte4bfdfe72009-06-10 23:11:52 +08001834static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1835{
Harald Welteaa0b29c2009-07-23 18:56:43 +02001836 if (bsc_timer_pending(&trans->cc.timer)) {
1837 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1838 bsc_del_timer(&trans->cc.timer);
1839 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001840 }
1841}
1842
1843static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1844 int msg_type, struct gsm_mncc *mncc)
1845{
1846 struct msgb *msg;
1847
1848 if (trans)
1849 if (trans->lchan)
1850 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
1851 "Sending '%s' to MNCC.\n",
1852 trans->lchan->ts->trx->bts->nr,
1853 trans->lchan->ts->trx->nr,
1854 trans->lchan->ts->nr, trans->transaction_id,
1855 (trans->subscr)?(trans->subscr->extension):"-",
1856 get_mncc_name(msg_type));
1857 else
1858 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1859 "Sending '%s' to MNCC.\n",
1860 (trans->subscr)?(trans->subscr->extension):"-",
1861 get_mncc_name(msg_type));
1862 else
1863 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1864 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1865
1866 mncc->msg_type = msg_type;
1867
Harald Welte966636f2009-06-26 19:39:35 +02001868 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001869 if (!msg)
1870 return -ENOMEM;
1871 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1872 msgb_enqueue(&net->upqueue, msg);
1873
1874 return 0;
1875}
1876
1877int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1878 u_int32_t callref, int location, int value)
1879{
1880 struct gsm_mncc rel;
1881
Harald Welte92f70c52009-06-12 01:54:08 +08001882 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001883 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001884 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001885 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1886}
1887
Harald Welteaa0b29c2009-07-23 18:56:43 +02001888/* Call Control Specific transaction release.
1889 * gets called by trans_free, DO NOT CALL YOURSELF! */
1890void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001891{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001892 gsm48_stop_cc_timer(trans);
1893
1894 /* send release to L4, if callref still exists */
1895 if (trans->callref) {
1896 /* Ressource unavailable */
Harald Welteb3c3fae2009-07-23 19:06:52 +02001897 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001898 GSM48_CAUSE_LOC_PRN_S_LU,
1899 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001900 }
Harald Welteaa0b29c2009-07-23 18:56:43 +02001901 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001902 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Welteaa0b29c2009-07-23 18:56:43 +02001903 if (trans->lchan)
1904 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001905}
1906
1907static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1908
Harald Welte09e38af2009-02-16 22:52:23 +00001909/* call-back from paging the B-end of the connection */
1910static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001911 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001912{
Harald Welte7ccf7782009-02-17 01:43:01 +00001913 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001914 struct gsm_subscriber *subscr = param;
1915 struct gsm_trans *transt, *tmp;
1916 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001917
Harald Welte09e38af2009-02-16 22:52:23 +00001918 if (hooknum != GSM_HOOK_RR_PAGING)
1919 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001920
1921 if (!subscr)
1922 return -EINVAL;
1923 net = subscr->net;
1924 if (!net) {
1925 DEBUGP(DCC, "Error Network not set!\n");
1926 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00001927 }
Harald Welte7584aea2009-02-11 11:44:12 +00001928
Harald Welte4bfdfe72009-06-10 23:11:52 +08001929 /* check all tranactions (without lchan) for subscriber */
1930 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1931 if (transt->subscr != subscr || transt->lchan)
1932 continue;
1933 switch (event) {
1934 case GSM_PAGING_SUCCEEDED:
1935 if (!lchan) // paranoid
1936 break;
1937 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1938 subscr->extension);
1939 /* Assign lchan */
1940 if (!transt->lchan) {
1941 transt->lchan = lchan;
1942 use_lchan(lchan);
1943 }
1944 /* send SETUP request to called party */
Harald Welteaa0b29c2009-07-23 18:56:43 +02001945 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001946 if (is_ipaccess_bts(lchan->ts->trx->bts))
1947 rsl_ipacc_bind(lchan);
1948 break;
1949 case GSM_PAGING_EXPIRED:
1950 DEBUGP(DCC, "Paging subscr %s expired!\n",
1951 subscr->extension);
1952 /* Temporarily out of order */
Harald Welteb3c3fae2009-07-23 19:06:52 +02001953 mncc_release_ind(transt->subscr->net, transt,
1954 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001955 GSM48_CAUSE_LOC_PRN_S_LU,
1956 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001957 transt->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02001958 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001959 break;
1960 }
1961 }
Harald Welte09e38af2009-02-16 22:52:23 +00001962 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00001963}
Harald Welte7584aea2009-02-11 11:44:12 +00001964
Harald Welte49f48b82009-02-17 15:29:33 +00001965/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00001966static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00001967{
Harald Welte11fa29c2009-02-19 17:24:39 +00001968 struct gsm_bts *bts = lchan->ts->trx->bts;
1969 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00001970 struct gsm_bts_trx_ts *ts;
1971
Harald Welte11fa29c2009-02-19 17:24:39 +00001972 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
1973 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
1974 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
1975
1976 if (bts->type != remote_bts->type) {
1977 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
1978 return -EINVAL;
1979 }
Harald Welte49f48b82009-02-17 15:29:33 +00001980
Harald Welte11fa29c2009-02-19 17:24:39 +00001981 switch (bts->type) {
1982 case GSM_BTS_TYPE_NANOBTS_900:
1983 case GSM_BTS_TYPE_NANOBTS_1800:
1984 ts = remote_lchan->ts;
Harald Welte20855542009-07-12 09:50:35 +02001985 rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
1986 ts->abis_ip.bound_port,
1987 lchan->ts->abis_ip.conn_id,
1988 ts->abis_ip.rtp_payload2);
Harald Welte11fa29c2009-02-19 17:24:39 +00001989
1990 ts = lchan->ts;
Harald Welte20855542009-07-12 09:50:35 +02001991 rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
1992 ts->abis_ip.bound_port,
1993 remote_lchan->ts->abis_ip.conn_id,
1994 ts->abis_ip.rtp_payload2);
Harald Welte11fa29c2009-02-19 17:24:39 +00001995 break;
1996 case GSM_BTS_TYPE_BS11:
1997 trau_mux_map_lchan(lchan, remote_lchan);
1998 break;
1999 default:
2000 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
2001 break;
2002 }
Harald Welte49f48b82009-02-17 15:29:33 +00002003
2004 return 0;
2005}
2006
Harald Welte4bfdfe72009-06-10 23:11:52 +08002007/* bridge channels of two transactions */
2008static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002009{
Harald Welteaa0b29c2009-07-23 18:56:43 +02002010 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2011 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002012
Harald Welte4bfdfe72009-06-10 23:11:52 +08002013 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002014 return -EIO;
2015
Harald Welte4bfdfe72009-06-10 23:11:52 +08002016 if (!trans1->lchan || !trans2->lchan)
2017 return -EIO;
2018
2019 /* through-connect channel */
2020 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002021}
2022
Harald Welte4bfdfe72009-06-10 23:11:52 +08002023/* enable receive of channels to upqueue */
2024static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2025{
2026 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002027
Harald Welte4bfdfe72009-06-10 23:11:52 +08002028 /* Find callref */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002029 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002030 if (!trans)
2031 return -EIO;
2032 if (!trans->lchan)
2033 return 0;
2034
2035 // todo IPACCESS
2036 if (enable)
2037 return trau_recv_lchan(trans->lchan, data->callref);
2038 return trau_mux_unmap(NULL, data->callref);
2039}
2040
2041/* send a frame to channel */
2042static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2043{
2044 struct gsm_trans *trans;
2045
2046 /* Find callref */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002047 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002048 if (!trans)
2049 return -EIO;
2050 if (!trans->lchan)
2051 return 0;
2052 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2053 trans->lchan->type != GSM_LCHAN_TCH_H)
2054 return 0;
2055
2056 // todo IPACCESS
2057 return trau_send_lchan(trans->lchan,
2058 (struct decoded_trau_frame *)frame->data);
2059}
2060
2061
2062static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2063{
2064 DEBUGP(DCC, "-> STATUS ENQ\n");
2065 return gsm48_cc_tx_status(trans, msg);
2066}
2067
2068static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2069static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2070
2071static void gsm48_cc_timeout(void *arg)
2072{
2073 struct gsm_trans *trans = arg;
2074 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002075 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2076 int mo_location = GSM48_CAUSE_LOC_USER;
2077 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2078 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002079 struct gsm_mncc mo_rel, l4_rel;
2080
2081 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2082 mo_rel.callref = trans->callref;
2083 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2084 l4_rel.callref = trans->callref;
2085
Harald Welteaa0b29c2009-07-23 18:56:43 +02002086 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002087 case 0x303:
2088 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002089 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002090 break;
2091 case 0x310:
2092 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002093 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002094 break;
2095 case 0x313:
2096 disconnect = 1;
2097 /* unknown, did not find it in the specs */
2098 break;
2099 case 0x301:
2100 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002101 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002102 break;
2103 case 0x308:
Harald Welteaa0b29c2009-07-23 18:56:43 +02002104 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002105 /* restart T308 a second time */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002106 gsm48_cc_tx_release(trans, &trans->cc.msg);
2107 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002108 break; /* stay in release state */
2109 }
Harald Welteaa0b29c2009-07-23 18:56:43 +02002110 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002111 return;
2112// release = 1;
2113// l4_cause = 14;
2114// break;
2115 case 0x306:
2116 release = 1;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002117 mo_cause = trans->cc.msg.cause.value;
2118 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002119 break;
2120 case 0x323:
2121 disconnect = 1;
2122 break;
2123 default:
2124 release = 1;
2125 }
2126
2127 if (release && trans->callref) {
2128 /* process release towards layer 4 */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002129 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002130 l4_location, l4_cause);
2131 trans->callref = 0;
2132 }
2133
2134 if (disconnect && trans->callref) {
2135 /* process disconnect towards layer 4 */
2136 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welteb3c3fae2009-07-23 19:06:52 +02002137 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002138 }
2139
2140 /* process disconnect towards mobile station */
2141 if (disconnect || release) {
2142 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Welteaa0b29c2009-07-23 18:56:43 +02002143 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2144 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2145 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002146 mo_rel.cause.diag_len = 3;
2147
2148 if (disconnect)
2149 gsm48_cc_tx_disconnect(trans, &mo_rel);
2150 if (release)
2151 gsm48_cc_tx_release(trans, &mo_rel);
2152 }
2153
2154}
2155
2156static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2157 int sec, int micro)
2158{
2159 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Welteaa0b29c2009-07-23 18:56:43 +02002160 trans->cc.timer.cb = gsm48_cc_timeout;
2161 trans->cc.timer.data = trans;
2162 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2163 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002164}
2165
2166static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2167{
2168 struct gsm48_hdr *gh = msgb_l3(msg);
2169 u_int8_t msg_type = gh->msg_type & 0xbf;
2170 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2171 struct tlv_parsed tp;
2172 struct gsm_mncc setup;
2173
2174 memset(&setup, 0, sizeof(struct gsm_mncc));
2175 setup.callref = trans->callref;
2176 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2177 /* emergency setup is identified by msg_type */
2178 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2179 setup.emergency = 1;
2180
2181 /* use subscriber as calling party number */
2182 if (trans->subscr) {
2183 setup.fields |= MNCC_F_CALLING;
2184 strncpy(setup.calling.number, trans->subscr->extension,
2185 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002186 strncpy(setup.imsi, trans->subscr->imsi,
2187 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002188 }
2189 /* bearer capability */
2190 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2191 setup.fields |= MNCC_F_BEARER_CAP;
2192 decode_bearer_cap(&setup.bearer_cap,
2193 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2194 }
2195 /* facility */
2196 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2197 setup.fields |= MNCC_F_FACILITY;
2198 decode_facility(&setup.facility,
2199 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2200 }
2201 /* called party bcd number */
2202 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2203 setup.fields |= MNCC_F_CALLED;
2204 decode_called(&setup.called,
2205 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2206 }
2207 /* user-user */
2208 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2209 setup.fields |= MNCC_F_USERUSER;
2210 decode_useruser(&setup.useruser,
2211 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2212 }
2213 /* ss-version */
2214 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2215 setup.fields |= MNCC_F_SSVERSION;
2216 decode_ssversion(&setup.ssversion,
2217 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2218 }
2219 /* CLIR suppression */
2220 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2221 setup.clir.sup = 1;
2222 /* CLIR invocation */
2223 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2224 setup.clir.inv = 1;
2225 /* cc cap */
2226 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2227 setup.fields |= MNCC_F_CCCAP;
2228 decode_cccap(&setup.cccap,
2229 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2230 }
2231
2232 if (is_ipaccess_bts(msg->trx->bts))
2233 rsl_ipacc_bind(msg->lchan);
2234
2235 new_cc_state(trans, GSM_CSTATE_INITIATED);
2236
2237 /* indicate setup to MNCC */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002238 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002239
2240 return 0;
2241}
2242
2243static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002244{
2245 struct msgb *msg = gsm48_msgb_alloc();
2246 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002247 struct gsm_mncc *setup = arg;
2248 struct gsm_trans *transt;
2249 u_int16_t trans_id_mask = 0;
2250 int rc, i;
Harald Welte65e74cc2008-12-29 01:55:35 +00002251
Harald Welte7ccf7782009-02-17 01:43:01 +00002252 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002253
Harald Welte4bfdfe72009-06-10 23:11:52 +08002254 /* transaction id must not be assigned */
2255 if (trans->transaction_id != 0xff) { /* unasssigned */
2256 DEBUGP(DCC, "TX Setup with assigned transaction. "
2257 "This is not allowed!\n");
2258 /* Temporarily out of order */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002259 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002260 GSM48_CAUSE_LOC_PRN_S_LU,
2261 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002262 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002263 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002264 return rc;
2265 }
2266
2267 /* Get free transaction_id */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002268 llist_for_each_entry(transt, &trans->subscr->net->trans_list, entry) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002269 /* Transaction of our lchan? */
2270 if (transt->lchan == trans->lchan &&
2271 transt->transaction_id != 0xff)
2272 trans_id_mask |= (1 << (transt->transaction_id >> 4));
2273 }
2274 /* Assign free transaction ID */
2275 if ((trans_id_mask & 0x007f) == 0x7f) {
2276 /* no free transaction ID */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002277 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002278 GSM48_CAUSE_LOC_PRN_S_LU,
2279 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002280 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002281 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002282 return rc;
2283 }
2284 for (i = 0; i < 7; i++) {
2285 if ((trans_id_mask & (1 << i)) == 0) {
2286 trans->transaction_id = i << 4; /* flag = 0 */
2287 break;
2288 }
2289 }
Harald Welte49f48b82009-02-17 15:29:33 +00002290
Harald Welte4bfdfe72009-06-10 23:11:52 +08002291 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2292 msg->lchan = trans->lchan;
Harald Welte65e74cc2008-12-29 01:55:35 +00002293 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002294
Harald Welte4bfdfe72009-06-10 23:11:52 +08002295 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002296
Harald Welte4bfdfe72009-06-10 23:11:52 +08002297 /* bearer capability */
2298 if (setup->fields & MNCC_F_BEARER_CAP)
2299 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2300 /* facility */
2301 if (setup->fields & MNCC_F_FACILITY)
2302 encode_facility(msg, 0, &setup->facility);
2303 /* progress */
2304 if (setup->fields & MNCC_F_PROGRESS)
2305 encode_progress(msg, 0, &setup->progress);
2306 /* calling party BCD number */
2307 if (setup->fields & MNCC_F_CALLING)
2308 encode_calling(msg, &setup->calling);
2309 /* called party BCD number */
2310 if (setup->fields & MNCC_F_CALLED)
2311 encode_called(msg, &setup->called);
2312 /* user-user */
2313 if (setup->fields & MNCC_F_USERUSER)
2314 encode_useruser(msg, 0, &setup->useruser);
2315 /* redirecting party BCD number */
2316 if (setup->fields & MNCC_F_REDIRECTING)
2317 encode_redirecting(msg, &setup->redirecting);
2318 /* signal */
2319 if (setup->fields & MNCC_F_SIGNAL)
2320 encode_signal(msg, setup->signal);
2321
2322 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002323
2324 return gsm48_sendmsg(msg);
2325}
2326
Harald Welte4bfdfe72009-06-10 23:11:52 +08002327static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2328{
2329 struct gsm48_hdr *gh = msgb_l3(msg);
2330 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2331 struct tlv_parsed tp;
2332 struct gsm_mncc call_conf;
2333
2334 gsm48_stop_cc_timer(trans);
2335 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2336
2337 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2338 call_conf.callref = trans->callref;
2339 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2340#if 0
2341 /* repeat */
2342 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2343 call_conf.repeat = 1;
2344 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2345 call_conf.repeat = 2;
2346#endif
2347 /* bearer capability */
2348 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2349 call_conf.fields |= MNCC_F_BEARER_CAP;
2350 decode_bearer_cap(&call_conf.bearer_cap,
2351 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2352 }
2353 /* cause */
2354 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2355 call_conf.fields |= MNCC_F_CAUSE;
2356 decode_cause(&call_conf.cause,
2357 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2358 }
2359 /* cc cap */
2360 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2361 call_conf.fields |= MNCC_F_CCCAP;
2362 decode_cccap(&call_conf.cccap,
2363 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2364 }
2365
2366 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2367
Harald Welteb3c3fae2009-07-23 19:06:52 +02002368 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2369 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002370}
2371
2372static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2373{
2374 struct gsm_mncc *proceeding = arg;
2375 struct msgb *msg = gsm48_msgb_alloc();
2376 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2377
2378 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2379 msg->lchan = trans->lchan;
2380 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2381
2382 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2383
2384 /* bearer capability */
2385 if (proceeding->fields & MNCC_F_BEARER_CAP)
2386 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2387 /* facility */
2388 if (proceeding->fields & MNCC_F_FACILITY)
2389 encode_facility(msg, 0, &proceeding->facility);
2390 /* progress */
2391 if (proceeding->fields & MNCC_F_PROGRESS)
2392 encode_progress(msg, 0, &proceeding->progress);
2393
2394 return gsm48_sendmsg(msg);
2395}
2396
2397static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2398{
2399 struct gsm48_hdr *gh = msgb_l3(msg);
2400 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2401 struct tlv_parsed tp;
2402 struct gsm_mncc alerting;
2403
2404 gsm48_stop_cc_timer(trans);
2405 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2406
2407 memset(&alerting, 0, sizeof(struct gsm_mncc));
2408 alerting.callref = trans->callref;
2409 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2410 /* facility */
2411 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2412 alerting.fields |= MNCC_F_FACILITY;
2413 decode_facility(&alerting.facility,
2414 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2415 }
2416
2417 /* progress */
2418 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2419 alerting.fields |= MNCC_F_PROGRESS;
2420 decode_progress(&alerting.progress,
2421 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2422 }
2423 /* ss-version */
2424 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2425 alerting.fields |= MNCC_F_SSVERSION;
2426 decode_ssversion(&alerting.ssversion,
2427 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2428 }
2429
2430 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2431
Harald Welteb3c3fae2009-07-23 19:06:52 +02002432 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2433 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002434}
2435
2436static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2437{
2438 struct gsm_mncc *alerting = arg;
2439 struct msgb *msg = gsm48_msgb_alloc();
2440 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2441
2442 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2443 msg->lchan = trans->lchan;
2444 gh->msg_type = GSM48_MT_CC_ALERTING;
2445
2446 /* facility */
2447 if (alerting->fields & MNCC_F_FACILITY)
2448 encode_facility(msg, 0, &alerting->facility);
2449 /* progress */
2450 if (alerting->fields & MNCC_F_PROGRESS)
2451 encode_progress(msg, 0, &alerting->progress);
2452 /* user-user */
2453 if (alerting->fields & MNCC_F_USERUSER)
2454 encode_useruser(msg, 0, &alerting->useruser);
2455
2456 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2457
2458 return gsm48_sendmsg(msg);
2459}
2460
2461static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2462{
2463 struct gsm_mncc *progress = arg;
2464 struct msgb *msg = gsm48_msgb_alloc();
2465 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2466
2467 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2468 msg->lchan = trans->lchan;
2469 gh->msg_type = GSM48_MT_CC_PROGRESS;
2470
2471 /* progress */
2472 encode_progress(msg, 1, &progress->progress);
2473 /* user-user */
2474 if (progress->fields & MNCC_F_USERUSER)
2475 encode_useruser(msg, 0, &progress->useruser);
2476
2477 return gsm48_sendmsg(msg);
2478}
2479
2480static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2481{
2482 struct gsm_mncc *connect = arg;
2483 struct msgb *msg = gsm48_msgb_alloc();
2484 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2485
2486 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2487 msg->lchan = trans->lchan;
2488 gh->msg_type = GSM48_MT_CC_CONNECT;
2489
2490 gsm48_stop_cc_timer(trans);
2491 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2492
2493 /* facility */
2494 if (connect->fields & MNCC_F_FACILITY)
2495 encode_facility(msg, 0, &connect->facility);
2496 /* progress */
2497 if (connect->fields & MNCC_F_PROGRESS)
2498 encode_progress(msg, 0, &connect->progress);
2499 /* connected number */
2500 if (connect->fields & MNCC_F_CONNECTED)
2501 encode_connected(msg, &connect->connected);
2502 /* user-user */
2503 if (connect->fields & MNCC_F_USERUSER)
2504 encode_useruser(msg, 0, &connect->useruser);
2505
2506 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2507
2508 return gsm48_sendmsg(msg);
2509}
2510
2511static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2512{
2513 struct gsm48_hdr *gh = msgb_l3(msg);
2514 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2515 struct tlv_parsed tp;
2516 struct gsm_mncc connect;
2517
2518 gsm48_stop_cc_timer(trans);
2519
2520 memset(&connect, 0, sizeof(struct gsm_mncc));
2521 connect.callref = trans->callref;
2522 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2523 /* use subscriber as connected party number */
2524 if (trans->subscr) {
2525 connect.fields |= MNCC_F_CONNECTED;
2526 strncpy(connect.connected.number, trans->subscr->extension,
2527 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002528 strncpy(connect.imsi, trans->subscr->imsi,
2529 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002530 }
2531 /* facility */
2532 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2533 connect.fields |= MNCC_F_FACILITY;
2534 decode_facility(&connect.facility,
2535 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2536 }
2537 /* user-user */
2538 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2539 connect.fields |= MNCC_F_USERUSER;
2540 decode_useruser(&connect.useruser,
2541 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2542 }
2543 /* ss-version */
2544 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2545 connect.fields |= MNCC_F_SSVERSION;
2546 decode_ssversion(&connect.ssversion,
2547 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2548 }
2549
2550 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2551
Harald Welteb3c3fae2009-07-23 19:06:52 +02002552 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002553}
2554
2555
2556static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2557{
2558 struct gsm_mncc connect_ack;
2559
2560 gsm48_stop_cc_timer(trans);
2561
2562 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2563
2564 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2565 connect_ack.callref = trans->callref;
Harald Welteb3c3fae2009-07-23 19:06:52 +02002566 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002567 &connect_ack);
2568}
2569
2570static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2571{
2572 struct msgb *msg = gsm48_msgb_alloc();
2573 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2574
2575 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2576 msg->lchan = trans->lchan;
2577 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2578
2579 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2580
2581 return gsm48_sendmsg(msg);
2582}
2583
2584static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2585{
2586 struct gsm48_hdr *gh = msgb_l3(msg);
2587 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2588 struct tlv_parsed tp;
2589 struct gsm_mncc disc;
2590
2591 gsm48_stop_cc_timer(trans);
2592
2593 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2594
2595 memset(&disc, 0, sizeof(struct gsm_mncc));
2596 disc.callref = trans->callref;
2597 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2598 /* cause */
2599 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2600 disc.fields |= MNCC_F_CAUSE;
2601 decode_cause(&disc.cause,
2602 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2603 }
2604 /* facility */
2605 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2606 disc.fields |= MNCC_F_FACILITY;
2607 decode_facility(&disc.facility,
2608 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2609 }
2610 /* user-user */
2611 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2612 disc.fields |= MNCC_F_USERUSER;
2613 decode_useruser(&disc.useruser,
2614 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2615 }
2616 /* ss-version */
2617 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2618 disc.fields |= MNCC_F_SSVERSION;
2619 decode_ssversion(&disc.ssversion,
2620 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2621 }
2622
Harald Welteb3c3fae2009-07-23 19:06:52 +02002623 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002624
2625}
2626
Harald Weltec66b71c2009-06-11 14:23:20 +08002627static struct gsm_mncc_cause default_cause = {
2628 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2629 .coding = 0,
2630 .rec = 0,
2631 .rec_val = 0,
2632 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2633 .diag_len = 0,
2634 .diag = { 0 },
2635};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002636
2637static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2638{
2639 struct gsm_mncc *disc = arg;
2640 struct msgb *msg = gsm48_msgb_alloc();
2641 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2642
2643 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2644 msg->lchan = trans->lchan;
2645 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2646
2647 gsm48_stop_cc_timer(trans);
2648 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2649
2650 /* cause */
2651 if (disc->fields & MNCC_F_CAUSE)
2652 encode_cause(msg, 1, &disc->cause);
2653 else
2654 encode_cause(msg, 1, &default_cause);
2655
2656 /* facility */
2657 if (disc->fields & MNCC_F_FACILITY)
2658 encode_facility(msg, 0, &disc->facility);
2659 /* progress */
2660 if (disc->fields & MNCC_F_PROGRESS)
2661 encode_progress(msg, 0, &disc->progress);
2662 /* user-user */
2663 if (disc->fields & MNCC_F_USERUSER)
2664 encode_useruser(msg, 0, &disc->useruser);
2665
2666 /* store disconnect cause for T306 expiry */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002667 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002668
2669 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2670
2671 return gsm48_sendmsg(msg);
2672}
2673
2674static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2675{
2676 struct gsm48_hdr *gh = msgb_l3(msg);
2677 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2678 struct tlv_parsed tp;
2679 struct gsm_mncc rel;
2680 int rc;
2681
2682 gsm48_stop_cc_timer(trans);
2683
2684 memset(&rel, 0, sizeof(struct gsm_mncc));
2685 rel.callref = trans->callref;
2686 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2687 /* cause */
2688 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2689 rel.fields |= MNCC_F_CAUSE;
2690 decode_cause(&rel.cause,
2691 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2692 }
2693 /* facility */
2694 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2695 rel.fields |= MNCC_F_FACILITY;
2696 decode_facility(&rel.facility,
2697 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2698 }
2699 /* user-user */
2700 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2701 rel.fields |= MNCC_F_USERUSER;
2702 decode_useruser(&rel.useruser,
2703 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2704 }
2705 /* ss-version */
2706 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2707 rel.fields |= MNCC_F_SSVERSION;
2708 decode_ssversion(&rel.ssversion,
2709 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2710 }
2711
Harald Welteaa0b29c2009-07-23 18:56:43 +02002712 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002713 /* release collision 5.4.5 */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002714 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002715 } else {
Harald Welteb3c3fae2009-07-23 19:06:52 +02002716 rc = gsm48_tx_simple(msg->lchan,
2717 GSM48_PDISC_CC | trans->transaction_id,
2718 GSM48_MT_CC_RELEASE_COMPL);
2719 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002720 }
2721
2722 new_cc_state(trans, GSM_CSTATE_NULL);
2723
2724 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002725 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002726
2727 return rc;
2728}
2729
2730static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2731{
2732 struct gsm_mncc *rel = arg;
2733 struct msgb *msg = gsm48_msgb_alloc();
2734 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2735
2736 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2737 msg->lchan = trans->lchan;
2738 gh->msg_type = GSM48_MT_CC_RELEASE;
2739
2740 trans->callref = 0;
2741
2742 gsm48_stop_cc_timer(trans);
2743 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2744
2745 /* cause */
2746 if (rel->fields & MNCC_F_CAUSE)
2747 encode_cause(msg, 0, &rel->cause);
2748 /* facility */
2749 if (rel->fields & MNCC_F_FACILITY)
2750 encode_facility(msg, 0, &rel->facility);
2751 /* user-user */
2752 if (rel->fields & MNCC_F_USERUSER)
2753 encode_useruser(msg, 0, &rel->useruser);
2754
Harald Welteaa0b29c2009-07-23 18:56:43 +02002755 trans->cc.T308_second = 0;
2756 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002757
Harald Welteaa0b29c2009-07-23 18:56:43 +02002758 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002759 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2760
2761 return gsm48_sendmsg(msg);
2762}
2763
2764static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2765{
2766 struct gsm48_hdr *gh = msgb_l3(msg);
2767 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2768 struct tlv_parsed tp;
2769 struct gsm_mncc rel;
2770 int rc = 0;
2771
2772 gsm48_stop_cc_timer(trans);
2773
2774 memset(&rel, 0, sizeof(struct gsm_mncc));
2775 rel.callref = trans->callref;
2776 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2777 /* cause */
2778 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2779 rel.fields |= MNCC_F_CAUSE;
2780 decode_cause(&rel.cause,
2781 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2782 }
2783 /* facility */
2784 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2785 rel.fields |= MNCC_F_FACILITY;
2786 decode_facility(&rel.facility,
2787 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2788 }
2789 /* user-user */
2790 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2791 rel.fields |= MNCC_F_USERUSER;
2792 decode_useruser(&rel.useruser,
2793 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2794 }
2795 /* ss-version */
2796 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2797 rel.fields |= MNCC_F_SSVERSION;
2798 decode_ssversion(&rel.ssversion,
2799 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2800 }
2801
2802 if (trans->callref) {
Harald Welteaa0b29c2009-07-23 18:56:43 +02002803 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002804 case GSM_CSTATE_CALL_PRESENT:
Harald Welteb3c3fae2009-07-23 19:06:52 +02002805 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002806 MNCC_REJ_IND, &rel);
2807 break;
2808 case GSM_CSTATE_RELEASE_REQ:
Harald Welteb3c3fae2009-07-23 19:06:52 +02002809 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002810 MNCC_REL_CNF, &rel);
2811 break;
2812 default:
Harald Welteb3c3fae2009-07-23 19:06:52 +02002813 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002814 MNCC_REL_IND, &rel);
2815 }
2816 }
2817
2818 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002819 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002820
2821 return rc;
2822}
2823
2824static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2825{
2826 struct gsm_mncc *rel = arg;
2827 struct msgb *msg = gsm48_msgb_alloc();
2828 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2829
2830 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2831 msg->lchan = trans->lchan;
2832 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2833
2834 trans->callref = 0;
2835
2836 gsm48_stop_cc_timer(trans);
2837
2838 /* cause */
2839 if (rel->fields & MNCC_F_CAUSE)
2840 encode_cause(msg, 0, &rel->cause);
2841 /* facility */
2842 if (rel->fields & MNCC_F_FACILITY)
2843 encode_facility(msg, 0, &rel->facility);
2844 /* user-user */
2845 if (rel->fields & MNCC_F_USERUSER)
2846 encode_useruser(msg, 0, &rel->useruser);
2847
Harald Welteaa0b29c2009-07-23 18:56:43 +02002848 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002849
2850 return gsm48_sendmsg(msg);
2851}
2852
2853static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2854{
2855 struct gsm48_hdr *gh = msgb_l3(msg);
2856 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2857 struct tlv_parsed tp;
2858 struct gsm_mncc fac;
2859
2860 memset(&fac, 0, sizeof(struct gsm_mncc));
2861 fac.callref = trans->callref;
2862 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2863 /* facility */
2864 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2865 fac.fields |= MNCC_F_FACILITY;
2866 decode_facility(&fac.facility,
2867 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2868 }
2869 /* ss-version */
2870 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2871 fac.fields |= MNCC_F_SSVERSION;
2872 decode_ssversion(&fac.ssversion,
2873 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2874 }
2875
Harald Welteb3c3fae2009-07-23 19:06:52 +02002876 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002877}
2878
2879static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2880{
2881 struct gsm_mncc *fac = arg;
2882 struct msgb *msg = gsm48_msgb_alloc();
2883 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2884
2885 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2886 msg->lchan = trans->lchan;
2887 gh->msg_type = GSM48_MT_CC_FACILITY;
2888
2889 /* facility */
2890 encode_facility(msg, 1, &fac->facility);
2891
2892 return gsm48_sendmsg(msg);
2893}
2894
2895static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2896{
2897 struct gsm_mncc hold;
2898
2899 memset(&hold, 0, sizeof(struct gsm_mncc));
2900 hold.callref = trans->callref;
Harald Welteb3c3fae2009-07-23 19:06:52 +02002901 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002902}
2903
2904static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2905{
2906 struct msgb *msg = gsm48_msgb_alloc();
2907 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2908
2909 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2910 msg->lchan = trans->lchan;
2911 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
2912
2913 return gsm48_sendmsg(msg);
2914}
2915
2916static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
2917{
2918 struct gsm_mncc *hold_rej = arg;
2919 struct msgb *msg = gsm48_msgb_alloc();
2920 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2921
2922 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2923 msg->lchan = trans->lchan;
2924 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
2925
2926 /* cause */
2927 if (hold_rej->fields & MNCC_F_CAUSE)
2928 encode_cause(msg, 1, &hold_rej->cause);
2929 else
2930 encode_cause(msg, 1, &default_cause);
2931
2932 return gsm48_sendmsg(msg);
2933}
2934
2935static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
2936{
2937 struct gsm_mncc retrieve;
2938
2939 memset(&retrieve, 0, sizeof(struct gsm_mncc));
2940 retrieve.callref = trans->callref;
Harald Welteb3c3fae2009-07-23 19:06:52 +02002941 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
2942 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002943}
2944
2945static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
2946{
2947 struct msgb *msg = gsm48_msgb_alloc();
2948 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2949
2950 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2951 msg->lchan = trans->lchan;
2952 gh->msg_type = GSM48_MT_CC_RETR_ACK;
2953
2954 return gsm48_sendmsg(msg);
2955}
2956
2957static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
2958{
2959 struct gsm_mncc *retrieve_rej = arg;
2960 struct msgb *msg = gsm48_msgb_alloc();
2961 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2962
2963 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
2964 msg->lchan = trans->lchan;
2965 gh->msg_type = GSM48_MT_CC_RETR_REJ;
2966
2967 /* cause */
2968 if (retrieve_rej->fields & MNCC_F_CAUSE)
2969 encode_cause(msg, 1, &retrieve_rej->cause);
2970 else
2971 encode_cause(msg, 1, &default_cause);
2972
2973 return gsm48_sendmsg(msg);
2974}
2975
2976static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
2977{
2978 struct gsm48_hdr *gh = msgb_l3(msg);
2979 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2980 struct tlv_parsed tp;
2981 struct gsm_mncc dtmf;
2982
2983 memset(&dtmf, 0, sizeof(struct gsm_mncc));
2984 dtmf.callref = trans->callref;
2985 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2986 /* keypad facility */
2987 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
2988 dtmf.fields |= MNCC_F_KEYPAD;
2989 decode_keypad(&dtmf.keypad,
2990 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
2991 }
2992
Harald Welteb3c3fae2009-07-23 19:06:52 +02002993 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002994}
2995
2996static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
2997{
2998 struct gsm_mncc *dtmf = arg;
2999 struct msgb *msg = gsm48_msgb_alloc();
3000 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3001
3002 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3003 msg->lchan = trans->lchan;
3004 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3005
3006 /* keypad */
3007 if (dtmf->fields & MNCC_F_KEYPAD)
3008 encode_keypad(msg, dtmf->keypad);
3009
3010 return gsm48_sendmsg(msg);
3011}
3012
3013static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3014{
3015 struct gsm_mncc *dtmf = arg;
3016 struct msgb *msg = gsm48_msgb_alloc();
3017 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3018
3019 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3020 msg->lchan = trans->lchan;
3021 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3022
3023 /* cause */
3024 if (dtmf->fields & MNCC_F_CAUSE)
3025 encode_cause(msg, 1, &dtmf->cause);
3026 else
3027 encode_cause(msg, 1, &default_cause);
3028
3029 return gsm48_sendmsg(msg);
3030}
3031
3032static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3033{
3034 struct msgb *msg = gsm48_msgb_alloc();
3035 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3036
3037 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3038 msg->lchan = trans->lchan;
3039 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3040
3041 return gsm48_sendmsg(msg);
3042}
3043
3044static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3045{
3046 struct gsm_mncc dtmf;
3047
3048 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3049 dtmf.callref = trans->callref;
3050
Harald Welteb3c3fae2009-07-23 19:06:52 +02003051 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003052}
3053
3054static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3055{
3056 struct gsm48_hdr *gh = msgb_l3(msg);
3057 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3058 struct tlv_parsed tp;
3059 struct gsm_mncc modify;
3060
3061 memset(&modify, 0, sizeof(struct gsm_mncc));
3062 modify.callref = trans->callref;
3063 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3064 /* bearer capability */
3065 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3066 modify.fields |= MNCC_F_BEARER_CAP;
3067 decode_bearer_cap(&modify.bearer_cap,
3068 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3069 }
3070
3071 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3072
Harald Welteb3c3fae2009-07-23 19:06:52 +02003073 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003074}
3075
3076static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3077{
3078 struct gsm_mncc *modify = arg;
3079 struct msgb *msg = gsm48_msgb_alloc();
3080 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3081
3082 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3083 msg->lchan = trans->lchan;
3084 gh->msg_type = GSM48_MT_CC_MODIFY;
3085
3086 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3087
3088 /* bearer capability */
3089 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3090
3091 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3092
3093 return gsm48_sendmsg(msg);
3094}
3095
3096static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3097{
3098 struct gsm48_hdr *gh = msgb_l3(msg);
3099 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3100 struct tlv_parsed tp;
3101 struct gsm_mncc modify;
3102
3103 gsm48_stop_cc_timer(trans);
3104
3105 memset(&modify, 0, sizeof(struct gsm_mncc));
3106 modify.callref = trans->callref;
3107 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3108 /* bearer capability */
3109 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3110 modify.fields |= MNCC_F_BEARER_CAP;
3111 decode_bearer_cap(&modify.bearer_cap,
3112 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3113 }
3114
3115 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3116
Harald Welteb3c3fae2009-07-23 19:06:52 +02003117 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003118}
3119
3120static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3121{
3122 struct gsm_mncc *modify = arg;
3123 struct msgb *msg = gsm48_msgb_alloc();
3124 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3125
3126 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3127 msg->lchan = trans->lchan;
3128 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3129
3130 /* bearer capability */
3131 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3132
3133 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3134
3135 return gsm48_sendmsg(msg);
3136}
3137
3138static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3139{
3140 struct gsm48_hdr *gh = msgb_l3(msg);
3141 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3142 struct tlv_parsed tp;
3143 struct gsm_mncc modify;
3144
3145 gsm48_stop_cc_timer(trans);
3146
3147 memset(&modify, 0, sizeof(struct gsm_mncc));
3148 modify.callref = trans->callref;
3149 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3150 /* bearer capability */
3151 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3152 modify.fields |= GSM48_IE_BEARER_CAP;
3153 decode_bearer_cap(&modify.bearer_cap,
3154 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3155 }
3156 /* cause */
3157 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3158 modify.fields |= MNCC_F_CAUSE;
3159 decode_cause(&modify.cause,
3160 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3161 }
3162
3163 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3164
Harald Welteb3c3fae2009-07-23 19:06:52 +02003165 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003166}
3167
3168static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3169{
3170 struct gsm_mncc *modify = arg;
3171 struct msgb *msg = gsm48_msgb_alloc();
3172 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3173
3174 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3175 msg->lchan = trans->lchan;
3176 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3177
3178 /* bearer capability */
3179 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3180 /* cause */
3181 encode_cause(msg, 1, &modify->cause);
3182
3183 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3184
3185 return gsm48_sendmsg(msg);
3186}
3187
3188static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3189{
3190 struct gsm_mncc *notify = arg;
3191 struct msgb *msg = gsm48_msgb_alloc();
3192 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3193
3194 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3195 msg->lchan = trans->lchan;
3196 gh->msg_type = GSM48_MT_CC_NOTIFY;
3197
3198 /* notify */
3199 encode_notify(msg, notify->notify);
3200
3201 return gsm48_sendmsg(msg);
3202}
3203
3204static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3205{
3206 struct gsm48_hdr *gh = msgb_l3(msg);
3207 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3208// struct tlv_parsed tp;
3209 struct gsm_mncc notify;
3210
3211 memset(&notify, 0, sizeof(struct gsm_mncc));
3212 notify.callref = trans->callref;
3213// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3214 if (payload_len >= 1)
3215 decode_notify(&notify.notify, gh->data);
3216
Harald Welteb3c3fae2009-07-23 19:06:52 +02003217 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003218}
3219
3220static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3221{
3222 struct gsm_mncc *user = arg;
3223 struct msgb *msg = gsm48_msgb_alloc();
3224 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3225
3226 gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id;
3227 msg->lchan = trans->lchan;
3228 gh->msg_type = GSM48_MT_CC_USER_INFO;
3229
3230 /* user-user */
3231 if (user->fields & MNCC_F_USERUSER)
3232 encode_useruser(msg, 1, &user->useruser);
3233 /* more data */
3234 if (user->more)
3235 encode_more(msg);
3236
3237 return gsm48_sendmsg(msg);
3238}
3239
3240static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3241{
3242 struct gsm48_hdr *gh = msgb_l3(msg);
3243 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3244 struct tlv_parsed tp;
3245 struct gsm_mncc user;
3246
3247 memset(&user, 0, sizeof(struct gsm_mncc));
3248 user.callref = trans->callref;
3249 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3250 /* user-user */
3251 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3252 user.fields |= MNCC_F_USERUSER;
3253 decode_useruser(&user.useruser,
3254 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3255 }
3256 /* more data */
3257 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3258 user.more = 1;
3259
Harald Welteb3c3fae2009-07-23 19:06:52 +02003260 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003261}
3262
3263static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3264{
3265 struct gsm_mncc *mode = arg;
3266
3267 return gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3268}
3269
3270static struct downstate {
3271 u_int32_t states;
3272 int type;
3273 int (*rout) (struct gsm_trans *trans, void *arg);
3274} downstatelist[] = {
3275 /* mobile originating call establishment */
3276 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3277 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3278 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3279 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3280 {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 */
3281 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3282 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3283 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3284 /* mobile terminating call establishment */
3285 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3286 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3287 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3288 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3289 /* signalling during call */
3290 {SBIT(GSM_CSTATE_ACTIVE),
3291 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3292 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3293 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3294 {ALL_STATES,
3295 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3296 {ALL_STATES,
3297 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3298 {ALL_STATES,
3299 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3300 {SBIT(GSM_CSTATE_ACTIVE),
3301 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3302 {SBIT(GSM_CSTATE_ACTIVE),
3303 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3304 {SBIT(GSM_CSTATE_ACTIVE),
3305 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3306 {SBIT(GSM_CSTATE_ACTIVE),
3307 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3308 {SBIT(GSM_CSTATE_ACTIVE),
3309 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3310 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3311 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3312 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3313 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3314 {SBIT(GSM_CSTATE_ACTIVE),
3315 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3316 /* clearing */
3317 {SBIT(GSM_CSTATE_INITIATED),
3318 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3319 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3320 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3321 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3322 MNCC_REL_REQ, gsm48_cc_tx_release},
3323 /* special */
3324 {ALL_STATES,
3325 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3326};
3327
3328#define DOWNSLLEN \
3329 (sizeof(downstatelist) / sizeof(struct downstate))
3330
3331
3332int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3333{
3334 int i, j, k, l, rc = 0;
3335 struct gsm_trans *trans = NULL, *transt;
3336 struct gsm_subscriber *subscr;
3337 struct gsm_lchan *lchan = NULL, *lchant;
3338 struct gsm_bts *bts = NULL;
3339 struct gsm_bts_trx *trx;
3340 struct gsm_bts_trx_ts *ts;
3341 struct gsm_mncc *data = arg, rel;
3342
3343 /* handle special messages */
3344 switch(msg_type) {
3345 case MNCC_BRIDGE:
3346 return tch_bridge(net, arg);
3347 case MNCC_FRAME_DROP:
3348 return tch_recv(net, arg, 0);
3349 case MNCC_FRAME_RECV:
3350 return tch_recv(net, arg, 1);
3351 case GSM_TRAU_FRAME:
3352 return tch_frame(net, arg);
3353 }
3354
3355 memset(&rel, 0, sizeof(struct gsm_mncc));
3356 rel.callref = data->callref;
3357
3358 /* Find callref */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003359 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003360
3361 /* Callref unknown */
3362 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003363 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003364 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3365 "Received '%s' from MNCC with "
3366 "unknown callref %d\n", data->called.number,
3367 get_mncc_name(msg_type), data->callref);
3368 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003369 return mncc_release_ind(net, NULL, data->callref,
3370 GSM48_CAUSE_LOC_PRN_S_LU,
3371 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003372 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003373 if (!data->called.number[0] && !data->imsi[0]) {
3374 DEBUGP(DCC, "(bts - trx - ts - ti) "
3375 "Received '%s' from MNCC with "
3376 "no number or IMSI\n", get_mncc_name(msg_type));
3377 /* Invalid number */
3378 return mncc_release_ind(net, NULL, data->callref,
3379 GSM48_CAUSE_LOC_PRN_S_LU,
3380 GSM48_CC_CAUSE_INV_NR_FORMAT);
3381 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003382 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003383 if (data->called.number[0])
3384 subscr = subscr_get_by_extension(data->called.number);
3385 else
3386 subscr = subscr_get_by_imsi(data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003387 /* If subscriber is not found */
3388 if (!subscr) {
3389 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3390 "Received '%s' from MNCC with "
3391 "unknown subscriber %s\n", data->called.number,
3392 get_mncc_name(msg_type), data->called.number);
3393 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003394 return mncc_release_ind(net, NULL, data->callref,
3395 GSM48_CAUSE_LOC_PRN_S_LU,
3396 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003397 }
3398 /* If subscriber is not "attached" */
3399 if (!subscr->lac) {
3400 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3401 "Received '%s' from MNCC with "
3402 "detached subscriber %s\n", data->called.number,
3403 get_mncc_name(msg_type), data->called.number);
3404 subscr_put(subscr);
3405 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003406 return mncc_release_ind(net, NULL, data->callref,
3407 GSM48_CAUSE_LOC_PRN_S_LU,
3408 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003409 }
3410 /* Create transaction */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003411 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3412 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003413 DEBUGP(DCC, "No memory for trans.\n");
3414 subscr_put(subscr);
3415 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003416 mncc_release_ind(net, NULL, data->callref,
3417 GSM48_CAUSE_LOC_PRN_S_LU,
3418 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003419 return -ENOMEM;
3420 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003421 /* Find lchan */
3422 for (i = 0; i < net->num_bts; i++) {
Harald Weltee441d9c2009-06-21 16:17:15 +02003423 bts = gsm_bts_num(net, i);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003424 for (j = 0; j < bts->num_trx; j++) {
Harald Weltee441d9c2009-06-21 16:17:15 +02003425 trx = gsm_bts_trx_num(bts, j);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003426 for (k = 0; k < TRX_NR_TS; k++) {
3427 ts = &trx->ts[k];
3428 for (l = 0; l < TS_MAX_LCHAN; l++) {
3429 lchant = &ts->lchan[l];
3430 if (lchant->subscr == subscr) {
3431 lchan = lchant;
3432 break;
3433 }
3434 }
3435 }
3436 }
3437 }
3438
3439 /* If subscriber has no lchan */
3440 if (!lchan) {
3441 /* find transaction with this subscriber already paging */
3442 llist_for_each_entry(transt, &net->trans_list, entry) {
3443 /* Transaction of our lchan? */
3444 if (transt == trans ||
3445 transt->subscr != subscr)
3446 continue;
3447 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3448 "Received '%s' from MNCC with "
3449 "unallocated channel, paging already "
3450 "started.\n", bts->nr,
3451 data->called.number,
3452 get_mncc_name(msg_type));
3453 return 0;
3454 }
3455 /* store setup informations until paging was successfull */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003456 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08003457 /* start paging subscriber on all BTS with her location */
3458 subscr->net = net;
3459 bts = NULL;
3460 do {
3461 bts = gsm_bts_by_lac(net, subscr->lac, bts);
3462 if (!bts)
3463 break;
3464 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3465 "Received '%s' from MNCC with "
3466 "unallocated channel, paging.\n",
3467 bts->nr, data->called.number,
3468 get_mncc_name(msg_type));
3469 /* Trigger paging */
Harald Welte92f70c52009-06-12 01:54:08 +08003470 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
Harald Welte4bfdfe72009-06-10 23:11:52 +08003471 setup_trig_pag_evt, subscr);
3472 } while (1);
3473 return 0;
3474 }
3475 /* Assign lchan */
3476 trans->lchan = lchan;
3477 use_lchan(lchan);
3478 }
3479 lchan = trans->lchan;
3480
3481 /* if paging did not respond yet */
3482 if (!lchan) {
3483 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3484 "Received '%s' from MNCC in paging state\n",
3485 (trans->subscr)?(trans->subscr->extension):"-",
3486 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003487 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3488 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003489 if (msg_type == MNCC_REL_REQ)
3490 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3491 else
3492 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3493 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02003494 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003495 return rc;
3496 }
3497
3498 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3499 "Received '%s' from MNCC in state %d (%s)\n",
3500 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3501 trans->transaction_id,
3502 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Welteaa0b29c2009-07-23 18:56:43 +02003503 get_mncc_name(msg_type), trans->cc.state,
3504 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003505
3506 /* Find function for current state and message */
3507 for (i = 0; i < DOWNSLLEN; i++)
3508 if ((msg_type == downstatelist[i].type)
Harald Welteaa0b29c2009-07-23 18:56:43 +02003509 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003510 break;
3511 if (i == DOWNSLLEN) {
3512 DEBUGP(DCC, "Message unhandled at this state.\n");
3513 return 0;
3514 }
3515
3516 rc = downstatelist[i].rout(trans, arg);
3517
3518 return rc;
3519}
3520
3521
3522static struct datastate {
3523 u_int32_t states;
3524 int type;
3525 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3526} datastatelist[] = {
3527 /* mobile originating call establishment */
3528 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3529 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3530 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3531 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3532 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3533 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3534 /* mobile terminating call establishment */
3535 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3536 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3537 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3538 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3539 {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 */
3540 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3541 /* signalling during call */
3542 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3543 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3544 {SBIT(GSM_CSTATE_ACTIVE),
3545 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3546 {ALL_STATES,
3547 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3548 {ALL_STATES,
3549 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3550 {ALL_STATES,
3551 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3552 {SBIT(GSM_CSTATE_ACTIVE),
3553 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3554 {SBIT(GSM_CSTATE_ACTIVE),
3555 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3556 {SBIT(GSM_CSTATE_ACTIVE),
3557 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3558 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3559 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3560 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3561 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3562 {SBIT(GSM_CSTATE_ACTIVE),
3563 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3564 /* clearing */
3565 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3566 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3567 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3568 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3569 {ALL_STATES, /* 5.4.3.4 */
3570 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3571};
3572
3573#define DATASLLEN \
3574 (sizeof(datastatelist) / sizeof(struct datastate))
3575
Harald Welte4bc90a12008-12-27 16:32:52 +00003576static int gsm0408_rcv_cc(struct msgb *msg)
3577{
3578 struct gsm48_hdr *gh = msgb_l3(msg);
3579 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003580 u_int8_t transaction_id = (gh->proto_discr & 0xf0) ^ 0x80; /* flip */
3581 struct gsm_lchan *lchan = msg->lchan;
Harald Welteaa0b29c2009-07-23 18:56:43 +02003582 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003583 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003584
Harald Welte4bfdfe72009-06-10 23:11:52 +08003585 if (msg_type & 0x80) {
3586 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3587 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003588 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003589
3590 /* Find transaction */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003591 trans = trans_find_by_id(lchan, transaction_id);
3592
Harald Welte4bfdfe72009-06-10 23:11:52 +08003593 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3594 "Received '%s' from MS in state %d (%s)\n",
3595 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3596 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Welteaa0b29c2009-07-23 18:56:43 +02003597 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3598 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003599
3600 /* Create transaction */
3601 if (!trans) {
3602 DEBUGP(DCC, "Unknown transaction ID %02x, "
3603 "creating new trans.\n", transaction_id);
3604 /* Create transaction */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003605 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3606 transaction_id, new_callref++);
3607 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003608 DEBUGP(DCC, "No memory for trans.\n");
3609 rc = gsm48_tx_simple(msg->lchan,
3610 GSM48_PDISC_CC | transaction_id,
3611 GSM48_MT_CC_RELEASE_COMPL);
3612 return -ENOMEM;
3613 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003614 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003615 trans->lchan = lchan;
3616 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003617 }
3618
3619 /* find function for current state and message */
3620 for (i = 0; i < DATASLLEN; i++)
3621 if ((msg_type == datastatelist[i].type)
Harald Welteaa0b29c2009-07-23 18:56:43 +02003622 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003623 break;
3624 if (i == DATASLLEN) {
3625 DEBUGP(DCC, "Message unhandled at this state.\n");
3626 return 0;
3627 }
3628
3629 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003630
3631 return rc;
3632}
3633
Harald Welte52b1f982008-12-23 20:25:15 +00003634/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3635int gsm0408_rcvmsg(struct msgb *msg)
3636{
3637 struct gsm48_hdr *gh = msgb_l3(msg);
3638 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003639 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003640
3641 switch (pdisc) {
3642 case GSM48_PDISC_CC:
3643 rc = gsm0408_rcv_cc(msg);
3644 break;
3645 case GSM48_PDISC_MM:
3646 rc = gsm0408_rcv_mm(msg);
3647 break;
3648 case GSM48_PDISC_RR:
3649 rc = gsm0408_rcv_rr(msg);
3650 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003651 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003652 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003653 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003654 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003655 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003656 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3657 pdisc);
3658 break;
3659 default:
3660 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3661 pdisc);
3662 break;
3663 }
3664
3665 return rc;
3666}
Harald Welte8470bf22008-12-25 23:28:35 +00003667
Harald Welte8470bf22008-12-25 23:28:35 +00003668/* Section 9.1.8 / Table 9.9 */
3669struct chreq {
3670 u_int8_t val;
3671 u_int8_t mask;
3672 enum chreq_type type;
3673};
3674
3675/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3676static const struct chreq chreq_type_neci1[] = {
3677 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3678 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3679 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3680 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3681 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3682 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3683 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3684 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3685 { 0x10, 0xf0, CHREQ_T_SDCCH },
3686 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3687 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3688 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3689};
3690
3691/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3692static const struct chreq chreq_type_neci0[] = {
3693 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3694 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3695 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3696 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3697 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3698 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3699 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3700 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3701};
3702
3703static const enum gsm_chan_t ctype_by_chreq[] = {
3704 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3705 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3706 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3707 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3708 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3709 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3710 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3711 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3712 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3713 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3714 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3715 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3716};
3717
Harald Weltee14a57c2008-12-29 04:08:28 +00003718static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3719 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3720 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3721 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3722 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3723 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3724 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3725 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3726 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3727 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3728 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3729 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3730 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3731};
3732
Harald Welte8470bf22008-12-25 23:28:35 +00003733enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3734{
3735 int i;
3736 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3737
3738 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3739 const struct chreq *chr = &chreq_type_neci0[i];
3740 if ((ra & chr->mask) == chr->val)
3741 return ctype_by_chreq[chr->type];
3742 }
3743 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3744 return GSM_LCHAN_SDCCH;
3745}
Harald Weltee14a57c2008-12-29 04:08:28 +00003746
3747enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3748{
3749 int i;
3750 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3751
3752 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3753 const struct chreq *chr = &chreq_type_neci0[i];
3754 if ((ra & chr->mask) == chr->val)
3755 return reason_by_chreq[chr->type];
3756 }
3757 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3758 return GSM_CHREQ_REASON_OTHER;
3759}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003760
3761/* dequeue messages to layer 4 */
3762int bsc_upqueue(struct gsm_network *net)
3763{
3764 struct gsm_mncc *mncc;
3765 struct msgb *msg;
3766 int work = 0;
3767
3768 if (net)
3769 while ((msg = msgb_dequeue(&net->upqueue))) {
3770 mncc = (struct gsm_mncc *)msg->data;
3771 if (net->mncc_recv)
3772 net->mncc_recv(net, mncc->msg_type, mncc);
3773 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003774 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003775 }
3776
3777 return work;
3778}
Harald Welteaa0b29c2009-07-23 18:56:43 +02003779