blob: 2d3a634e1aee07dd82f38069e84a60f90c727f64 [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 Welte805f6442009-07-28 18:25:29 +020047#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020048#include <openbsc/talloc.h>
Harald Welteaa0b29c2009-07-23 18:56:43 +020049#include <openbsc/transaction.h>
Harald Welte52b1f982008-12-23 20:25:15 +000050
Harald Welte8470bf22008-12-25 23:28:35 +000051#define GSM48_ALLOC_SIZE 1024
52#define GSM48_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000053
Harald Welte0c389302009-06-10 12:08:54 +080054#define GSM_MAX_FACILITY 128
55#define GSM_MAX_SSVERSION 128
56#define GSM_MAX_USERUSER 128
57
Harald Welte2cf161b2009-06-20 22:36:41 +020058static void *tall_locop_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020059
Harald Welte805f6442009-07-28 18:25:29 +020060/* should ip.access BTS use direct RTP streams between each other (1),
61 * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
62int ipacc_rtp_direct = 1;
63
Harald Welte09e38af2009-02-16 22:52:23 +000064static const struct tlv_definition rsl_att_tlvdef = {
65 .def = {
66 [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
67 [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
68 [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
69 [GSM48_IE_UTC] = { TLV_TYPE_TV },
70 [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
71 [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
72
73 [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
74 [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
75 [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
76 [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
77 [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
78 [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
79 [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
Harald Welte0c389302009-06-10 12:08:54 +080080 [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
Harald Welte09e38af2009-02-16 22:52:23 +000081 [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
82 [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
Harald Welte0c389302009-06-10 12:08:54 +080083 [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
84 [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
Harald Welte09e38af2009-02-16 22:52:23 +000085 [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
86 [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
87 [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
88 [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
89 [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
90 [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
91 [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
92 [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
93 [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
94 [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
95 [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
96 [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
97 [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
98 [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
Harald Welte0c389302009-06-10 12:08:54 +080099 [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
100 [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
Harald Welte09e38af2009-02-16 22:52:23 +0000101 /* FIXME: more elements */
102 },
103};
Harald Weltecf5b3592009-05-01 18:28:42 +0000104
105static const char *rr_cause_names[] = {
106 [GSM48_RR_CAUSE_NORMAL] = "Normal event",
107 [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
108 [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
109 [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
110 [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
111 [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
112 [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
113 [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
114 [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
115 [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
116 [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
117 [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
118 [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
119 [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
120 [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
121 [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
122 [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
123};
124
Harald Welte4bfdfe72009-06-10 23:11:52 +0800125static const char *cc_state_names[] = {
126 "NULL",
127 "INITIATED",
128 "illegal state 2",
129 "MO_CALL_PROC",
130 "CALL_DELIVERED",
131 "illegal state 5",
132 "CALL_PRESENT",
133 "CALL_RECEIVED",
134 "CONNECT_REQUEST",
135 "MO_TERM_CALL_CONF",
136 "ACTIVE",
137 "DISCONNECT_REQ",
138 "DISCONNECT_IND",
139 "illegal state 13",
140 "illegal state 14",
141 "illegal state 15",
142 "illegal state 16",
143 "illegal state 17",
144 "illegal state 18",
145 "RELEASE_REQ",
146 "illegal state 20",
147 "illegal state 21",
148 "illegal state 22",
149 "illegal state 23",
150 "illegal state 24",
151 "illegal state 25",
152 "MO_ORIG_MODIFY",
153 "MO_TERM_MODIFY",
154 "CONNECT_IND",
155 "illegal state 29",
156 "illegal state 30",
157 "illegal state 31",
158};
159
160static const char *cc_msg_names[] = {
161 "unknown 0x00",
162 "ALERTING",
163 "CALL_PROC",
164 "PROGRESS",
165 "ESTAB",
166 "SETUP",
167 "ESTAB_CONF",
168 "CONNECT",
169 "CALL_CONF",
170 "START_CC",
171 "unknown 0x0a",
172 "RECALL",
173 "unknown 0x0c",
174 "unknown 0x0d",
175 "EMERG_SETUP",
176 "CONNECT_ACK",
177 "USER_INFO",
178 "unknown 0x11",
179 "unknown 0x12",
180 "MODIFY_REJECT",
181 "unknown 0x14",
182 "unknown 0x15",
183 "unknown 0x16",
184 "MODIFY",
185 "HOLD",
186 "HOLD_ACK",
187 "HOLD_REJ",
188 "unknown 0x1b",
189 "RETR",
190 "RETR_ACK",
191 "RETR_REJ",
192 "MODIFY_COMPL",
193 "unknown 0x20",
194 "unknown 0x21",
195 "unknown 0x22",
196 "unknown 0x23",
197 "unknown 0x24",
198 "DISCONNECT",
199 "unknown 0x26",
200 "unknown 0x27",
201 "unknown 0x28",
202 "unknown 0x29",
203 "RELEASE_COMPL",
204 "unknown 0x2b",
205 "unknown 0x2c",
206 "RELEASE",
207 "unknown 0x2e",
208 "unknown 0x2f",
209 "unknown 0x30",
210 "STOP_DTMF",
211 "STOP_DTMF_ACK",
212 "unknown 0x33",
213 "STATUS_ENQ",
214 "START_DTMF",
215 "START_DTMF_ACK",
216 "START_DTMF_REJ",
217 "unknown 0x38",
218 "CONG_CTRL",
219 "FACILITY",
220 "unknown 0x3b",
221 "STATUS",
222 "unknown 0x3c",
223 "NOTIFY",
224 "unknown 0x3f",
225};
226
Harald Weltecf5b3592009-05-01 18:28:42 +0000227static char strbuf[64];
228
229static const char *rr_cause_name(u_int8_t cause)
230{
231 if (cause < ARRAY_SIZE(rr_cause_names) &&
232 rr_cause_names[cause])
233 return rr_cause_names[cause];
234
235 snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
236 return strbuf;
237}
238
Harald Weltef7c43522009-06-09 20:24:21 +0000239static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
240 int len)
241{
242 memset(rep, 0, sizeof(*rep));
243
244 if (data[0] & 0x80)
245 rep->flags |= MEAS_REP_F_BA1;
246 if (data[0] & 0x40)
247 rep->flags |= MEAS_REP_F_DTX;
248 if (data[1] & 0x40)
249 rep->flags |= MEAS_REP_F_VALID;
250
251 rep->rxlev_full = data[0] & 0x3f;
252 rep->rxlev_sub = data[1] & 0x3f;
253 rep->rxqual_full = (data[3] >> 4) & 0x7;
254 rep->rxqual_sub = (data[3] >> 1) & 0x7;
255 rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2);
256 if (rep->num_cell < 1)
257 return;
258
259 /* an encoding nightmare in perfection */
260
261 rep->cell[0].rxlev = data[4] & 0x3f;
262 rep->cell[0].bcch_freq = data[5] >> 2;
263 rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5);
264 if (rep->num_cell < 2)
265 return;
266
267 rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7);
268 rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f;
269 rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4);
270 if (rep->num_cell < 3)
271 return;
272
273 rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6);
274 rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f;
275 rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3);
276 if (rep->num_cell < 4)
277 return;
278
279 rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5);
280 rep->cell[3].bcch_freq = data[11] & 0x1f;
281 rep->cell[3].bsic = data[12] >> 2;
282 if (rep->num_cell < 5)
283 return;
284
285 rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4);
286 rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7);
287 rep->cell[4].bsic = (data[14] >> 1) & 0x3f;
288 if (rep->num_cell < 6)
289 return;
290
291 rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3);
292 rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6);
293 rep->cell[5].bsic = data[16] & 0x3f;
294}
295
Holger Freytherd51524f2009-06-09 08:27:07 +0000296int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
Harald Welte65e74cc2008-12-29 01:55:35 +0000297static int gsm48_tx_simple(struct gsm_lchan *lchan,
298 u_int8_t pdisc, u_int8_t msg_type);
Holger Freytherb7193e42008-12-29 17:44:08 +0000299static void schedule_reject(struct gsm_lchan *lchan);
Harald Welte65e74cc2008-12-29 01:55:35 +0000300
Harald Welte52b1f982008-12-23 20:25:15 +0000301struct gsm_lai {
302 u_int16_t mcc;
303 u_int16_t mnc;
304 u_int16_t lac;
305};
306
Holger Freyther89824fc2008-12-30 16:18:18 +0000307static int authorize_everonye = 0;
308void gsm0408_allow_everyone(int everyone)
309{
310 printf("Allowing everyone?\n");
311 authorize_everonye = everyone;
312}
313
Holger Freythere97f7fb2008-12-31 18:52:11 +0000314static int reject_cause = 0;
315void gsm0408_set_reject_cause(int cause)
316{
317 reject_cause = cause;
318}
319
Harald Welte4bfdfe72009-06-10 23:11:52 +0800320static u_int32_t new_callref = 0x80000001;
321
Holger Freyther73487a22008-12-31 18:53:57 +0000322static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
323 struct gsm_subscriber *subscriber)
Holger Freyther89824fc2008-12-30 16:18:18 +0000324{
325 if (!subscriber)
326 return 0;
327
Holger Freyther73487a22008-12-31 18:53:57 +0000328 /*
329 * Do not send accept yet as more information should arrive. Some
330 * phones will not send us the information and we will have to check
331 * what we want to do with that.
332 */
333 if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
334 return 0;
335
Holger Freyther89824fc2008-12-30 16:18:18 +0000336 if (authorize_everonye)
337 return 1;
338
339 return subscriber->authorized;
340}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000341
Holger Freyther73487a22008-12-31 18:53:57 +0000342static void release_loc_updating_req(struct gsm_lchan *lchan)
343{
Harald Welte179f0642008-12-31 23:59:18 +0000344 if (!lchan->loc_operation)
Holger Freyther73487a22008-12-31 18:53:57 +0000345 return;
346
Harald Welteff117a82009-05-23 05:22:08 +0000347 bsc_del_timer(&lchan->loc_operation->updating_timer);
Harald Welte2cf161b2009-06-20 22:36:41 +0200348 talloc_free(lchan->loc_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000349 lchan->loc_operation = 0;
Holger Freyther3eaa7922009-01-01 02:59:03 +0000350 put_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000351}
352
353static void allocate_loc_updating_req(struct gsm_lchan *lchan)
354{
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000355 use_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000356 release_loc_updating_req(lchan);
357
Harald Welte470ec292009-06-26 20:25:23 +0200358 lchan->loc_operation = talloc_zero(tall_locop_ctx,
359 struct gsm_loc_updating_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000360}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000361
Holger Freytherd51524f2009-06-09 08:27:07 +0000362static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
363{
364 u_int32_t tmsi;
365
366 if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
367 db_subscriber_alloc_tmsi(lchan->subscr);
368 subscr_update(lchan->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED);
369 tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
370 release_loc_updating_req(lchan);
371 return gsm0408_loc_upd_acc(msg->lchan, tmsi);
372 }
373
374 return 0;
375}
376
Holger Freyther7c19f742009-06-06 13:54:35 +0000377static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
378 void *handler_data, void *signal_data)
379{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800380 struct gsm_trans *trans, *temp;
381
Holger Freyther7c19f742009-06-06 13:54:35 +0000382 if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
383 return 0;
384
385 /*
386 * Cancel any outstanding location updating request
387 * operation taking place on the lchan.
388 */
Harald Welte1a5c6bd2009-07-04 09:35:21 +0200389 struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
Harald Weltec05677b2009-06-26 20:17:06 +0200390 if (!lchan)
391 return 0;
392
Holger Freyther7c19f742009-06-06 13:54:35 +0000393 release_loc_updating_req(lchan);
394
Harald Welte4bfdfe72009-06-10 23:11:52 +0800395 /* Free all transactions that are associated with the released lchan */
Harald Welteaa0b29c2009-07-23 18:56:43 +0200396 /* FIXME: this is not neccessarily the right thing to do, we should
397 * only set trans->lchan to NULL and wait for another lchan to be
398 * established to the same MM entity (phone/subscriber) */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800399 llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
400 if (trans->lchan == lchan)
Harald Welteaa0b29c2009-07-23 18:56:43 +0200401 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800402 }
403
Holger Freyther7c19f742009-06-06 13:54:35 +0000404 return 0;
405}
406
Harald Welte52b1f982008-12-23 20:25:15 +0000407static void to_bcd(u_int8_t *bcd, u_int16_t val)
408{
Harald Welte4b634542008-12-27 01:55:51 +0000409 bcd[2] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000410 val = val / 10;
411 bcd[1] = val % 10;
412 val = val / 10;
Harald Welte4b634542008-12-27 01:55:51 +0000413 bcd[0] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000414 val = val / 10;
415}
416
Holger Freyther17746612008-12-28 16:32:44 +0000417void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
Harald Welte52b1f982008-12-23 20:25:15 +0000418 u_int16_t mnc, u_int16_t lac)
419{
420 u_int8_t bcd[3];
421
422 to_bcd(bcd, mcc);
423 lai48->digits[0] = bcd[0] | (bcd[1] << 4);
424 lai48->digits[1] = bcd[2];
425
426 to_bcd(bcd, mnc);
Harald Welte4b634542008-12-27 01:55:51 +0000427 /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
428#if 0
Harald Welte8470bf22008-12-25 23:28:35 +0000429 lai48->digits[1] |= bcd[2] << 4;
430 lai48->digits[2] = bcd[0] | (bcd[1] << 4);
Harald Welte4b634542008-12-27 01:55:51 +0000431#else
432 lai48->digits[1] |= 0xf << 4;
433 lai48->digits[2] = bcd[1] | (bcd[2] << 4);
434#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000435
Harald Welte4b634542008-12-27 01:55:51 +0000436 lai48->lac = htons(lac);
Harald Welte52b1f982008-12-23 20:25:15 +0000437}
438
Harald Welte255539c2008-12-28 02:26:27 +0000439#define TMSI_LEN 5
Harald Welte52b1f982008-12-23 20:25:15 +0000440#define MID_TMSI_LEN (TMSI_LEN + 2)
441
Harald Welte255539c2008-12-28 02:26:27 +0000442int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +0000443{
Harald Welte65e74cc2008-12-29 01:55:35 +0000444 u_int32_t *tptr = (u_int32_t *) &buf[3];
Harald Welte255539c2008-12-28 02:26:27 +0000445
Harald Welte4b634542008-12-27 01:55:51 +0000446 buf[0] = GSM48_IE_MOBILE_ID;
Harald Welte1a412182008-12-27 22:13:43 +0000447 buf[1] = TMSI_LEN;
Harald Welte4b634542008-12-27 01:55:51 +0000448 buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
Harald Welte255539c2008-12-28 02:26:27 +0000449 *tptr = htonl(tmsi);
450
451 return 7;
Harald Welte52b1f982008-12-23 20:25:15 +0000452}
453
Harald Welte09e38af2009-02-16 22:52:23 +0000454static const char bcd_num_digits[] = {
455 '0', '1', '2', '3', '4', '5', '6', '7',
456 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
457};
458
Harald Welte0c389302009-06-10 12:08:54 +0800459/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
460int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
461 int h_len)
Harald Welte09e38af2009-02-16 22:52:23 +0000462{
463 u_int8_t in_len = bcd_lv[0];
464 int i;
465
Harald Welte0c389302009-06-10 12:08:54 +0800466 for (i = 1 + h_len; i <= in_len; i++) {
Harald Welte09e38af2009-02-16 22:52:23 +0000467 /* lower nibble */
468 output_len--;
469 if (output_len <= 1)
470 break;
471 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
472
473 /* higher nibble */
474 output_len--;
475 if (output_len <= 1)
476 break;
477 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
478 }
479 if (output_len >= 1)
480 *output++ = '\0';
481
Harald Welte0c389302009-06-10 12:08:54 +0800482 return 0;
Harald Welte09e38af2009-02-16 22:52:23 +0000483}
484
485/* convert a single ASCII character to call-control BCD */
486static int asc_to_bcd(const char asc)
487{
488 int i;
489
490 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
491 if (bcd_num_digits[i] == asc)
492 return i;
493 }
494 return -EINVAL;
495}
496
Harald Welte0c389302009-06-10 12:08:54 +0800497/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
Harald Welte09e38af2009-02-16 22:52:23 +0000498int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
Harald Welte0c389302009-06-10 12:08:54 +0800499 int h_len, const char *input)
Harald Welte09e38af2009-02-16 22:52:23 +0000500{
501 int in_len = strlen(input);
502 int i;
Harald Welte0c389302009-06-10 12:08:54 +0800503 u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000504
505 /* two digits per byte, plus type byte */
Harald Welte0c389302009-06-10 12:08:54 +0800506 bcd_lv[0] = in_len/2 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000507 if (in_len % 2)
508 bcd_lv[0]++;
509
Harald Welte0c389302009-06-10 12:08:54 +0800510 if (bcd_lv[0] > max_len)
511 return -EIO;
Harald Welte09e38af2009-02-16 22:52:23 +0000512
513 for (i = 0; i < in_len; i++) {
514 int rc = asc_to_bcd(input[i]);
515 if (rc < 0)
516 return rc;
517 if (i % 2 == 0)
518 *bcd_cur = rc;
519 else
520 *bcd_cur++ |= (rc << 4);
521 }
522 /* append padding nibble in case of odd length */
523 if (i % 2)
524 *bcd_cur++ |= 0xf0;
525
526 /* return how many bytes we used */
527 return (bcd_cur - bcd_lv);
528}
529
Harald Welte0c389302009-06-10 12:08:54 +0800530/* decode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800531static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
Harald Welte0c389302009-06-10 12:08:54 +0800532 const u_int8_t *lv)
533{
534 u_int8_t in_len = lv[0];
535 int i, s;
536
537 if (in_len < 1)
538 return -EINVAL;
539
Harald Welte4bfdfe72009-06-10 23:11:52 +0800540 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
Harald Welte0c389302009-06-10 12:08:54 +0800541
542 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800543 bcap->transfer = lv[1] & 0x07;
544 bcap->mode = (lv[1] & 0x08) >> 3;
545 bcap->coding = (lv[1] & 0x10) >> 4;
546 bcap->radio = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800547
548 i = 1;
549 s = 0;
550 while(!(lv[i] & 0x80)) {
551 i++; /* octet 3a etc */
552 if (in_len < i)
553 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800554 bcap->speech_ver[s++] = lv[i] & 0x0f;
555 bcap->speech_ver[s] = -1; /* end of list */
Harald Welte0c389302009-06-10 12:08:54 +0800556 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800557 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800558 if (s == 7) /* maximum speech versions + end of list */
559 return 0;
560 }
561
562 return 0;
563}
564
565/* encode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800566static int encode_bearer_cap(struct msgb *msg, int lv_only,
567 const struct gsm_mncc_bearer_cap *bcap)
Harald Welte0c389302009-06-10 12:08:54 +0800568{
569 u_int8_t lv[32 + 1];
570 int i, s;
571
Harald Welte4bfdfe72009-06-10 23:11:52 +0800572 lv[1] = bcap->transfer;
573 lv[1] |= bcap->mode << 3;
574 lv[1] |= bcap->coding << 4;
575 lv[1] |= bcap->radio << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800576
577 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800578 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
Harald Welte0c389302009-06-10 12:08:54 +0800579 i++; /* octet 3a etc */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800580 lv[i] = bcap->speech_ver[s];
Harald Welte0c389302009-06-10 12:08:54 +0800581 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800582 lv[i] |= bcap->speech_ctm << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800583 }
584 lv[i] |= 0x80; /* last IE of octet 3 etc */
585
586 lv[0] = i;
587 if (lv_only)
588 msgb_lv_put(msg, lv[0], lv+1);
589 else
590 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
591
592 return 0;
593}
594
595/* decode 'call control cap' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800596static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800597{
598 u_int8_t in_len = lv[0];
599
600 if (in_len < 1)
601 return -EINVAL;
602
603 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800604 ccap->dtmf = lv[1] & 0x01;
605 ccap->pcp = (lv[1] & 0x02) >> 1;
Harald Welte0c389302009-06-10 12:08:54 +0800606
607 return 0;
608}
609
610/* decode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800611static int decode_called(struct gsm_mncc_number *called,
612 const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800613{
614 u_int8_t in_len = lv[0];
615
616 if (in_len < 1)
617 return -EINVAL;
618
619 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800620 called->plan = lv[1] & 0x0f;
621 called->type = (lv[1] & 0x70) >> 4;
Harald Welte0c389302009-06-10 12:08:54 +0800622
623 /* octet 4..N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800624 decode_bcd_number(called->number, sizeof(called->number), lv, 1);
Harald Welte0c389302009-06-10 12:08:54 +0800625
626 return 0;
627}
628
629/* encode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800630static int encode_called(struct msgb *msg,
631 const struct gsm_mncc_number *called)
Harald Welte0c389302009-06-10 12:08:54 +0800632{
633 u_int8_t lv[18];
634 int ret;
635
636 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800637 lv[1] = called->plan;
638 lv[1] |= called->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800639
640 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800641 ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
Harald Welte0c389302009-06-10 12:08:54 +0800642 if (ret < 0)
643 return ret;
644
645 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
646
647 return 0;
648}
649
650/* encode callerid of various IEs */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800651static int encode_callerid(struct msgb *msg, int ie,
652 const struct gsm_mncc_number *callerid)
Harald Welte0c389302009-06-10 12:08:54 +0800653{
654 u_int8_t lv[13];
655 int h_len = 1;
656 int ret;
657
658 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800659 lv[1] = callerid->plan;
660 lv[1] |= callerid->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800661
Harald Welte4bfdfe72009-06-10 23:11:52 +0800662 if (callerid->present || callerid->screen) {
Harald Welte0c389302009-06-10 12:08:54 +0800663 /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800664 lv[2] = callerid->screen;
665 lv[2] |= callerid->present << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800666 lv[2] |= 0x80;
667 h_len++;
668 } else
669 lv[1] |= 0x80;
670
671 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800672 ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
Harald Welte0c389302009-06-10 12:08:54 +0800673 if (ret < 0)
674 return ret;
675
676 msgb_tlv_put(msg, ie, lv[0], lv+1);
677
678 return 0;
679}
680
681/* decode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800682static int decode_cause(struct gsm_mncc_cause *cause,
Harald Welte0c389302009-06-10 12:08:54 +0800683 const u_int8_t *lv)
684{
685 u_int8_t in_len = lv[0];
686 int i;
687
688 if (in_len < 2)
689 return -EINVAL;
690
Harald Welte4bfdfe72009-06-10 23:11:52 +0800691 cause->diag_len = 0;
Harald Welte0c389302009-06-10 12:08:54 +0800692
693 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800694 cause->location = lv[1] & 0x0f;
695 cause->coding = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800696
697 i = 1;
698 if (!(lv[i] & 0x80)) {
699 i++; /* octet 3a */
700 if (in_len < i+1)
701 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800702 cause->rec = 1;
703 cause->rec_val = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800704
705 }
706 i++;
707
708 /* octet 4 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800709 cause->value = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800710 i++;
711
712 if (in_len < i) /* no diag */
713 return 0;
714
715 if (in_len - (i-1) > 32) /* maximum 32 octets */
716 return 0;
717
718 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800719 memcpy(cause->diag, lv + i, in_len - (i-1));
720 cause->diag_len = in_len - (i-1);
Harald Welte0c389302009-06-10 12:08:54 +0800721
722 return 0;
723}
724
725/* encode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800726static int encode_cause(struct msgb *msg, int lv_only,
727 const struct gsm_mncc_cause *cause)
Harald Welte0c389302009-06-10 12:08:54 +0800728{
729 u_int8_t lv[32+4];
730 int i;
731
Harald Welte4bfdfe72009-06-10 23:11:52 +0800732 if (cause->diag_len > 32)
Harald Welte0c389302009-06-10 12:08:54 +0800733 return -EINVAL;
734
735 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800736 lv[1] = cause->location;
737 lv[1] |= cause->coding << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800738
739 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800740 if (cause->rec) {
Harald Welte0c389302009-06-10 12:08:54 +0800741 i++; /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800742 lv[i] = cause->rec_val;
Harald Welte0c389302009-06-10 12:08:54 +0800743 }
744 lv[i] |= 0x80; /* end of octet 3 */
745
746 /* octet 4 */
747 i++;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800748 lv[i] = 0x80 | cause->value;
Harald Welte0c389302009-06-10 12:08:54 +0800749
750 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800751 if (cause->diag_len) {
752 memcpy(lv + i, cause->diag, cause->diag_len);
753 i += cause->diag_len;
Harald Welte0c389302009-06-10 12:08:54 +0800754 }
755
756 lv[0] = i;
757 if (lv_only)
758 msgb_lv_put(msg, lv[0], lv+1);
759 else
760 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
761
762 return 0;
763}
764
765/* encode 'calling number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800766static int encode_calling(struct msgb *msg,
767 const struct gsm_mncc_number *calling)
Harald Welte0c389302009-06-10 12:08:54 +0800768{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800769 return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
Harald Welte0c389302009-06-10 12:08:54 +0800770}
771
772/* encode 'connected number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800773static int encode_connected(struct msgb *msg,
774 const struct gsm_mncc_number *connected)
Harald Welte0c389302009-06-10 12:08:54 +0800775{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800776 return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
Harald Welte0c389302009-06-10 12:08:54 +0800777}
778
779/* encode 'redirecting number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800780static int encode_redirecting(struct msgb *msg,
781 const struct gsm_mncc_number *redirecting)
Harald Welte0c389302009-06-10 12:08:54 +0800782{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800783 return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
Harald Welte0c389302009-06-10 12:08:54 +0800784}
785
786/* decode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800787static int decode_facility(struct gsm_mncc_facility *facility,
Harald Welte0c389302009-06-10 12:08:54 +0800788 const u_int8_t *lv)
789{
790 u_int8_t in_len = lv[0];
791
792 if (in_len < 1)
793 return -EINVAL;
794
Harald Welte4bfdfe72009-06-10 23:11:52 +0800795 if (in_len > sizeof(facility->info))
Harald Welte0c389302009-06-10 12:08:54 +0800796 return -EINVAL;
797
Harald Welte4bfdfe72009-06-10 23:11:52 +0800798 memcpy(facility->info, lv+1, in_len);
799 facility->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800800
801 return 0;
802}
803
804/* encode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800805static int encode_facility(struct msgb *msg, int lv_only,
806 const struct gsm_mncc_facility *facility)
Harald Welte0c389302009-06-10 12:08:54 +0800807{
808 u_int8_t lv[GSM_MAX_FACILITY + 1];
809
Harald Welte4bfdfe72009-06-10 23:11:52 +0800810 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
Harald Welte0c389302009-06-10 12:08:54 +0800811 return -EINVAL;
812
Harald Welte4bfdfe72009-06-10 23:11:52 +0800813 memcpy(lv+1, facility->info, facility->len);
814 lv[0] = facility->len;
Harald Welte0c389302009-06-10 12:08:54 +0800815 if (lv_only)
816 msgb_lv_put(msg, lv[0], lv+1);
817 else
818 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
819
820 return 0;
821}
822
823/* decode 'notify' */
824static int decode_notify(int *notify, const u_int8_t *v)
825{
826 *notify = v[0] & 0x7f;
827
828 return 0;
829}
830
831/* encode 'notify' */
832static int encode_notify(struct msgb *msg, int notify)
833{
834 msgb_v_put(msg, notify | 0x80);
835
836 return 0;
837}
838
839/* encode 'signal' */
840static int encode_signal(struct msgb *msg, int signal)
841{
842 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
843
844 return 0;
845}
846
847/* decode 'keypad' */
848static int decode_keypad(int *keypad, const u_int8_t *lv)
849{
850 u_int8_t in_len = lv[0];
851
852 if (in_len < 1)
853 return -EINVAL;
854
855 *keypad = lv[1] & 0x7f;
856
857 return 0;
858}
859
860/* encode 'keypad' */
861static int encode_keypad(struct msgb *msg, int keypad)
862{
863 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
864
865 return 0;
866}
867
868/* decode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800869static int decode_progress(struct gsm_mncc_progress *progress,
Harald Welte0c389302009-06-10 12:08:54 +0800870 const u_int8_t *lv)
871{
872 u_int8_t in_len = lv[0];
873
874 if (in_len < 2)
875 return -EINVAL;
876
Harald Welte4bfdfe72009-06-10 23:11:52 +0800877 progress->coding = (lv[1] & 0x60) >> 5;
878 progress->location = lv[1] & 0x0f;
879 progress->descr = lv[2] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800880
881 return 0;
882}
883
884/* encode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800885static int encode_progress(struct msgb *msg, int lv_only,
886 const struct gsm_mncc_progress *p)
Harald Welte0c389302009-06-10 12:08:54 +0800887{
888 u_int8_t lv[3];
889
890 lv[0] = 2;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800891 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
892 lv[2] = 0x80 | (p->descr & 0x7f);
Harald Welte0c389302009-06-10 12:08:54 +0800893 if (lv_only)
894 msgb_lv_put(msg, lv[0], lv+1);
895 else
896 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
897
898 return 0;
899}
900
901/* decode 'user-user' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800902static int decode_useruser(struct gsm_mncc_useruser *uu,
Harald Welte0c389302009-06-10 12:08:54 +0800903 const u_int8_t *lv)
904{
905 u_int8_t in_len = lv[0];
Harald Welte4bfdfe72009-06-10 23:11:52 +0800906 char *info = uu->info;
907 int info_len = sizeof(uu->info);
Harald Welte0c389302009-06-10 12:08:54 +0800908 int i;
909
910 if (in_len < 1)
911 return -EINVAL;
912
Harald Welte4bfdfe72009-06-10 23:11:52 +0800913 uu->proto = lv[1];
Harald Welte0c389302009-06-10 12:08:54 +0800914
915 for (i = 2; i <= in_len; i++) {
916 info_len--;
917 if (info_len <= 1)
918 break;
919 *info++ = lv[i];
920 }
921 if (info_len >= 1)
922 *info++ = '\0';
923
924 return 0;
925}
926
927/* encode 'useruser' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800928static int encode_useruser(struct msgb *msg, int lv_only,
929 const struct gsm_mncc_useruser *uu)
Harald Welte0c389302009-06-10 12:08:54 +0800930{
931 u_int8_t lv[GSM_MAX_USERUSER + 2];
932
Harald Welte4bfdfe72009-06-10 23:11:52 +0800933 if (strlen(uu->info) > GSM_MAX_USERUSER)
Harald Welte0c389302009-06-10 12:08:54 +0800934 return -EINVAL;
935
Harald Welte4bfdfe72009-06-10 23:11:52 +0800936 lv[0] = 1 + strlen(uu->info);
937 lv[1] = uu->proto;
938 memcpy(lv + 2, uu->info, strlen(uu->info));
Harald Welte0c389302009-06-10 12:08:54 +0800939 if (lv_only)
940 msgb_lv_put(msg, lv[0], lv+1);
941 else
942 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
943
944 return 0;
945}
946
947/* decode 'ss version' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800948static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
Harald Welte0c389302009-06-10 12:08:54 +0800949 const u_int8_t *lv)
950{
951 u_int8_t in_len = lv[0];
952
Harald Welte4bfdfe72009-06-10 23:11:52 +0800953 if (in_len < 1 || in_len < sizeof(ssv->info))
Harald Welte0c389302009-06-10 12:08:54 +0800954 return -EINVAL;
955
Harald Welte4bfdfe72009-06-10 23:11:52 +0800956 memcpy(ssv->info, lv + 1, in_len);
957 ssv->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800958
959 return 0;
960}
961
962/* encode 'more data' */
963static int encode_more(struct msgb *msg)
964{
965 u_int8_t *ie;
966
967 ie = msgb_put(msg, 1);
968 ie[0] = GSM48_IE_MORE_DATA;
969
970 return 0;
971}
972
Holger Freyther819dd202009-01-04 03:52:50 +0000973struct msgb *gsm48_msgb_alloc(void)
Harald Welte8470bf22008-12-25 23:28:35 +0000974{
Harald Welte966636f2009-06-26 19:39:35 +0200975 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
976 "GSM 04.08");
Harald Welte8470bf22008-12-25 23:28:35 +0000977}
978
Harald Welte39e2ead2009-07-23 21:13:03 +0200979int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
Harald Welte52b1f982008-12-23 20:25:15 +0000980{
Harald Welte39e2ead2009-07-23 21:13:03 +0200981 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
982
983 /* if we get passed a transaction reference, do some common
984 * work that the caller no longer has to do */
985 if (trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +0200986 gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
Harald Welte39e2ead2009-07-23 21:13:03 +0200987 msg->lchan = trans->lchan;
988 }
989
Harald Welte65e74cc2008-12-29 01:55:35 +0000990 if (msg->lchan) {
Harald Welte8470bf22008-12-25 23:28:35 +0000991 msg->trx = msg->lchan->ts->trx;
Harald Welte52b1f982008-12-23 20:25:15 +0000992
Harald Welte4bfdfe72009-06-10 23:11:52 +0800993 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
994 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
995 "Sending '%s' to MS.\n", msg->trx->bts->nr,
996 msg->trx->nr, msg->lchan->ts->nr,
997 gh->proto_discr & 0xf0,
998 cc_msg_names[gh->msg_type & 0x3f]);
999 else
1000 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
1001 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
1002 msg->trx->nr, msg->lchan->ts->nr,
1003 gh->proto_discr, gh->msg_type);
Harald Welte65e74cc2008-12-29 01:55:35 +00001004 }
1005
Harald Welte4b634542008-12-27 01:55:51 +00001006 msg->l3h = msg->data;
1007
Harald Welte8470bf22008-12-25 23:28:35 +00001008 return rsl_data_request(msg, 0);
Harald Welte52b1f982008-12-23 20:25:15 +00001009}
1010
Holger Freyther429e7762008-12-30 13:28:30 +00001011/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
Harald Welte8470bf22008-12-25 23:28:35 +00001012int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
Harald Welte52b1f982008-12-23 20:25:15 +00001013{
Harald Welte8470bf22008-12-25 23:28:35 +00001014 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001015 struct gsm48_hdr *gh;
1016
Harald Welte8470bf22008-12-25 23:28:35 +00001017 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001018
1019 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1020 gh->proto_discr = GSM48_PDISC_MM;
Harald Welte10b487b2008-12-27 19:53:37 +00001021 gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
Harald Welte52b1f982008-12-23 20:25:15 +00001022 gh->data[0] = cause;
1023
Harald Weltedb253af2008-12-30 17:56:55 +00001024 DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
1025
Harald Welte39e2ead2009-07-23 21:13:03 +02001026 return gsm48_sendmsg(msg, NULL);
Harald Welte52b1f982008-12-23 20:25:15 +00001027}
1028
1029/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
Harald Welte75a983f2008-12-27 21:34:06 +00001030int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +00001031{
Harald Welte8470bf22008-12-25 23:28:35 +00001032 struct gsm_bts *bts = lchan->ts->trx->bts;
1033 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001034 struct gsm48_hdr *gh;
1035 struct gsm48_loc_area_id *lai;
1036 u_int8_t *mid;
Holger Freyther07cc8d82008-12-29 06:23:46 +00001037 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001038
Harald Welte8470bf22008-12-25 23:28:35 +00001039 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001040
1041 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1042 gh->proto_discr = GSM48_PDISC_MM;
1043 gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
1044
1045 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
Holger Freyther17746612008-12-28 16:32:44 +00001046 gsm0408_generate_lai(lai, bts->network->country_code,
Harald Welte52b1f982008-12-23 20:25:15 +00001047 bts->network->network_code, bts->location_area_code);
1048
1049 mid = msgb_put(msg, MID_TMSI_LEN);
1050 generate_mid_from_tmsi(mid, tmsi);
1051
1052 DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
1053
Harald Welte39e2ead2009-07-23 21:13:03 +02001054 ret = gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001055
Harald Weltedb253af2008-12-30 17:56:55 +00001056 ret = gsm48_tx_mm_info(lchan);
Harald Weltedb253af2008-12-30 17:56:55 +00001057
Holger Freyther07cc8d82008-12-29 06:23:46 +00001058 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001059}
1060
Harald Weltefc977a82008-12-27 10:19:37 +00001061static char bcd2char(u_int8_t bcd)
1062{
1063 if (bcd < 0xa)
1064 return '0' + bcd;
1065 else
1066 return 'A' + (bcd - 0xa);
1067}
1068
Harald Weltebf5e8df2009-02-03 12:59:45 +00001069/* Convert Mobile Identity (10.5.1.4) to string */
Harald Weltefc977a82008-12-27 10:19:37 +00001070static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
1071{
1072 int i;
1073 u_int8_t mi_type;
1074 char *str_cur = string;
Harald Welte4ed0e922009-01-10 03:17:30 +00001075 u_int32_t tmsi;
Harald Weltefc977a82008-12-27 10:19:37 +00001076
1077 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1078
1079 switch (mi_type) {
1080 case GSM_MI_TYPE_NONE:
1081 break;
1082 case GSM_MI_TYPE_TMSI:
Harald Welte4ed0e922009-01-10 03:17:30 +00001083 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
1084 if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
1085 memcpy(&tmsi, &mi[1], 4);
1086 tmsi = ntohl(tmsi);
1087 return snprintf(string, str_len, "%u", tmsi);
Harald Weltefc977a82008-12-27 10:19:37 +00001088 }
1089 break;
1090 case GSM_MI_TYPE_IMSI:
1091 case GSM_MI_TYPE_IMEI:
1092 case GSM_MI_TYPE_IMEISV:
Harald Weltedb253af2008-12-30 17:56:55 +00001093 *str_cur++ = bcd2char(mi[0] >> 4);
1094
1095 for (i = 1; i < mi_len; i++) {
Harald Weltefc977a82008-12-27 10:19:37 +00001096 if (str_cur + 2 >= string + str_len)
1097 return str_cur - string;
1098 *str_cur++ = bcd2char(mi[i] & 0xf);
Harald Weltedb253af2008-12-30 17:56:55 +00001099 /* skip last nibble in last input byte when GSM_EVEN */
1100 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
1101 *str_cur++ = bcd2char(mi[i] >> 4);
Harald Weltefc977a82008-12-27 10:19:37 +00001102 }
1103 break;
1104 default:
1105 break;
1106 }
Harald Weltefc977a82008-12-27 10:19:37 +00001107 *str_cur++ = '\0';
Harald Weltedb253af2008-12-30 17:56:55 +00001108
Harald Weltefc977a82008-12-27 10:19:37 +00001109 return str_cur - string;
1110}
1111
Harald Weltebf5e8df2009-02-03 12:59:45 +00001112/* Transmit Chapter 9.2.10 Identity Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001113static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
1114{
1115 struct msgb *msg = gsm48_msgb_alloc();
1116 struct gsm48_hdr *gh;
Harald Weltefc977a82008-12-27 10:19:37 +00001117
Harald Welte231ad4f2008-12-27 11:15:38 +00001118 msg->lchan = lchan;
1119
1120 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1121 gh->proto_discr = GSM48_PDISC_MM;
1122 gh->msg_type = GSM48_MT_MM_ID_REQ;
1123 gh->data[0] = id_type;
1124
Harald Welte39e2ead2009-07-23 21:13:03 +02001125 return gsm48_sendmsg(msg, NULL);
Harald Welte231ad4f2008-12-27 11:15:38 +00001126}
1127
1128#define MI_SIZE 32
1129
Harald Weltebf5e8df2009-02-03 12:59:45 +00001130/* Parse Chapter 9.2.11 Identity Response */
Harald Welte231ad4f2008-12-27 11:15:38 +00001131static int mm_rx_id_resp(struct msgb *msg)
1132{
1133 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte75a983f2008-12-27 21:34:06 +00001134 struct gsm_lchan *lchan = msg->lchan;
Harald Welte761e9442009-07-23 19:21:02 +02001135 struct gsm_bts *bts = lchan->ts->trx->bts;
1136 struct gsm_network *net = bts->network;
Harald Welte231ad4f2008-12-27 11:15:38 +00001137 u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
1138 char mi_string[MI_SIZE];
1139
1140 mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
Harald Welte61253062008-12-27 11:25:50 +00001141 DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
Harald Welte231ad4f2008-12-27 11:15:38 +00001142 mi_type, mi_string);
1143
Harald Welte75a983f2008-12-27 21:34:06 +00001144 switch (mi_type) {
1145 case GSM_MI_TYPE_IMSI:
1146 if (!lchan->subscr)
Harald Welte761e9442009-07-23 19:21:02 +02001147 lchan->subscr = db_create_subscriber(net, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001148 if (lchan->loc_operation)
1149 lchan->loc_operation->waiting_for_imsi = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001150 break;
1151 case GSM_MI_TYPE_IMEI:
Harald Welte255539c2008-12-28 02:26:27 +00001152 case GSM_MI_TYPE_IMEISV:
Harald Welte75a983f2008-12-27 21:34:06 +00001153 /* update subscribe <-> IMEI mapping */
1154 if (lchan->subscr)
1155 db_subscriber_assoc_imei(lchan->subscr, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001156 if (lchan->loc_operation)
1157 lchan->loc_operation->waiting_for_imei = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001158 break;
1159 }
Holger Freyther73487a22008-12-31 18:53:57 +00001160
1161 /* Check if we can let the mobile station enter */
Holger Freytherd51524f2009-06-09 08:27:07 +00001162 return gsm0408_authorize(lchan, msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001163}
1164
Harald Welte255539c2008-12-28 02:26:27 +00001165
1166static void loc_upd_rej_cb(void *data)
1167{
1168 struct gsm_lchan *lchan = data;
1169
Holger Freyther73487a22008-12-31 18:53:57 +00001170 release_loc_updating_req(lchan);
Holger Freythere97f7fb2008-12-31 18:52:11 +00001171 gsm0408_loc_upd_rej(lchan, reject_cause);
Holger Freyther67b4b9a2009-01-01 03:46:11 +00001172 lchan_auto_release(lchan);
Harald Welte255539c2008-12-28 02:26:27 +00001173}
1174
Holger Freytherb7193e42008-12-29 17:44:08 +00001175static void schedule_reject(struct gsm_lchan *lchan)
1176{
Holger Freyther73487a22008-12-31 18:53:57 +00001177 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1178 lchan->loc_operation->updating_timer.data = lchan;
Harald Welteff117a82009-05-23 05:22:08 +00001179 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
Holger Freytherb7193e42008-12-29 17:44:08 +00001180}
1181
Harald Welte2a139372009-02-22 21:14:55 +00001182static const char *lupd_name(u_int8_t type)
1183{
1184 switch (type) {
1185 case GSM48_LUPD_NORMAL:
1186 return "NORMAL";
1187 case GSM48_LUPD_PERIODIC:
1188 return "PEROIDOC";
1189 case GSM48_LUPD_IMSI_ATT:
1190 return "IMSI ATTACH";
1191 default:
1192 return "UNKNOWN";
1193 }
1194}
1195
Harald Welte231ad4f2008-12-27 11:15:38 +00001196#define MI_SIZE 32
Harald Weltebf5e8df2009-02-03 12:59:45 +00001197/* Chapter 9.2.15: Receive Location Updating Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001198static int mm_rx_loc_upd_req(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001199{
Harald Welte8470bf22008-12-25 23:28:35 +00001200 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001201 struct gsm48_loc_upd_req *lu;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001202 struct gsm_subscriber *subscr = NULL;
Harald Welte255539c2008-12-28 02:26:27 +00001203 struct gsm_lchan *lchan = msg->lchan;
Harald Welte761e9442009-07-23 19:21:02 +02001204 struct gsm_bts *bts = lchan->ts->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +00001205 u_int8_t mi_type;
Harald Welte231ad4f2008-12-27 11:15:38 +00001206 char mi_string[MI_SIZE];
1207 int rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001208
Harald Welte8470bf22008-12-25 23:28:35 +00001209 lu = (struct gsm48_loc_upd_req *) gh->data;
1210
1211 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
Harald Welte52b1f982008-12-23 20:25:15 +00001212
Harald Weltefc977a82008-12-27 10:19:37 +00001213 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1214
Harald Weltea0368542009-06-27 02:58:43 +02001215 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte2a139372009-02-22 21:14:55 +00001216 lupd_name(lu->type));
Holger Freyther73487a22008-12-31 18:53:57 +00001217
Holger Freythereaf04692009-06-06 13:54:44 +00001218 /*
1219 * Pseudo Spoof detection: Just drop a second/concurrent
1220 * location updating request.
1221 */
1222 if (lchan->loc_operation) {
Harald Weltea0368542009-06-27 02:58:43 +02001223 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Holger Freythereaf04692009-06-06 13:54:44 +00001224 lchan->loc_operation);
1225 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1226 return 0;
1227 }
1228
Holger Freyther73487a22008-12-31 18:53:57 +00001229 allocate_loc_updating_req(lchan);
1230
Harald Welte52b1f982008-12-23 20:25:15 +00001231 switch (mi_type) {
1232 case GSM_MI_TYPE_IMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001233 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001234 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001235 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001236 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001237
Harald Welte52b1f982008-12-23 20:25:15 +00001238 /* look up subscriber based on IMSI */
Harald Welte761e9442009-07-23 19:21:02 +02001239 subscr = db_create_subscriber(bts->network, mi_string);
Harald Welte4b634542008-12-27 01:55:51 +00001240 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001241 case GSM_MI_TYPE_TMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001242 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001243 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001244 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001245 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001246
Harald Welte52b1f982008-12-23 20:25:15 +00001247 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welte761e9442009-07-23 19:21:02 +02001248 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte52b1f982008-12-23 20:25:15 +00001249 if (!subscr) {
Harald Welte231ad4f2008-12-27 11:15:38 +00001250 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte255539c2008-12-28 02:26:27 +00001251 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
Holger Freyther73487a22008-12-31 18:53:57 +00001252 lchan->loc_operation->waiting_for_imsi = 1;
Harald Welte52b1f982008-12-23 20:25:15 +00001253 }
1254 break;
1255 case GSM_MI_TYPE_IMEI:
1256 case GSM_MI_TYPE_IMEISV:
1257 /* no sim card... FIXME: what to do ? */
Harald Weltea0368542009-06-27 02:58:43 +02001258 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001259 break;
1260 default:
Harald Weltea0368542009-06-27 02:58:43 +02001261 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001262 break;
1263 }
1264
Harald Welte24516ea2009-07-04 10:18:00 +02001265 /* schedule the reject timer */
1266 schedule_reject(lchan);
1267
Harald Welte4bfdfe72009-06-10 23:11:52 +08001268 if (!subscr) {
Harald Weltea0368542009-06-27 02:58:43 +02001269 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001270 /* FIXME: request id? close channel? */
1271 return -EINVAL;
1272 }
1273
Harald Welte255539c2008-12-28 02:26:27 +00001274 lchan->subscr = subscr;
1275
Harald Welte24516ea2009-07-04 10:18:00 +02001276 /* check if we can let the subscriber into our network immediately
1277 * or if we need to wait for identity responses. */
Holger Freytherd51524f2009-06-09 08:27:07 +00001278 return gsm0408_authorize(lchan, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001279}
1280
Harald Welte7584aea2009-02-11 11:44:12 +00001281/* 9.1.5 Channel mode modify */
1282int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1283{
1284 struct msgb *msg = gsm48_msgb_alloc();
1285 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1286 struct gsm48_chan_mode_modify *cmm =
1287 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
Harald Welte4a543e82009-02-28 13:17:55 +00001288 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
Harald Welte7584aea2009-02-11 11:44:12 +00001289
Harald Welte4a543e82009-02-28 13:17:55 +00001290 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
Harald Welte7ccf7782009-02-17 01:43:01 +00001291
Harald Welte45b407a2009-05-23 15:51:12 +00001292 lchan->tch_mode = mode;
Harald Welte7584aea2009-02-11 11:44:12 +00001293 msg->lchan = lchan;
1294 gh->proto_discr = GSM48_PDISC_RR;
1295 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1296
1297 /* fill the channel information element, this code
1298 * should probably be shared with rsl_rx_chan_rqd() */
1299 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte02b0e092009-02-28 13:11:07 +00001300 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
Harald Welte7584aea2009-02-11 11:44:12 +00001301 cmm->chan_desc.h0.h = 0;
1302 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1303 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1304 cmm->mode = mode;
1305
Harald Welte39e2ead2009-07-23 21:13:03 +02001306 return gsm48_sendmsg(msg, NULL);
Harald Welte7584aea2009-02-11 11:44:12 +00001307}
1308
Harald Welte4bfdfe72009-06-10 23:11:52 +08001309#if 0
1310static u_int8_t to_bcd8(u_int8_t val)
1311{
1312 return ((val / 10) << 4) | (val % 10);
1313}
1314#endif
1315
Harald Weltedb253af2008-12-30 17:56:55 +00001316/* Section 9.2.15a */
1317int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1318{
1319 struct msgb *msg = gsm48_msgb_alloc();
1320 struct gsm48_hdr *gh;
1321 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Weltedb253af2008-12-30 17:56:55 +00001322 u_int8_t *ptr8;
1323 u_int16_t *ptr16;
1324 int name_len;
Harald Weltedb253af2008-12-30 17:56:55 +00001325 int i;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001326#if 0
1327 time_t cur_t;
1328 struct tm* cur_time;
1329 int tz15min;
1330#endif
Harald Weltedb253af2008-12-30 17:56:55 +00001331
1332 msg->lchan = lchan;
1333
1334 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1335 gh->proto_discr = GSM48_PDISC_MM;
1336 gh->msg_type = GSM48_MT_MM_INFO;
1337
1338 if (net->name_long) {
1339 name_len = strlen(net->name_long);
1340 /* 10.5.3.5a */
1341 ptr8 = msgb_put(msg, 3);
1342 ptr8[0] = GSM48_IE_NAME_LONG;
1343 ptr8[1] = name_len*2 +1;
1344 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1345
1346 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1347 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001348 ptr16[i] = htons(net->name_long[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001349
1350 /* FIXME: Use Cell Broadcast, not UCS-2, since
1351 * UCS-2 is only supported by later revisions of the spec */
1352 }
1353
1354 if (net->name_short) {
1355 name_len = strlen(net->name_short);
1356 /* 10.5.3.5a */
1357 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Welte7543eb72009-07-19 17:51:36 +02001358 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Weltedb253af2008-12-30 17:56:55 +00001359 ptr8[1] = name_len*2 + 1;
1360 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1361
Harald Weltee872cb12009-01-01 00:33:37 +00001362 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
Harald Weltedb253af2008-12-30 17:56:55 +00001363 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001364 ptr16[i] = htons(net->name_short[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001365 }
1366
1367#if 0
1368 /* Section 10.5.3.9 */
1369 cur_t = time(NULL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001370 cur_time = gmtime(&cur_t);
Harald Weltedb253af2008-12-30 17:56:55 +00001371 ptr8 = msgb_put(msg, 8);
1372 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1373 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1374 ptr8[2] = to_bcd8(cur_time->tm_mon);
1375 ptr8[3] = to_bcd8(cur_time->tm_mday);
1376 ptr8[4] = to_bcd8(cur_time->tm_hour);
1377 ptr8[5] = to_bcd8(cur_time->tm_min);
1378 ptr8[6] = to_bcd8(cur_time->tm_sec);
1379 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1380 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001381 ptr8[7] = to_bcd8(tz15min);
Harald Weltedb253af2008-12-30 17:56:55 +00001382 if (tz15min < 0)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001383 ptr8[7] |= 0x80;
Harald Weltedb253af2008-12-30 17:56:55 +00001384#endif
1385
Harald Welte39e2ead2009-07-23 21:13:03 +02001386 return gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001387}
1388
Harald Welte4b634542008-12-27 01:55:51 +00001389static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1390{
Harald Welte4b634542008-12-27 01:55:51 +00001391 DEBUGP(DMM, "-> CM SERVICE ACK\n");
Harald Welte65e74cc2008-12-29 01:55:35 +00001392 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
Harald Welte4b634542008-12-27 01:55:51 +00001393}
Harald Welteba4cf162009-01-10 01:49:35 +00001394
1395/* 9.2.6 CM service reject */
1396static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1397 enum gsm48_reject_value value)
1398{
1399 struct msgb *msg = gsm48_msgb_alloc();
1400 struct gsm48_hdr *gh;
1401
1402 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1403
1404 msg->lchan = lchan;
1405 use_lchan(lchan);
1406
1407 gh->proto_discr = GSM48_PDISC_MM;
1408 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1409 gh->data[0] = value;
1410 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1411
Harald Welte39e2ead2009-07-23 21:13:03 +02001412 return gsm48_sendmsg(msg, NULL);
Harald Welteba4cf162009-01-10 01:49:35 +00001413}
1414
Harald Welte4ed0e922009-01-10 03:17:30 +00001415
1416/*
1417 * Handle CM Service Requests
1418 * a) Verify that the packet is long enough to contain the information
1419 * we require otherwsie reject with INCORRECT_MESSAGE
1420 * b) Try to parse the TMSI. If we do not have one reject
1421 * c) Check that we know the subscriber with the TMSI otherwise reject
1422 * with a HLR cause
1423 * d) Set the subscriber on the gsm_lchan and accept
1424 */
Harald Welte4b634542008-12-27 01:55:51 +00001425static int gsm48_rx_mm_serv_req(struct msgb *msg)
1426{
Harald Welteba4cf162009-01-10 01:49:35 +00001427 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001428 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001429
Harald Welte761e9442009-07-23 19:21:02 +02001430 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welteba4cf162009-01-10 01:49:35 +00001431 struct gsm_subscriber *subscr;
1432 struct gsm48_hdr *gh = msgb_l3(msg);
1433 struct gsm48_service_request *req =
1434 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001435 /* unfortunately in Phase1 the classmar2 length is variable */
1436 u_int8_t classmark2_len = gh->data[1];
1437 u_int8_t *classmark2 = gh->data+2;
1438 u_int8_t mi_len = *(classmark2 + classmark2_len);
1439 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001440
Harald Weltec9e02182009-05-01 19:07:53 +00001441 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001442 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001443 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001444 return gsm48_tx_mm_serv_rej(msg->lchan,
1445 GSM48_REJECT_INCORRECT_MESSAGE);
1446 }
1447
1448 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001449 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001450 return gsm48_tx_mm_serv_rej(msg->lchan,
1451 GSM48_REJECT_INCORRECT_MESSAGE);
1452 }
1453
Harald Weltec9e02182009-05-01 19:07:53 +00001454 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001455 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001456 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001457 return gsm48_tx_mm_serv_rej(msg->lchan,
1458 GSM48_REJECT_INCORRECT_MESSAGE);
1459 }
1460
Harald Weltec9e02182009-05-01 19:07:53 +00001461 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001462 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001463 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001464
Harald Welte761e9442009-07-23 19:21:02 +02001465 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Holger Freythereb443982009-06-04 13:58:42 +00001466
Harald Welte2a139372009-02-22 21:14:55 +00001467 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001468 if (!subscr)
1469 return gsm48_tx_mm_serv_rej(msg->lchan,
1470 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1471
1472 if (!msg->lchan->subscr)
1473 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001474 else if (msg->lchan->subscr != subscr) {
1475 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1476 subscr_put(subscr);
1477 }
1478
Harald Weltec2e302d2009-07-05 14:08:13 +02001479 subscr->equipment.classmark2_len = classmark2_len;
1480 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1481 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001482
Harald Welte4b634542008-12-27 01:55:51 +00001483 return gsm48_tx_mm_serv_ack(msg->lchan);
1484}
1485
Harald Welte2a139372009-02-22 21:14:55 +00001486static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1487{
Harald Welte761e9442009-07-23 19:21:02 +02001488 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2a139372009-02-22 21:14:55 +00001489 struct gsm48_hdr *gh = msgb_l3(msg);
1490 struct gsm48_imsi_detach_ind *idi =
1491 (struct gsm48_imsi_detach_ind *) gh->data;
1492 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1493 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001494 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001495
1496 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1497 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1498 mi_type, mi_string);
1499
1500 switch (mi_type) {
1501 case GSM_MI_TYPE_TMSI:
Harald Welte761e9442009-07-23 19:21:02 +02001502 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001503 break;
1504 case GSM_MI_TYPE_IMSI:
Harald Welte761e9442009-07-23 19:21:02 +02001505 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001506 break;
1507 case GSM_MI_TYPE_IMEI:
1508 case GSM_MI_TYPE_IMEISV:
1509 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001510 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001511 break;
1512 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001513 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001514 break;
1515 }
1516
Holger Freyther4a49e772009-04-12 05:37:29 +00001517 if (subscr) {
1518 subscr_update(subscr, msg->trx->bts,
1519 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001520 DEBUGP(DMM, "Subscriber: %s\n",
1521 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001522 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001523 } else
Harald Welte2a139372009-02-22 21:14:55 +00001524 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1525
Harald Welte2a139372009-02-22 21:14:55 +00001526 return 0;
1527}
1528
Harald Welted2a7f5a2009-06-05 20:08:20 +00001529static int gsm48_rx_mm_status(struct msgb *msg)
1530{
1531 struct gsm48_hdr *gh = msgb_l3(msg);
1532
1533 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1534
1535 return 0;
1536}
1537
Harald Weltebf5e8df2009-02-03 12:59:45 +00001538/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001539static int gsm0408_rcv_mm(struct msgb *msg)
1540{
1541 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001542 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001543
1544 switch (gh->msg_type & 0xbf) {
1545 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001546 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001547 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001548 break;
1549 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001550 rc = mm_rx_id_resp(msg);
1551 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001552 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001553 rc = gsm48_rx_mm_serv_req(msg);
1554 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001555 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001556 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001557 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001558 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001559 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1560 msg->lchan->subscr ?
1561 msg->lchan->subscr->imsi :
1562 "unknown subscriber");
1563 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001564 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001565 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1566 break;
1567 case GSM48_MT_MM_CM_REEST_REQ:
1568 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1569 break;
1570 case GSM48_MT_MM_AUTH_RESP:
1571 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001572 break;
1573 default:
1574 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1575 gh->msg_type);
1576 break;
1577 }
1578
1579 return rc;
1580}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001581
Harald Welte2d35ae62009-02-06 12:02:13 +00001582/* Receive a PAGING RESPONSE message from the MS */
1583static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1584{
Harald Welte761e9442009-07-23 19:21:02 +02001585 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2d35ae62009-02-06 12:02:13 +00001586 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001587 u_int8_t *classmark2_lv = gh->data + 1;
1588 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1589 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001590 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001591 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001592 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001593 int rc = 0;
1594
Harald Welte61548982009-02-22 21:26:29 +00001595 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001596 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1597 mi_type, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001598 switch (mi_type) {
1599 case GSM_MI_TYPE_TMSI:
Harald Welte761e9442009-07-23 19:21:02 +02001600 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001601 break;
1602 case GSM_MI_TYPE_IMSI:
Harald Welte761e9442009-07-23 19:21:02 +02001603 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001604 break;
1605 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001606
1607 if (!subscr) {
1608 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001609 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001610 return -EINVAL;
1611 }
1612 DEBUGP(DRR, "<- Channel was requested by %s\n",
1613 subscr->name ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001614
Harald Weltec2e302d2009-07-05 14:08:13 +02001615 subscr->equipment.classmark2_len = *classmark2_lv;
1616 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1617 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001618
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001619 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001620 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001621 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001622 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1623 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001624 return -EINVAL;
1625 } else {
1626 DEBUGP(DRR, "<- Channel already owned by us\n");
1627 subscr_put(subscr);
1628 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001629 }
1630
Harald Welte595ad7b2009-02-16 22:05:44 +00001631 sig_data.subscr = subscr;
1632 sig_data.bts = msg->lchan->ts->trx->bts;
1633 sig_data.lchan = msg->lchan;
1634
1635 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001636
1637 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001638 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001639
Harald Welte7584aea2009-02-11 11:44:12 +00001640 /* FIXME: somehow signal the completion of the PAGING to
1641 * the entity that requested the paging */
1642
Harald Welte2d35ae62009-02-06 12:02:13 +00001643 return rc;
1644}
1645
Harald Weltef7c43522009-06-09 20:24:21 +00001646static int gsm48_rx_rr_classmark(struct msgb *msg)
1647{
1648 struct gsm48_hdr *gh = msgb_l3(msg);
1649 struct gsm_subscriber *subscr = msg->lchan->subscr;
1650 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1651 u_int8_t cm2_len, cm3_len = 0;
1652 u_int8_t *cm2, *cm3 = NULL;
1653
1654 DEBUGP(DRR, "CLASSMARK CHANGE ");
1655
1656 /* classmark 2 */
1657 cm2_len = gh->data[0];
1658 cm2 = &gh->data[1];
1659 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1660
1661 if (payload_len > cm2_len + 1) {
1662 /* we must have a classmark3 */
1663 if (gh->data[cm2_len+1] != 0x20) {
1664 DEBUGPC(DRR, "ERR CM3 TAG\n");
1665 return -EINVAL;
1666 }
1667 if (cm2_len > 3) {
1668 DEBUGPC(DRR, "CM2 too long!\n");
1669 return -EINVAL;
1670 }
1671
1672 cm3_len = gh->data[cm2_len+2];
1673 cm3 = &gh->data[cm2_len+3];
1674 if (cm3_len > 14) {
1675 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1676 return -EINVAL;
1677 }
1678 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1679 }
1680 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001681 subscr->equipment.classmark2_len = cm2_len;
1682 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001683 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001684 subscr->equipment.classmark3_len = cm3_len;
1685 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001686 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001687 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001688 }
1689
Harald Weltef7c43522009-06-09 20:24:21 +00001690 return 0;
1691}
1692
Harald Weltecf5b3592009-05-01 18:28:42 +00001693static int gsm48_rx_rr_status(struct msgb *msg)
1694{
1695 struct gsm48_hdr *gh = msgb_l3(msg);
1696
1697 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1698 rr_cause_name(gh->data[0]));
1699
1700 return 0;
1701}
1702
Harald Weltef7c43522009-06-09 20:24:21 +00001703static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1704{
1705 struct gsm48_hdr *gh = msgb_l3(msg);
1706 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1707 static struct gsm_meas_rep meas_rep;
1708
Harald Welte10d0e672009-06-27 02:53:10 +02001709 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001710 parse_meas_rep(&meas_rep, gh->data, payload_len);
1711 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001712 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001713 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001714 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001715 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001716 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001717 else
Harald Welte10d0e672009-06-27 02:53:10 +02001718 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001719 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1720 meas_rep.rxqual_sub);
1721
Harald Welte10d0e672009-06-27 02:53:10 +02001722 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001723
1724 /* FIXME: put the results somwhere */
1725
1726 return 0;
1727}
1728
Harald Weltebf5e8df2009-02-03 12:59:45 +00001729/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001730static int gsm0408_rcv_rr(struct msgb *msg)
1731{
1732 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001733 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001734
1735 switch (gh->msg_type) {
1736 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001737 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001738 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001739 case GSM48_MT_RR_GPRS_SUSP_REQ:
1740 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1741 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001742 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001743 rc = gsm48_rr_rx_pag_resp(msg);
1744 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001745 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1746 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte2c38aa82009-02-18 03:44:24 +00001747 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001748 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001749 case GSM48_MT_RR_STATUS:
1750 rc = gsm48_rx_rr_status(msg);
1751 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001752 case GSM48_MT_RR_MEAS_REP:
1753 rc = gsm48_rx_rr_meas_rep(msg);
1754 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001755 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001756 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001757 gh->msg_type);
1758 break;
1759 }
1760
Harald Welte2d35ae62009-02-06 12:02:13 +00001761 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001762}
1763
Holger Freythere64a7a32009-02-06 21:55:37 +00001764/* 7.1.7 and 9.1.7 Channel release*/
1765int gsm48_send_rr_release(struct gsm_lchan *lchan)
1766{
1767 struct msgb *msg = gsm48_msgb_alloc();
1768 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1769 u_int8_t *cause;
1770
1771 msg->lchan = lchan;
1772 gh->proto_discr = GSM48_PDISC_RR;
1773 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1774
1775 cause = msgb_put(msg, 1);
1776 cause[0] = GSM48_RR_CAUSE_NORMAL;
1777
1778 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1779 lchan->nr, lchan->type);
1780
Harald Welteae0f2362009-07-19 18:36:49 +02001781 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001782 gsm48_sendmsg(msg, NULL);
Harald Welteae0f2362009-07-19 18:36:49 +02001783
1784 /* Deactivate the SACCH on the BTS side */
1785 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001786}
1787
Harald Welte4bc90a12008-12-27 16:32:52 +00001788/* Call Control */
1789
Harald Welte7584aea2009-02-11 11:44:12 +00001790/* The entire call control code is written in accordance with Figure 7.10c
1791 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1792 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1793 * it for voice */
1794
Harald Welte4bfdfe72009-06-10 23:11:52 +08001795static void new_cc_state(struct gsm_trans *trans, int state)
1796{
1797 if (state > 31 || state < 0)
1798 return;
1799
1800 DEBUGP(DCC, "new state %s -> %s\n",
Harald Welteaa0b29c2009-07-23 18:56:43 +02001801 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001802
Harald Welteaa0b29c2009-07-23 18:56:43 +02001803 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001804}
1805
1806static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001807{
1808 struct msgb *msg = gsm48_msgb_alloc();
1809 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1810 u_int8_t *cause, *call_state;
1811
Harald Welte4bc90a12008-12-27 16:32:52 +00001812 gh->msg_type = GSM48_MT_CC_STATUS;
1813
1814 cause = msgb_put(msg, 3);
1815 cause[0] = 2;
1816 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1817 cause[2] = 0x80 | 30; /* response to status inquiry */
1818
1819 call_state = msgb_put(msg, 1);
1820 call_state[0] = 0xc0 | 0x00;
1821
Harald Welte39e2ead2009-07-23 21:13:03 +02001822 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001823}
1824
Harald Welte6f4b7532008-12-29 00:39:37 +00001825static int gsm48_tx_simple(struct gsm_lchan *lchan,
1826 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001827{
1828 struct msgb *msg = gsm48_msgb_alloc();
1829 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1830
1831 msg->lchan = lchan;
1832
Harald Welte6f4b7532008-12-29 00:39:37 +00001833 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001834 gh->msg_type = msg_type;
1835
Harald Welte39e2ead2009-07-23 21:13:03 +02001836 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001837}
1838
Harald Welte4bfdfe72009-06-10 23:11:52 +08001839static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1840{
Harald Welteaa0b29c2009-07-23 18:56:43 +02001841 if (bsc_timer_pending(&trans->cc.timer)) {
1842 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1843 bsc_del_timer(&trans->cc.timer);
1844 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001845 }
1846}
1847
1848static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1849 int msg_type, struct gsm_mncc *mncc)
1850{
1851 struct msgb *msg;
1852
1853 if (trans)
1854 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001855 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001856 "Sending '%s' to MNCC.\n",
1857 trans->lchan->ts->trx->bts->nr,
1858 trans->lchan->ts->trx->nr,
1859 trans->lchan->ts->nr, trans->transaction_id,
1860 (trans->subscr)?(trans->subscr->extension):"-",
1861 get_mncc_name(msg_type));
1862 else
1863 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1864 "Sending '%s' to MNCC.\n",
1865 (trans->subscr)?(trans->subscr->extension):"-",
1866 get_mncc_name(msg_type));
1867 else
1868 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1869 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1870
1871 mncc->msg_type = msg_type;
1872
Harald Welte966636f2009-06-26 19:39:35 +02001873 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001874 if (!msg)
1875 return -ENOMEM;
1876 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1877 msgb_enqueue(&net->upqueue, msg);
1878
1879 return 0;
1880}
1881
1882int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1883 u_int32_t callref, int location, int value)
1884{
1885 struct gsm_mncc rel;
1886
Harald Welte92f70c52009-06-12 01:54:08 +08001887 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001888 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001889 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001890 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1891}
1892
Harald Welteaa0b29c2009-07-23 18:56:43 +02001893/* Call Control Specific transaction release.
1894 * gets called by trans_free, DO NOT CALL YOURSELF! */
1895void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001896{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001897 gsm48_stop_cc_timer(trans);
1898
1899 /* send release to L4, if callref still exists */
1900 if (trans->callref) {
1901 /* Ressource unavailable */
Harald Welteb3c3fae2009-07-23 19:06:52 +02001902 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001903 GSM48_CAUSE_LOC_PRN_S_LU,
1904 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001905 }
Harald Welteaa0b29c2009-07-23 18:56:43 +02001906 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001907 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Welteaa0b29c2009-07-23 18:56:43 +02001908 if (trans->lchan)
1909 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001910}
1911
1912static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1913
Harald Welte09e38af2009-02-16 22:52:23 +00001914/* call-back from paging the B-end of the connection */
1915static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001916 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001917{
Harald Welte7ccf7782009-02-17 01:43:01 +00001918 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001919 struct gsm_subscriber *subscr = param;
1920 struct gsm_trans *transt, *tmp;
1921 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001922
Harald Welte09e38af2009-02-16 22:52:23 +00001923 if (hooknum != GSM_HOOK_RR_PAGING)
1924 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001925
1926 if (!subscr)
1927 return -EINVAL;
1928 net = subscr->net;
1929 if (!net) {
1930 DEBUGP(DCC, "Error Network not set!\n");
1931 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00001932 }
Harald Welte7584aea2009-02-11 11:44:12 +00001933
Harald Welte4bfdfe72009-06-10 23:11:52 +08001934 /* check all tranactions (without lchan) for subscriber */
1935 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1936 if (transt->subscr != subscr || transt->lchan)
1937 continue;
1938 switch (event) {
1939 case GSM_PAGING_SUCCEEDED:
1940 if (!lchan) // paranoid
1941 break;
1942 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1943 subscr->extension);
1944 /* Assign lchan */
1945 if (!transt->lchan) {
1946 transt->lchan = lchan;
1947 use_lchan(lchan);
1948 }
1949 /* send SETUP request to called party */
Harald Welteaa0b29c2009-07-23 18:56:43 +02001950 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001951 if (is_ipaccess_bts(lchan->ts->trx->bts))
1952 rsl_ipacc_bind(lchan);
1953 break;
1954 case GSM_PAGING_EXPIRED:
1955 DEBUGP(DCC, "Paging subscr %s expired!\n",
1956 subscr->extension);
1957 /* Temporarily out of order */
Harald Welteb3c3fae2009-07-23 19:06:52 +02001958 mncc_release_ind(transt->subscr->net, transt,
1959 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001960 GSM48_CAUSE_LOC_PRN_S_LU,
1961 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001962 transt->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02001963 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001964 break;
1965 }
1966 }
Harald Welte09e38af2009-02-16 22:52:23 +00001967 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00001968}
Harald Welte7584aea2009-02-11 11:44:12 +00001969
Harald Welte805f6442009-07-28 18:25:29 +02001970/* some other part of the code sends us a signal */
1971static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
1972 void *handler_data, void *signal_data)
1973{
1974 struct gsm_lchan *lchan = signal_data;
1975 struct gsm_bts_trx_ts *ts;
1976 int rc;
1977
1978 if (subsys != SS_ABISIP)
1979 return 0;
1980
1981 /* in case we use direct BTS-to-BTS RTP */
1982 if (ipacc_rtp_direct)
1983 return 0;
1984
1985 ts = lchan->ts;
1986
1987 switch (signal) {
1988 case S_ABISIP_BIND_ACK:
1989 /* the BTS has successfully bound a TCH to a local ip/port,
1990 * which means we can connect our UDP socket to it */
1991 if (ts->abis_ip.rtp_socket) {
1992 rtp_socket_free(ts->abis_ip.rtp_socket);
1993 ts->abis_ip.rtp_socket = NULL;
1994 }
1995
1996 ts->abis_ip.rtp_socket = rtp_socket_create();
1997 if (!ts->abis_ip.rtp_socket)
1998 goto out_err;
1999
2000 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2001 ts->abis_ip.bound_ip,
2002 ts->abis_ip.bound_port);
2003 if (rc < 0)
2004 goto out_err;
2005 break;
2006 case S_ABISIP_DISC_IND:
2007 /* the BTS tells us a RTP stream has been disconnected */
2008 if (ts->abis_ip.rtp_socket) {
2009 rtp_socket_free(ts->abis_ip.rtp_socket);
2010 ts->abis_ip.rtp_socket = NULL;
2011 }
2012 break;
2013 }
2014
2015 return 0;
2016out_err:
2017 /* FIXME: do something */
2018 return 0;
2019}
2020
2021/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2022static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2023{
2024 struct gsm_bts_trx_ts *ts = lchan->ts;
2025 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2026 int rc;
2027
2028 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2029 ntohs(rs->rtp.sin_local.sin_port),
2030 ts->abis_ip.conn_id,
2031 /* FIXME: use RTP payload of bound socket, not BTS*/
2032 ts->abis_ip.rtp_payload2);
2033
2034 return rc;
2035}
2036
Harald Welte49f48b82009-02-17 15:29:33 +00002037/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002038static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002039{
Harald Welte11fa29c2009-02-19 17:24:39 +00002040 struct gsm_bts *bts = lchan->ts->trx->bts;
2041 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002042 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002043 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002044
Harald Welte11fa29c2009-02-19 17:24:39 +00002045 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2046 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2047 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2048
2049 if (bts->type != remote_bts->type) {
2050 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2051 return -EINVAL;
2052 }
Harald Welte49f48b82009-02-17 15:29:33 +00002053
Harald Welte11fa29c2009-02-19 17:24:39 +00002054 switch (bts->type) {
2055 case GSM_BTS_TYPE_NANOBTS_900:
2056 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002057 if (!ipacc_rtp_direct) {
2058 /* connect the TCH's to our RTP proxy */
2059 rc = ipacc_connect_proxy_bind(lchan);
2060 if (rc < 0)
2061 return rc;
2062 rc = ipacc_connect_proxy_bind(remote_lchan);
2063
2064 /* connect them with each other */
2065 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2066 remote_lchan->ts->abis_ip.rtp_socket);
2067 } else {
2068 /* directly connect TCH RTP streams to each other */
2069 ts = remote_lchan->ts;
2070 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2071 ts->abis_ip.bound_port,
2072 lchan->ts->abis_ip.conn_id,
2073 ts->abis_ip.rtp_payload2);
2074 if (rc < 0)
2075 return rc;
2076 ts = lchan->ts;
2077 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2078 ts->abis_ip.bound_port,
2079 remote_lchan->ts->abis_ip.conn_id,
2080 ts->abis_ip.rtp_payload2);
2081 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002082 break;
2083 case GSM_BTS_TYPE_BS11:
2084 trau_mux_map_lchan(lchan, remote_lchan);
2085 break;
2086 default:
2087 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002088 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002089 break;
2090 }
Harald Welte49f48b82009-02-17 15:29:33 +00002091
2092 return 0;
2093}
2094
Harald Welte4bfdfe72009-06-10 23:11:52 +08002095/* bridge channels of two transactions */
2096static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002097{
Harald Welteaa0b29c2009-07-23 18:56:43 +02002098 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2099 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002100
Harald Welte4bfdfe72009-06-10 23:11:52 +08002101 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002102 return -EIO;
2103
Harald Welte4bfdfe72009-06-10 23:11:52 +08002104 if (!trans1->lchan || !trans2->lchan)
2105 return -EIO;
2106
2107 /* through-connect channel */
2108 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002109}
2110
Harald Welte4bfdfe72009-06-10 23:11:52 +08002111/* enable receive of channels to upqueue */
2112static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2113{
2114 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002115
Harald Welte4bfdfe72009-06-10 23:11:52 +08002116 /* Find callref */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002117 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002118 if (!trans)
2119 return -EIO;
2120 if (!trans->lchan)
2121 return 0;
2122
2123 // todo IPACCESS
2124 if (enable)
2125 return trau_recv_lchan(trans->lchan, data->callref);
2126 return trau_mux_unmap(NULL, data->callref);
2127}
2128
2129/* send a frame to channel */
2130static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2131{
2132 struct gsm_trans *trans;
2133
2134 /* Find callref */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002135 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002136 if (!trans)
2137 return -EIO;
2138 if (!trans->lchan)
2139 return 0;
2140 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2141 trans->lchan->type != GSM_LCHAN_TCH_H)
2142 return 0;
2143
2144 // todo IPACCESS
2145 return trau_send_lchan(trans->lchan,
2146 (struct decoded_trau_frame *)frame->data);
2147}
2148
2149
2150static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2151{
2152 DEBUGP(DCC, "-> STATUS ENQ\n");
2153 return gsm48_cc_tx_status(trans, msg);
2154}
2155
2156static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2157static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2158
2159static void gsm48_cc_timeout(void *arg)
2160{
2161 struct gsm_trans *trans = arg;
2162 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002163 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2164 int mo_location = GSM48_CAUSE_LOC_USER;
2165 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2166 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002167 struct gsm_mncc mo_rel, l4_rel;
2168
2169 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2170 mo_rel.callref = trans->callref;
2171 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2172 l4_rel.callref = trans->callref;
2173
Harald Welteaa0b29c2009-07-23 18:56:43 +02002174 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002175 case 0x303:
2176 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002177 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002178 break;
2179 case 0x310:
2180 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002181 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002182 break;
2183 case 0x313:
2184 disconnect = 1;
2185 /* unknown, did not find it in the specs */
2186 break;
2187 case 0x301:
2188 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002189 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002190 break;
2191 case 0x308:
Harald Welteaa0b29c2009-07-23 18:56:43 +02002192 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002193 /* restart T308 a second time */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002194 gsm48_cc_tx_release(trans, &trans->cc.msg);
2195 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002196 break; /* stay in release state */
2197 }
Harald Welteaa0b29c2009-07-23 18:56:43 +02002198 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002199 return;
2200// release = 1;
2201// l4_cause = 14;
2202// break;
2203 case 0x306:
2204 release = 1;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002205 mo_cause = trans->cc.msg.cause.value;
2206 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002207 break;
2208 case 0x323:
2209 disconnect = 1;
2210 break;
2211 default:
2212 release = 1;
2213 }
2214
2215 if (release && trans->callref) {
2216 /* process release towards layer 4 */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002217 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002218 l4_location, l4_cause);
2219 trans->callref = 0;
2220 }
2221
2222 if (disconnect && trans->callref) {
2223 /* process disconnect towards layer 4 */
2224 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welteb3c3fae2009-07-23 19:06:52 +02002225 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002226 }
2227
2228 /* process disconnect towards mobile station */
2229 if (disconnect || release) {
2230 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Welteaa0b29c2009-07-23 18:56:43 +02002231 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2232 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2233 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002234 mo_rel.cause.diag_len = 3;
2235
2236 if (disconnect)
2237 gsm48_cc_tx_disconnect(trans, &mo_rel);
2238 if (release)
2239 gsm48_cc_tx_release(trans, &mo_rel);
2240 }
2241
2242}
2243
2244static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2245 int sec, int micro)
2246{
2247 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Welteaa0b29c2009-07-23 18:56:43 +02002248 trans->cc.timer.cb = gsm48_cc_timeout;
2249 trans->cc.timer.data = trans;
2250 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2251 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002252}
2253
2254static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2255{
2256 struct gsm48_hdr *gh = msgb_l3(msg);
2257 u_int8_t msg_type = gh->msg_type & 0xbf;
2258 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2259 struct tlv_parsed tp;
2260 struct gsm_mncc setup;
2261
2262 memset(&setup, 0, sizeof(struct gsm_mncc));
2263 setup.callref = trans->callref;
2264 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2265 /* emergency setup is identified by msg_type */
2266 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2267 setup.emergency = 1;
2268
2269 /* use subscriber as calling party number */
2270 if (trans->subscr) {
2271 setup.fields |= MNCC_F_CALLING;
2272 strncpy(setup.calling.number, trans->subscr->extension,
2273 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002274 strncpy(setup.imsi, trans->subscr->imsi,
2275 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002276 }
2277 /* bearer capability */
2278 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2279 setup.fields |= MNCC_F_BEARER_CAP;
2280 decode_bearer_cap(&setup.bearer_cap,
2281 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2282 }
2283 /* facility */
2284 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2285 setup.fields |= MNCC_F_FACILITY;
2286 decode_facility(&setup.facility,
2287 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2288 }
2289 /* called party bcd number */
2290 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2291 setup.fields |= MNCC_F_CALLED;
2292 decode_called(&setup.called,
2293 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2294 }
2295 /* user-user */
2296 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2297 setup.fields |= MNCC_F_USERUSER;
2298 decode_useruser(&setup.useruser,
2299 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2300 }
2301 /* ss-version */
2302 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2303 setup.fields |= MNCC_F_SSVERSION;
2304 decode_ssversion(&setup.ssversion,
2305 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2306 }
2307 /* CLIR suppression */
2308 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2309 setup.clir.sup = 1;
2310 /* CLIR invocation */
2311 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2312 setup.clir.inv = 1;
2313 /* cc cap */
2314 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2315 setup.fields |= MNCC_F_CCCAP;
2316 decode_cccap(&setup.cccap,
2317 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2318 }
2319
2320 if (is_ipaccess_bts(msg->trx->bts))
2321 rsl_ipacc_bind(msg->lchan);
2322
2323 new_cc_state(trans, GSM_CSTATE_INITIATED);
2324
2325 /* indicate setup to MNCC */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002326 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002327
2328 return 0;
2329}
2330
2331static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002332{
2333 struct msgb *msg = gsm48_msgb_alloc();
2334 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002335 struct gsm_mncc *setup = arg;
Harald Welteb49248b2009-07-23 21:36:44 +02002336 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002337
Harald Welte7ccf7782009-02-17 01:43:01 +00002338 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002339
Harald Welte4bfdfe72009-06-10 23:11:52 +08002340 /* transaction id must not be assigned */
2341 if (trans->transaction_id != 0xff) { /* unasssigned */
2342 DEBUGP(DCC, "TX Setup with assigned transaction. "
2343 "This is not allowed!\n");
2344 /* Temporarily out of order */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002345 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002346 GSM48_CAUSE_LOC_PRN_S_LU,
2347 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002348 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002349 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002350 return rc;
2351 }
2352
2353 /* Get free transaction_id */
Harald Welteb49248b2009-07-23 21:36:44 +02002354 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2355 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002356 /* no free transaction ID */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002357 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002358 GSM48_CAUSE_LOC_PRN_S_LU,
2359 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002360 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002361 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002362 return rc;
2363 }
Harald Welteb49248b2009-07-23 21:36:44 +02002364 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002365
Harald Welte65e74cc2008-12-29 01:55:35 +00002366 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002367
Harald Welte4bfdfe72009-06-10 23:11:52 +08002368 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002369
Harald Welte4bfdfe72009-06-10 23:11:52 +08002370 /* bearer capability */
2371 if (setup->fields & MNCC_F_BEARER_CAP)
2372 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2373 /* facility */
2374 if (setup->fields & MNCC_F_FACILITY)
2375 encode_facility(msg, 0, &setup->facility);
2376 /* progress */
2377 if (setup->fields & MNCC_F_PROGRESS)
2378 encode_progress(msg, 0, &setup->progress);
2379 /* calling party BCD number */
2380 if (setup->fields & MNCC_F_CALLING)
2381 encode_calling(msg, &setup->calling);
2382 /* called party BCD number */
2383 if (setup->fields & MNCC_F_CALLED)
2384 encode_called(msg, &setup->called);
2385 /* user-user */
2386 if (setup->fields & MNCC_F_USERUSER)
2387 encode_useruser(msg, 0, &setup->useruser);
2388 /* redirecting party BCD number */
2389 if (setup->fields & MNCC_F_REDIRECTING)
2390 encode_redirecting(msg, &setup->redirecting);
2391 /* signal */
2392 if (setup->fields & MNCC_F_SIGNAL)
2393 encode_signal(msg, setup->signal);
2394
2395 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002396
Harald Welte39e2ead2009-07-23 21:13:03 +02002397 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002398}
2399
Harald Welte4bfdfe72009-06-10 23:11:52 +08002400static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2401{
2402 struct gsm48_hdr *gh = msgb_l3(msg);
2403 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2404 struct tlv_parsed tp;
2405 struct gsm_mncc call_conf;
2406
2407 gsm48_stop_cc_timer(trans);
2408 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2409
2410 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2411 call_conf.callref = trans->callref;
2412 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2413#if 0
2414 /* repeat */
2415 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2416 call_conf.repeat = 1;
2417 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2418 call_conf.repeat = 2;
2419#endif
2420 /* bearer capability */
2421 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2422 call_conf.fields |= MNCC_F_BEARER_CAP;
2423 decode_bearer_cap(&call_conf.bearer_cap,
2424 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2425 }
2426 /* cause */
2427 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2428 call_conf.fields |= MNCC_F_CAUSE;
2429 decode_cause(&call_conf.cause,
2430 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2431 }
2432 /* cc cap */
2433 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2434 call_conf.fields |= MNCC_F_CCCAP;
2435 decode_cccap(&call_conf.cccap,
2436 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2437 }
2438
2439 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2440
Harald Welteb3c3fae2009-07-23 19:06:52 +02002441 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2442 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002443}
2444
2445static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2446{
2447 struct gsm_mncc *proceeding = arg;
2448 struct msgb *msg = gsm48_msgb_alloc();
2449 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2450
Harald Welte4bfdfe72009-06-10 23:11:52 +08002451 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2452
2453 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2454
2455 /* bearer capability */
2456 if (proceeding->fields & MNCC_F_BEARER_CAP)
2457 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2458 /* facility */
2459 if (proceeding->fields & MNCC_F_FACILITY)
2460 encode_facility(msg, 0, &proceeding->facility);
2461 /* progress */
2462 if (proceeding->fields & MNCC_F_PROGRESS)
2463 encode_progress(msg, 0, &proceeding->progress);
2464
Harald Welte39e2ead2009-07-23 21:13:03 +02002465 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002466}
2467
2468static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2469{
2470 struct gsm48_hdr *gh = msgb_l3(msg);
2471 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2472 struct tlv_parsed tp;
2473 struct gsm_mncc alerting;
2474
2475 gsm48_stop_cc_timer(trans);
2476 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2477
2478 memset(&alerting, 0, sizeof(struct gsm_mncc));
2479 alerting.callref = trans->callref;
2480 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2481 /* facility */
2482 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2483 alerting.fields |= MNCC_F_FACILITY;
2484 decode_facility(&alerting.facility,
2485 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2486 }
2487
2488 /* progress */
2489 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2490 alerting.fields |= MNCC_F_PROGRESS;
2491 decode_progress(&alerting.progress,
2492 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2493 }
2494 /* ss-version */
2495 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2496 alerting.fields |= MNCC_F_SSVERSION;
2497 decode_ssversion(&alerting.ssversion,
2498 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2499 }
2500
2501 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2502
Harald Welteb3c3fae2009-07-23 19:06:52 +02002503 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2504 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002505}
2506
2507static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2508{
2509 struct gsm_mncc *alerting = arg;
2510 struct msgb *msg = gsm48_msgb_alloc();
2511 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2512
Harald Welte4bfdfe72009-06-10 23:11:52 +08002513 gh->msg_type = GSM48_MT_CC_ALERTING;
2514
2515 /* facility */
2516 if (alerting->fields & MNCC_F_FACILITY)
2517 encode_facility(msg, 0, &alerting->facility);
2518 /* progress */
2519 if (alerting->fields & MNCC_F_PROGRESS)
2520 encode_progress(msg, 0, &alerting->progress);
2521 /* user-user */
2522 if (alerting->fields & MNCC_F_USERUSER)
2523 encode_useruser(msg, 0, &alerting->useruser);
2524
2525 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2526
Harald Welte39e2ead2009-07-23 21:13:03 +02002527 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002528}
2529
2530static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2531{
2532 struct gsm_mncc *progress = arg;
2533 struct msgb *msg = gsm48_msgb_alloc();
2534 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2535
Harald Welte4bfdfe72009-06-10 23:11:52 +08002536 gh->msg_type = GSM48_MT_CC_PROGRESS;
2537
2538 /* progress */
2539 encode_progress(msg, 1, &progress->progress);
2540 /* user-user */
2541 if (progress->fields & MNCC_F_USERUSER)
2542 encode_useruser(msg, 0, &progress->useruser);
2543
Harald Welte39e2ead2009-07-23 21:13:03 +02002544 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002545}
2546
2547static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2548{
2549 struct gsm_mncc *connect = arg;
2550 struct msgb *msg = gsm48_msgb_alloc();
2551 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2552
Harald Welte4bfdfe72009-06-10 23:11:52 +08002553 gh->msg_type = GSM48_MT_CC_CONNECT;
2554
2555 gsm48_stop_cc_timer(trans);
2556 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2557
2558 /* facility */
2559 if (connect->fields & MNCC_F_FACILITY)
2560 encode_facility(msg, 0, &connect->facility);
2561 /* progress */
2562 if (connect->fields & MNCC_F_PROGRESS)
2563 encode_progress(msg, 0, &connect->progress);
2564 /* connected number */
2565 if (connect->fields & MNCC_F_CONNECTED)
2566 encode_connected(msg, &connect->connected);
2567 /* user-user */
2568 if (connect->fields & MNCC_F_USERUSER)
2569 encode_useruser(msg, 0, &connect->useruser);
2570
2571 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2572
Harald Welte39e2ead2009-07-23 21:13:03 +02002573 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002574}
2575
2576static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2577{
2578 struct gsm48_hdr *gh = msgb_l3(msg);
2579 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2580 struct tlv_parsed tp;
2581 struct gsm_mncc connect;
2582
2583 gsm48_stop_cc_timer(trans);
2584
2585 memset(&connect, 0, sizeof(struct gsm_mncc));
2586 connect.callref = trans->callref;
2587 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2588 /* use subscriber as connected party number */
2589 if (trans->subscr) {
2590 connect.fields |= MNCC_F_CONNECTED;
2591 strncpy(connect.connected.number, trans->subscr->extension,
2592 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002593 strncpy(connect.imsi, trans->subscr->imsi,
2594 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002595 }
2596 /* facility */
2597 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2598 connect.fields |= MNCC_F_FACILITY;
2599 decode_facility(&connect.facility,
2600 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2601 }
2602 /* user-user */
2603 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2604 connect.fields |= MNCC_F_USERUSER;
2605 decode_useruser(&connect.useruser,
2606 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2607 }
2608 /* ss-version */
2609 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2610 connect.fields |= MNCC_F_SSVERSION;
2611 decode_ssversion(&connect.ssversion,
2612 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2613 }
2614
2615 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2616
Harald Welteb3c3fae2009-07-23 19:06:52 +02002617 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002618}
2619
2620
2621static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2622{
2623 struct gsm_mncc connect_ack;
2624
2625 gsm48_stop_cc_timer(trans);
2626
2627 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2628
2629 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2630 connect_ack.callref = trans->callref;
Harald Welteb3c3fae2009-07-23 19:06:52 +02002631 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002632 &connect_ack);
2633}
2634
2635static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2636{
2637 struct msgb *msg = gsm48_msgb_alloc();
2638 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2639
Harald Welte4bfdfe72009-06-10 23:11:52 +08002640 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2641
2642 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2643
Harald Welte39e2ead2009-07-23 21:13:03 +02002644 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002645}
2646
2647static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2648{
2649 struct gsm48_hdr *gh = msgb_l3(msg);
2650 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2651 struct tlv_parsed tp;
2652 struct gsm_mncc disc;
2653
2654 gsm48_stop_cc_timer(trans);
2655
2656 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2657
2658 memset(&disc, 0, sizeof(struct gsm_mncc));
2659 disc.callref = trans->callref;
2660 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2661 /* cause */
2662 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2663 disc.fields |= MNCC_F_CAUSE;
2664 decode_cause(&disc.cause,
2665 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2666 }
2667 /* facility */
2668 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2669 disc.fields |= MNCC_F_FACILITY;
2670 decode_facility(&disc.facility,
2671 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2672 }
2673 /* user-user */
2674 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2675 disc.fields |= MNCC_F_USERUSER;
2676 decode_useruser(&disc.useruser,
2677 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2678 }
2679 /* ss-version */
2680 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2681 disc.fields |= MNCC_F_SSVERSION;
2682 decode_ssversion(&disc.ssversion,
2683 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2684 }
2685
Harald Welteb3c3fae2009-07-23 19:06:52 +02002686 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002687
2688}
2689
Harald Weltec66b71c2009-06-11 14:23:20 +08002690static struct gsm_mncc_cause default_cause = {
2691 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2692 .coding = 0,
2693 .rec = 0,
2694 .rec_val = 0,
2695 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2696 .diag_len = 0,
2697 .diag = { 0 },
2698};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002699
2700static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2701{
2702 struct gsm_mncc *disc = arg;
2703 struct msgb *msg = gsm48_msgb_alloc();
2704 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2705
Harald Welte4bfdfe72009-06-10 23:11:52 +08002706 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2707
2708 gsm48_stop_cc_timer(trans);
2709 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2710
2711 /* cause */
2712 if (disc->fields & MNCC_F_CAUSE)
2713 encode_cause(msg, 1, &disc->cause);
2714 else
2715 encode_cause(msg, 1, &default_cause);
2716
2717 /* facility */
2718 if (disc->fields & MNCC_F_FACILITY)
2719 encode_facility(msg, 0, &disc->facility);
2720 /* progress */
2721 if (disc->fields & MNCC_F_PROGRESS)
2722 encode_progress(msg, 0, &disc->progress);
2723 /* user-user */
2724 if (disc->fields & MNCC_F_USERUSER)
2725 encode_useruser(msg, 0, &disc->useruser);
2726
2727 /* store disconnect cause for T306 expiry */
Harald Welteaa0b29c2009-07-23 18:56:43 +02002728 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002729
2730 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2731
Harald Welte39e2ead2009-07-23 21:13:03 +02002732 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002733}
2734
2735static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2736{
2737 struct gsm48_hdr *gh = msgb_l3(msg);
2738 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2739 struct tlv_parsed tp;
2740 struct gsm_mncc rel;
2741 int rc;
2742
2743 gsm48_stop_cc_timer(trans);
2744
2745 memset(&rel, 0, sizeof(struct gsm_mncc));
2746 rel.callref = trans->callref;
2747 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2748 /* cause */
2749 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2750 rel.fields |= MNCC_F_CAUSE;
2751 decode_cause(&rel.cause,
2752 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2753 }
2754 /* facility */
2755 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2756 rel.fields |= MNCC_F_FACILITY;
2757 decode_facility(&rel.facility,
2758 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2759 }
2760 /* user-user */
2761 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2762 rel.fields |= MNCC_F_USERUSER;
2763 decode_useruser(&rel.useruser,
2764 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2765 }
2766 /* ss-version */
2767 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2768 rel.fields |= MNCC_F_SSVERSION;
2769 decode_ssversion(&rel.ssversion,
2770 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2771 }
2772
Harald Welteaa0b29c2009-07-23 18:56:43 +02002773 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002774 /* release collision 5.4.5 */
Harald Welteb3c3fae2009-07-23 19:06:52 +02002775 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002776 } else {
Harald Welteb3c3fae2009-07-23 19:06:52 +02002777 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002778 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welteb3c3fae2009-07-23 19:06:52 +02002779 GSM48_MT_CC_RELEASE_COMPL);
2780 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002781 }
2782
2783 new_cc_state(trans, GSM_CSTATE_NULL);
2784
2785 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002786 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002787
2788 return rc;
2789}
2790
2791static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2792{
2793 struct gsm_mncc *rel = arg;
2794 struct msgb *msg = gsm48_msgb_alloc();
2795 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2796
Harald Welte4bfdfe72009-06-10 23:11:52 +08002797 gh->msg_type = GSM48_MT_CC_RELEASE;
2798
2799 trans->callref = 0;
2800
2801 gsm48_stop_cc_timer(trans);
2802 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2803
2804 /* cause */
2805 if (rel->fields & MNCC_F_CAUSE)
2806 encode_cause(msg, 0, &rel->cause);
2807 /* facility */
2808 if (rel->fields & MNCC_F_FACILITY)
2809 encode_facility(msg, 0, &rel->facility);
2810 /* user-user */
2811 if (rel->fields & MNCC_F_USERUSER)
2812 encode_useruser(msg, 0, &rel->useruser);
2813
Harald Welteaa0b29c2009-07-23 18:56:43 +02002814 trans->cc.T308_second = 0;
2815 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002816
Harald Welteaa0b29c2009-07-23 18:56:43 +02002817 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002818 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2819
Harald Welte39e2ead2009-07-23 21:13:03 +02002820 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002821}
2822
2823static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2824{
2825 struct gsm48_hdr *gh = msgb_l3(msg);
2826 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2827 struct tlv_parsed tp;
2828 struct gsm_mncc rel;
2829 int rc = 0;
2830
2831 gsm48_stop_cc_timer(trans);
2832
2833 memset(&rel, 0, sizeof(struct gsm_mncc));
2834 rel.callref = trans->callref;
2835 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2836 /* cause */
2837 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2838 rel.fields |= MNCC_F_CAUSE;
2839 decode_cause(&rel.cause,
2840 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2841 }
2842 /* facility */
2843 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2844 rel.fields |= MNCC_F_FACILITY;
2845 decode_facility(&rel.facility,
2846 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2847 }
2848 /* user-user */
2849 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2850 rel.fields |= MNCC_F_USERUSER;
2851 decode_useruser(&rel.useruser,
2852 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2853 }
2854 /* ss-version */
2855 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2856 rel.fields |= MNCC_F_SSVERSION;
2857 decode_ssversion(&rel.ssversion,
2858 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2859 }
2860
2861 if (trans->callref) {
Harald Welteaa0b29c2009-07-23 18:56:43 +02002862 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002863 case GSM_CSTATE_CALL_PRESENT:
Harald Welteb3c3fae2009-07-23 19:06:52 +02002864 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002865 MNCC_REJ_IND, &rel);
2866 break;
2867 case GSM_CSTATE_RELEASE_REQ:
Harald Welteb3c3fae2009-07-23 19:06:52 +02002868 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002869 MNCC_REL_CNF, &rel);
2870 break;
2871 default:
Harald Welteb3c3fae2009-07-23 19:06:52 +02002872 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002873 MNCC_REL_IND, &rel);
2874 }
2875 }
2876
2877 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02002878 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002879
2880 return rc;
2881}
2882
2883static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2884{
2885 struct gsm_mncc *rel = arg;
2886 struct msgb *msg = gsm48_msgb_alloc();
2887 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2888
Harald Welte4bfdfe72009-06-10 23:11:52 +08002889 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2890
2891 trans->callref = 0;
2892
2893 gsm48_stop_cc_timer(trans);
2894
2895 /* cause */
2896 if (rel->fields & MNCC_F_CAUSE)
2897 encode_cause(msg, 0, &rel->cause);
2898 /* facility */
2899 if (rel->fields & MNCC_F_FACILITY)
2900 encode_facility(msg, 0, &rel->facility);
2901 /* user-user */
2902 if (rel->fields & MNCC_F_USERUSER)
2903 encode_useruser(msg, 0, &rel->useruser);
2904
Harald Welteaa0b29c2009-07-23 18:56:43 +02002905 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002906
Harald Welte39e2ead2009-07-23 21:13:03 +02002907 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002908}
2909
2910static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2911{
2912 struct gsm48_hdr *gh = msgb_l3(msg);
2913 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2914 struct tlv_parsed tp;
2915 struct gsm_mncc fac;
2916
2917 memset(&fac, 0, sizeof(struct gsm_mncc));
2918 fac.callref = trans->callref;
2919 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2920 /* facility */
2921 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2922 fac.fields |= MNCC_F_FACILITY;
2923 decode_facility(&fac.facility,
2924 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2925 }
2926 /* ss-version */
2927 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2928 fac.fields |= MNCC_F_SSVERSION;
2929 decode_ssversion(&fac.ssversion,
2930 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2931 }
2932
Harald Welteb3c3fae2009-07-23 19:06:52 +02002933 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002934}
2935
2936static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2937{
2938 struct gsm_mncc *fac = arg;
2939 struct msgb *msg = gsm48_msgb_alloc();
2940 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2941
Harald Welte4bfdfe72009-06-10 23:11:52 +08002942 gh->msg_type = GSM48_MT_CC_FACILITY;
2943
2944 /* facility */
2945 encode_facility(msg, 1, &fac->facility);
2946
Harald Welte39e2ead2009-07-23 21:13:03 +02002947 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002948}
2949
2950static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2951{
2952 struct gsm_mncc hold;
2953
2954 memset(&hold, 0, sizeof(struct gsm_mncc));
2955 hold.callref = trans->callref;
Harald Welteb3c3fae2009-07-23 19:06:52 +02002956 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002957}
2958
2959static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2960{
2961 struct msgb *msg = gsm48_msgb_alloc();
2962 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2963
Harald Welte4bfdfe72009-06-10 23:11:52 +08002964 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
2965
Harald Welte39e2ead2009-07-23 21:13:03 +02002966 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002967}
2968
2969static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
2970{
2971 struct gsm_mncc *hold_rej = arg;
2972 struct msgb *msg = gsm48_msgb_alloc();
2973 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2974
Harald Welte4bfdfe72009-06-10 23:11:52 +08002975 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
2976
2977 /* cause */
2978 if (hold_rej->fields & MNCC_F_CAUSE)
2979 encode_cause(msg, 1, &hold_rej->cause);
2980 else
2981 encode_cause(msg, 1, &default_cause);
2982
Harald Welte39e2ead2009-07-23 21:13:03 +02002983 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002984}
2985
2986static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
2987{
2988 struct gsm_mncc retrieve;
2989
2990 memset(&retrieve, 0, sizeof(struct gsm_mncc));
2991 retrieve.callref = trans->callref;
Harald Welteb3c3fae2009-07-23 19:06:52 +02002992 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
2993 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002994}
2995
2996static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
2997{
2998 struct msgb *msg = gsm48_msgb_alloc();
2999 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3000
Harald Welte4bfdfe72009-06-10 23:11:52 +08003001 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3002
Harald Welte39e2ead2009-07-23 21:13:03 +02003003 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003004}
3005
3006static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3007{
3008 struct gsm_mncc *retrieve_rej = arg;
3009 struct msgb *msg = gsm48_msgb_alloc();
3010 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3011
Harald Welte4bfdfe72009-06-10 23:11:52 +08003012 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3013
3014 /* cause */
3015 if (retrieve_rej->fields & MNCC_F_CAUSE)
3016 encode_cause(msg, 1, &retrieve_rej->cause);
3017 else
3018 encode_cause(msg, 1, &default_cause);
3019
Harald Welte39e2ead2009-07-23 21:13:03 +02003020 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003021}
3022
3023static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3024{
3025 struct gsm48_hdr *gh = msgb_l3(msg);
3026 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3027 struct tlv_parsed tp;
3028 struct gsm_mncc dtmf;
3029
3030 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3031 dtmf.callref = trans->callref;
3032 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3033 /* keypad facility */
3034 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3035 dtmf.fields |= MNCC_F_KEYPAD;
3036 decode_keypad(&dtmf.keypad,
3037 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3038 }
3039
Harald Welteb3c3fae2009-07-23 19:06:52 +02003040 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003041}
3042
3043static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3044{
3045 struct gsm_mncc *dtmf = arg;
3046 struct msgb *msg = gsm48_msgb_alloc();
3047 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3048
Harald Welte4bfdfe72009-06-10 23:11:52 +08003049 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3050
3051 /* keypad */
3052 if (dtmf->fields & MNCC_F_KEYPAD)
3053 encode_keypad(msg, dtmf->keypad);
3054
Harald Welte39e2ead2009-07-23 21:13:03 +02003055 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003056}
3057
3058static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3059{
3060 struct gsm_mncc *dtmf = arg;
3061 struct msgb *msg = gsm48_msgb_alloc();
3062 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3063
Harald Welte4bfdfe72009-06-10 23:11:52 +08003064 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3065
3066 /* cause */
3067 if (dtmf->fields & MNCC_F_CAUSE)
3068 encode_cause(msg, 1, &dtmf->cause);
3069 else
3070 encode_cause(msg, 1, &default_cause);
3071
Harald Welte39e2ead2009-07-23 21:13:03 +02003072 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003073}
3074
3075static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3076{
3077 struct msgb *msg = gsm48_msgb_alloc();
3078 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3079
Harald Welte4bfdfe72009-06-10 23:11:52 +08003080 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3081
Harald Welte39e2ead2009-07-23 21:13:03 +02003082 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003083}
3084
3085static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3086{
3087 struct gsm_mncc dtmf;
3088
3089 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3090 dtmf.callref = trans->callref;
3091
Harald Welteb3c3fae2009-07-23 19:06:52 +02003092 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003093}
3094
3095static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3096{
3097 struct gsm48_hdr *gh = msgb_l3(msg);
3098 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3099 struct tlv_parsed tp;
3100 struct gsm_mncc modify;
3101
3102 memset(&modify, 0, sizeof(struct gsm_mncc));
3103 modify.callref = trans->callref;
3104 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3105 /* bearer capability */
3106 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3107 modify.fields |= MNCC_F_BEARER_CAP;
3108 decode_bearer_cap(&modify.bearer_cap,
3109 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3110 }
3111
3112 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3113
Harald Welteb3c3fae2009-07-23 19:06:52 +02003114 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003115}
3116
3117static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3118{
3119 struct gsm_mncc *modify = arg;
3120 struct msgb *msg = gsm48_msgb_alloc();
3121 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3122
Harald Welte4bfdfe72009-06-10 23:11:52 +08003123 gh->msg_type = GSM48_MT_CC_MODIFY;
3124
3125 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3126
3127 /* bearer capability */
3128 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3129
3130 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3131
Harald Welte39e2ead2009-07-23 21:13:03 +02003132 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003133}
3134
3135static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3136{
3137 struct gsm48_hdr *gh = msgb_l3(msg);
3138 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3139 struct tlv_parsed tp;
3140 struct gsm_mncc modify;
3141
3142 gsm48_stop_cc_timer(trans);
3143
3144 memset(&modify, 0, sizeof(struct gsm_mncc));
3145 modify.callref = trans->callref;
3146 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3147 /* bearer capability */
3148 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3149 modify.fields |= MNCC_F_BEARER_CAP;
3150 decode_bearer_cap(&modify.bearer_cap,
3151 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3152 }
3153
3154 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3155
Harald Welteb3c3fae2009-07-23 19:06:52 +02003156 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003157}
3158
3159static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3160{
3161 struct gsm_mncc *modify = arg;
3162 struct msgb *msg = gsm48_msgb_alloc();
3163 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3164
Harald Welte4bfdfe72009-06-10 23:11:52 +08003165 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3166
3167 /* bearer capability */
3168 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3169
3170 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3171
Harald Welte39e2ead2009-07-23 21:13:03 +02003172 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003173}
3174
3175static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3176{
3177 struct gsm48_hdr *gh = msgb_l3(msg);
3178 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3179 struct tlv_parsed tp;
3180 struct gsm_mncc modify;
3181
3182 gsm48_stop_cc_timer(trans);
3183
3184 memset(&modify, 0, sizeof(struct gsm_mncc));
3185 modify.callref = trans->callref;
3186 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3187 /* bearer capability */
3188 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3189 modify.fields |= GSM48_IE_BEARER_CAP;
3190 decode_bearer_cap(&modify.bearer_cap,
3191 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3192 }
3193 /* cause */
3194 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3195 modify.fields |= MNCC_F_CAUSE;
3196 decode_cause(&modify.cause,
3197 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3198 }
3199
3200 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3201
Harald Welteb3c3fae2009-07-23 19:06:52 +02003202 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003203}
3204
3205static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3206{
3207 struct gsm_mncc *modify = arg;
3208 struct msgb *msg = gsm48_msgb_alloc();
3209 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3210
Harald Welte4bfdfe72009-06-10 23:11:52 +08003211 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3212
3213 /* bearer capability */
3214 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3215 /* cause */
3216 encode_cause(msg, 1, &modify->cause);
3217
3218 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3219
Harald Welte39e2ead2009-07-23 21:13:03 +02003220 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003221}
3222
3223static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3224{
3225 struct gsm_mncc *notify = arg;
3226 struct msgb *msg = gsm48_msgb_alloc();
3227 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3228
Harald Welte4bfdfe72009-06-10 23:11:52 +08003229 gh->msg_type = GSM48_MT_CC_NOTIFY;
3230
3231 /* notify */
3232 encode_notify(msg, notify->notify);
3233
Harald Welte39e2ead2009-07-23 21:13:03 +02003234 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003235}
3236
3237static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3238{
3239 struct gsm48_hdr *gh = msgb_l3(msg);
3240 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3241// struct tlv_parsed tp;
3242 struct gsm_mncc notify;
3243
3244 memset(&notify, 0, sizeof(struct gsm_mncc));
3245 notify.callref = trans->callref;
3246// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3247 if (payload_len >= 1)
3248 decode_notify(&notify.notify, gh->data);
3249
Harald Welteb3c3fae2009-07-23 19:06:52 +02003250 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003251}
3252
3253static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3254{
3255 struct gsm_mncc *user = arg;
3256 struct msgb *msg = gsm48_msgb_alloc();
3257 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3258
Harald Welte4bfdfe72009-06-10 23:11:52 +08003259 gh->msg_type = GSM48_MT_CC_USER_INFO;
3260
3261 /* user-user */
3262 if (user->fields & MNCC_F_USERUSER)
3263 encode_useruser(msg, 1, &user->useruser);
3264 /* more data */
3265 if (user->more)
3266 encode_more(msg);
3267
Harald Welte39e2ead2009-07-23 21:13:03 +02003268 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003269}
3270
3271static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3272{
3273 struct gsm48_hdr *gh = msgb_l3(msg);
3274 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3275 struct tlv_parsed tp;
3276 struct gsm_mncc user;
3277
3278 memset(&user, 0, sizeof(struct gsm_mncc));
3279 user.callref = trans->callref;
3280 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3281 /* user-user */
3282 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3283 user.fields |= MNCC_F_USERUSER;
3284 decode_useruser(&user.useruser,
3285 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3286 }
3287 /* more data */
3288 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3289 user.more = 1;
3290
Harald Welteb3c3fae2009-07-23 19:06:52 +02003291 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003292}
3293
3294static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3295{
3296 struct gsm_mncc *mode = arg;
3297
3298 return gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3299}
3300
3301static struct downstate {
3302 u_int32_t states;
3303 int type;
3304 int (*rout) (struct gsm_trans *trans, void *arg);
3305} downstatelist[] = {
3306 /* mobile originating call establishment */
3307 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3308 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3309 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3310 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3311 {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 */
3312 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3313 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3314 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3315 /* mobile terminating call establishment */
3316 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3317 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3318 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3319 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3320 /* signalling during call */
3321 {SBIT(GSM_CSTATE_ACTIVE),
3322 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3323 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3324 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3325 {ALL_STATES,
3326 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3327 {ALL_STATES,
3328 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3329 {ALL_STATES,
3330 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3331 {SBIT(GSM_CSTATE_ACTIVE),
3332 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3333 {SBIT(GSM_CSTATE_ACTIVE),
3334 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3335 {SBIT(GSM_CSTATE_ACTIVE),
3336 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3337 {SBIT(GSM_CSTATE_ACTIVE),
3338 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3339 {SBIT(GSM_CSTATE_ACTIVE),
3340 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3341 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3342 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3343 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3344 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3345 {SBIT(GSM_CSTATE_ACTIVE),
3346 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3347 /* clearing */
3348 {SBIT(GSM_CSTATE_INITIATED),
3349 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3350 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3351 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3352 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3353 MNCC_REL_REQ, gsm48_cc_tx_release},
3354 /* special */
3355 {ALL_STATES,
3356 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3357};
3358
3359#define DOWNSLLEN \
3360 (sizeof(downstatelist) / sizeof(struct downstate))
3361
3362
3363int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3364{
3365 int i, j, k, l, rc = 0;
3366 struct gsm_trans *trans = NULL, *transt;
3367 struct gsm_subscriber *subscr;
3368 struct gsm_lchan *lchan = NULL, *lchant;
3369 struct gsm_bts *bts = NULL;
3370 struct gsm_bts_trx *trx;
3371 struct gsm_bts_trx_ts *ts;
3372 struct gsm_mncc *data = arg, rel;
3373
3374 /* handle special messages */
3375 switch(msg_type) {
3376 case MNCC_BRIDGE:
3377 return tch_bridge(net, arg);
3378 case MNCC_FRAME_DROP:
3379 return tch_recv(net, arg, 0);
3380 case MNCC_FRAME_RECV:
3381 return tch_recv(net, arg, 1);
3382 case GSM_TRAU_FRAME:
3383 return tch_frame(net, arg);
3384 }
3385
3386 memset(&rel, 0, sizeof(struct gsm_mncc));
3387 rel.callref = data->callref;
3388
3389 /* Find callref */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003390 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003391
3392 /* Callref unknown */
3393 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003394 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003395 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3396 "Received '%s' from MNCC with "
3397 "unknown callref %d\n", data->called.number,
3398 get_mncc_name(msg_type), data->callref);
3399 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003400 return mncc_release_ind(net, NULL, data->callref,
3401 GSM48_CAUSE_LOC_PRN_S_LU,
3402 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003403 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003404 if (!data->called.number[0] && !data->imsi[0]) {
3405 DEBUGP(DCC, "(bts - trx - ts - ti) "
3406 "Received '%s' from MNCC with "
3407 "no number or IMSI\n", get_mncc_name(msg_type));
3408 /* Invalid number */
3409 return mncc_release_ind(net, NULL, data->callref,
3410 GSM48_CAUSE_LOC_PRN_S_LU,
3411 GSM48_CC_CAUSE_INV_NR_FORMAT);
3412 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003413 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003414 if (data->called.number[0])
Harald Welte761e9442009-07-23 19:21:02 +02003415 subscr = subscr_get_by_extension(net,
3416 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003417 else
Harald Welte761e9442009-07-23 19:21:02 +02003418 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003419 /* If subscriber is not found */
3420 if (!subscr) {
3421 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3422 "Received '%s' from MNCC with "
3423 "unknown subscriber %s\n", data->called.number,
3424 get_mncc_name(msg_type), data->called.number);
3425 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003426 return mncc_release_ind(net, NULL, data->callref,
3427 GSM48_CAUSE_LOC_PRN_S_LU,
3428 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003429 }
3430 /* If subscriber is not "attached" */
3431 if (!subscr->lac) {
3432 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3433 "Received '%s' from MNCC with "
3434 "detached subscriber %s\n", data->called.number,
3435 get_mncc_name(msg_type), data->called.number);
3436 subscr_put(subscr);
3437 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003438 return mncc_release_ind(net, NULL, data->callref,
3439 GSM48_CAUSE_LOC_PRN_S_LU,
3440 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003441 }
3442 /* Create transaction */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003443 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3444 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003445 DEBUGP(DCC, "No memory for trans.\n");
3446 subscr_put(subscr);
3447 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003448 mncc_release_ind(net, NULL, data->callref,
3449 GSM48_CAUSE_LOC_PRN_S_LU,
3450 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003451 return -ENOMEM;
3452 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003453 /* Find lchan */
3454 for (i = 0; i < net->num_bts; i++) {
Harald Weltee441d9c2009-06-21 16:17:15 +02003455 bts = gsm_bts_num(net, i);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003456 for (j = 0; j < bts->num_trx; j++) {
Harald Weltee441d9c2009-06-21 16:17:15 +02003457 trx = gsm_bts_trx_num(bts, j);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003458 for (k = 0; k < TRX_NR_TS; k++) {
3459 ts = &trx->ts[k];
3460 for (l = 0; l < TS_MAX_LCHAN; l++) {
3461 lchant = &ts->lchan[l];
3462 if (lchant->subscr == subscr) {
3463 lchan = lchant;
3464 break;
3465 }
3466 }
3467 }
3468 }
3469 }
3470
3471 /* If subscriber has no lchan */
3472 if (!lchan) {
3473 /* find transaction with this subscriber already paging */
3474 llist_for_each_entry(transt, &net->trans_list, entry) {
3475 /* Transaction of our lchan? */
3476 if (transt == trans ||
3477 transt->subscr != subscr)
3478 continue;
3479 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3480 "Received '%s' from MNCC with "
3481 "unallocated channel, paging already "
3482 "started.\n", bts->nr,
3483 data->called.number,
3484 get_mncc_name(msg_type));
3485 return 0;
3486 }
3487 /* store setup informations until paging was successfull */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003488 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08003489 /* start paging subscriber on all BTS with her location */
3490 subscr->net = net;
3491 bts = NULL;
3492 do {
3493 bts = gsm_bts_by_lac(net, subscr->lac, bts);
3494 if (!bts)
3495 break;
3496 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3497 "Received '%s' from MNCC with "
3498 "unallocated channel, paging.\n",
3499 bts->nr, data->called.number,
3500 get_mncc_name(msg_type));
3501 /* Trigger paging */
Harald Welte92f70c52009-06-12 01:54:08 +08003502 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
Harald Welte4bfdfe72009-06-10 23:11:52 +08003503 setup_trig_pag_evt, subscr);
3504 } while (1);
3505 return 0;
3506 }
3507 /* Assign lchan */
3508 trans->lchan = lchan;
3509 use_lchan(lchan);
3510 }
3511 lchan = trans->lchan;
3512
3513 /* if paging did not respond yet */
3514 if (!lchan) {
3515 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3516 "Received '%s' from MNCC in paging state\n",
3517 (trans->subscr)?(trans->subscr->extension):"-",
3518 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003519 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3520 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003521 if (msg_type == MNCC_REL_REQ)
3522 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3523 else
3524 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3525 trans->callref = 0;
Harald Welteaa0b29c2009-07-23 18:56:43 +02003526 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003527 return rc;
3528 }
3529
3530 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3531 "Received '%s' from MNCC in state %d (%s)\n",
3532 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3533 trans->transaction_id,
3534 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Welteaa0b29c2009-07-23 18:56:43 +02003535 get_mncc_name(msg_type), trans->cc.state,
3536 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003537
3538 /* Find function for current state and message */
3539 for (i = 0; i < DOWNSLLEN; i++)
3540 if ((msg_type == downstatelist[i].type)
Harald Welteaa0b29c2009-07-23 18:56:43 +02003541 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003542 break;
3543 if (i == DOWNSLLEN) {
3544 DEBUGP(DCC, "Message unhandled at this state.\n");
3545 return 0;
3546 }
3547
3548 rc = downstatelist[i].rout(trans, arg);
3549
3550 return rc;
3551}
3552
3553
3554static struct datastate {
3555 u_int32_t states;
3556 int type;
3557 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3558} datastatelist[] = {
3559 /* mobile originating call establishment */
3560 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3561 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3562 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3563 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3564 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3565 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3566 /* mobile terminating call establishment */
3567 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3568 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3569 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3570 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3571 {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 */
3572 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3573 /* signalling during call */
3574 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3575 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3576 {SBIT(GSM_CSTATE_ACTIVE),
3577 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3578 {ALL_STATES,
3579 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3580 {ALL_STATES,
3581 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3582 {ALL_STATES,
3583 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3584 {SBIT(GSM_CSTATE_ACTIVE),
3585 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3586 {SBIT(GSM_CSTATE_ACTIVE),
3587 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3588 {SBIT(GSM_CSTATE_ACTIVE),
3589 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3590 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3591 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3592 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3593 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3594 {SBIT(GSM_CSTATE_ACTIVE),
3595 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3596 /* clearing */
3597 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3598 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3599 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3600 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3601 {ALL_STATES, /* 5.4.3.4 */
3602 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3603};
3604
3605#define DATASLLEN \
3606 (sizeof(datastatelist) / sizeof(struct datastate))
3607
Harald Welte4bc90a12008-12-27 16:32:52 +00003608static int gsm0408_rcv_cc(struct msgb *msg)
3609{
3610 struct gsm48_hdr *gh = msgb_l3(msg);
3611 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003612 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003613 struct gsm_lchan *lchan = msg->lchan;
Harald Welteaa0b29c2009-07-23 18:56:43 +02003614 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003615 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003616
Harald Welte4bfdfe72009-06-10 23:11:52 +08003617 if (msg_type & 0x80) {
3618 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3619 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003620 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003621
3622 /* Find transaction */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003623 trans = trans_find_by_id(lchan, transaction_id);
3624
Harald Welte6f5aee02009-07-23 21:21:14 +02003625 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003626 "Received '%s' from MS in state %d (%s)\n",
3627 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3628 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Welteaa0b29c2009-07-23 18:56:43 +02003629 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3630 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003631
3632 /* Create transaction */
3633 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003634 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003635 "creating new trans.\n", transaction_id);
3636 /* Create transaction */
Harald Welteaa0b29c2009-07-23 18:56:43 +02003637 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3638 transaction_id, new_callref++);
3639 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003640 DEBUGP(DCC, "No memory for trans.\n");
3641 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003642 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003643 GSM48_MT_CC_RELEASE_COMPL);
3644 return -ENOMEM;
3645 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003646 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003647 trans->lchan = lchan;
3648 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003649 }
3650
3651 /* find function for current state and message */
3652 for (i = 0; i < DATASLLEN; i++)
3653 if ((msg_type == datastatelist[i].type)
Harald Welteaa0b29c2009-07-23 18:56:43 +02003654 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003655 break;
3656 if (i == DATASLLEN) {
3657 DEBUGP(DCC, "Message unhandled at this state.\n");
3658 return 0;
3659 }
3660
3661 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003662
3663 return rc;
3664}
3665
Harald Welte52b1f982008-12-23 20:25:15 +00003666/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3667int gsm0408_rcvmsg(struct msgb *msg)
3668{
3669 struct gsm48_hdr *gh = msgb_l3(msg);
3670 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003671 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003672
3673 switch (pdisc) {
3674 case GSM48_PDISC_CC:
3675 rc = gsm0408_rcv_cc(msg);
3676 break;
3677 case GSM48_PDISC_MM:
3678 rc = gsm0408_rcv_mm(msg);
3679 break;
3680 case GSM48_PDISC_RR:
3681 rc = gsm0408_rcv_rr(msg);
3682 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003683 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003684 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003685 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003686 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003687 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003688 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3689 pdisc);
3690 break;
3691 default:
3692 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3693 pdisc);
3694 break;
3695 }
3696
3697 return rc;
3698}
Harald Welte8470bf22008-12-25 23:28:35 +00003699
Harald Welte8470bf22008-12-25 23:28:35 +00003700/* Section 9.1.8 / Table 9.9 */
3701struct chreq {
3702 u_int8_t val;
3703 u_int8_t mask;
3704 enum chreq_type type;
3705};
3706
3707/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3708static const struct chreq chreq_type_neci1[] = {
3709 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3710 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3711 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3712 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3713 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3714 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3715 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3716 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3717 { 0x10, 0xf0, CHREQ_T_SDCCH },
3718 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3719 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3720 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3721};
3722
3723/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3724static const struct chreq chreq_type_neci0[] = {
3725 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3726 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3727 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3728 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3729 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3730 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3731 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3732 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3733};
3734
3735static const enum gsm_chan_t ctype_by_chreq[] = {
3736 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3737 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3738 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3739 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3740 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3741 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3742 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3743 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3744 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3745 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3746 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3747 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3748};
3749
Harald Weltee14a57c2008-12-29 04:08:28 +00003750static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3751 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3752 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3753 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3754 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3755 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3756 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3757 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3758 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3759 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3760 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3761 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3762 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3763};
3764
Harald Welte8470bf22008-12-25 23:28:35 +00003765enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3766{
3767 int i;
3768 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3769
3770 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3771 const struct chreq *chr = &chreq_type_neci0[i];
3772 if ((ra & chr->mask) == chr->val)
3773 return ctype_by_chreq[chr->type];
3774 }
3775 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3776 return GSM_LCHAN_SDCCH;
3777}
Harald Weltee14a57c2008-12-29 04:08:28 +00003778
3779enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3780{
3781 int i;
3782 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3783
3784 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3785 const struct chreq *chr = &chreq_type_neci0[i];
3786 if ((ra & chr->mask) == chr->val)
3787 return reason_by_chreq[chr->type];
3788 }
3789 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3790 return GSM_CHREQ_REASON_OTHER;
3791}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003792
3793/* dequeue messages to layer 4 */
3794int bsc_upqueue(struct gsm_network *net)
3795{
3796 struct gsm_mncc *mncc;
3797 struct msgb *msg;
3798 int work = 0;
3799
3800 if (net)
3801 while ((msg = msgb_dequeue(&net->upqueue))) {
3802 mncc = (struct gsm_mncc *)msg->data;
3803 if (net->mncc_recv)
3804 net->mncc_recv(net, mncc->msg_type, mncc);
3805 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003806 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003807 }
3808
3809 return work;
3810}
Harald Welteaa0b29c2009-07-23 18:56:43 +02003811
Harald Welte805f6442009-07-28 18:25:29 +02003812/*
3813 * This will be ran by the linker when loading the DSO. We use it to
3814 * do system initialization, e.g. registration of signal handlers.
3815 */
3816static __attribute__((constructor)) void on_dso_load_0408(void)
3817{
3818 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3819 "loc_updating_oper");
3820 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3821 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3822}