blob: e0f15f69f593aeb1b5e142734ad4bf9b1ee7e29d [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 Weltedcaf5652009-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;
Harald Welte5a691b52009-07-05 04:05:44 +0200248 if ((data[1] & 0x40) == 0x00)
Harald Weltef7c43522009-06-09 20:24:21 +0000249 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 Weltedcaf5652009-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 Weltedcaf5652009-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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte13cac662009-07-29 12:10:35 +02001281/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Harald Welte7584aea2009-02-11 11:44:12 +00001282int 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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte9176bd42009-07-23 18:46:00 +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 Welte13cac662009-07-29 12:10:35 +02001747 /* We've successfully modified the MS side of the channel,
1748 * now go on to modify the BTS side of the channel */
Harald Welte9943c5b2009-07-29 15:41:29 +02001749 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
Harald Welte2c38aa82009-02-18 03:44:24 +00001750 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001751 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001752 case GSM48_MT_RR_STATUS:
1753 rc = gsm48_rx_rr_status(msg);
1754 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001755 case GSM48_MT_RR_MEAS_REP:
1756 rc = gsm48_rx_rr_meas_rep(msg);
1757 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001758 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001759 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001760 gh->msg_type);
1761 break;
1762 }
1763
Harald Welte2d35ae62009-02-06 12:02:13 +00001764 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001765}
1766
Holger Freythere64a7a32009-02-06 21:55:37 +00001767/* 7.1.7 and 9.1.7 Channel release*/
1768int gsm48_send_rr_release(struct gsm_lchan *lchan)
1769{
1770 struct msgb *msg = gsm48_msgb_alloc();
1771 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1772 u_int8_t *cause;
1773
1774 msg->lchan = lchan;
1775 gh->proto_discr = GSM48_PDISC_RR;
1776 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1777
1778 cause = msgb_put(msg, 1);
1779 cause[0] = GSM48_RR_CAUSE_NORMAL;
1780
1781 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1782 lchan->nr, lchan->type);
1783
Harald Welteae0f2362009-07-19 18:36:49 +02001784 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001785 gsm48_sendmsg(msg, NULL);
Harald Welteae0f2362009-07-19 18:36:49 +02001786
1787 /* Deactivate the SACCH on the BTS side */
1788 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001789}
1790
Harald Welte4bc90a12008-12-27 16:32:52 +00001791/* Call Control */
1792
Harald Welte7584aea2009-02-11 11:44:12 +00001793/* The entire call control code is written in accordance with Figure 7.10c
1794 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1795 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1796 * it for voice */
1797
Harald Welte4bfdfe72009-06-10 23:11:52 +08001798static void new_cc_state(struct gsm_trans *trans, int state)
1799{
1800 if (state > 31 || state < 0)
1801 return;
1802
1803 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001804 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001805
Harald Weltedcaf5652009-07-23 18:56:43 +02001806 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001807}
1808
1809static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001810{
1811 struct msgb *msg = gsm48_msgb_alloc();
1812 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1813 u_int8_t *cause, *call_state;
1814
Harald Welte4bc90a12008-12-27 16:32:52 +00001815 gh->msg_type = GSM48_MT_CC_STATUS;
1816
1817 cause = msgb_put(msg, 3);
1818 cause[0] = 2;
1819 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1820 cause[2] = 0x80 | 30; /* response to status inquiry */
1821
1822 call_state = msgb_put(msg, 1);
1823 call_state[0] = 0xc0 | 0x00;
1824
Harald Welte39e2ead2009-07-23 21:13:03 +02001825 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001826}
1827
Harald Welte6f4b7532008-12-29 00:39:37 +00001828static int gsm48_tx_simple(struct gsm_lchan *lchan,
1829 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001830{
1831 struct msgb *msg = gsm48_msgb_alloc();
1832 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1833
1834 msg->lchan = lchan;
1835
Harald Welte6f4b7532008-12-29 00:39:37 +00001836 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001837 gh->msg_type = msg_type;
1838
Harald Welte39e2ead2009-07-23 21:13:03 +02001839 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001840}
1841
Harald Welte4bfdfe72009-06-10 23:11:52 +08001842static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1843{
Harald Weltedcaf5652009-07-23 18:56:43 +02001844 if (bsc_timer_pending(&trans->cc.timer)) {
1845 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1846 bsc_del_timer(&trans->cc.timer);
1847 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001848 }
1849}
1850
1851static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1852 int msg_type, struct gsm_mncc *mncc)
1853{
1854 struct msgb *msg;
1855
1856 if (trans)
1857 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001858 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001859 "Sending '%s' to MNCC.\n",
1860 trans->lchan->ts->trx->bts->nr,
1861 trans->lchan->ts->trx->nr,
1862 trans->lchan->ts->nr, trans->transaction_id,
1863 (trans->subscr)?(trans->subscr->extension):"-",
1864 get_mncc_name(msg_type));
1865 else
1866 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1867 "Sending '%s' to MNCC.\n",
1868 (trans->subscr)?(trans->subscr->extension):"-",
1869 get_mncc_name(msg_type));
1870 else
1871 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1872 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1873
1874 mncc->msg_type = msg_type;
1875
Harald Welte966636f2009-06-26 19:39:35 +02001876 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001877 if (!msg)
1878 return -ENOMEM;
1879 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1880 msgb_enqueue(&net->upqueue, msg);
1881
1882 return 0;
1883}
1884
1885int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1886 u_int32_t callref, int location, int value)
1887{
1888 struct gsm_mncc rel;
1889
Harald Welte92f70c52009-06-12 01:54:08 +08001890 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001891 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001892 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001893 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1894}
1895
Harald Weltedcaf5652009-07-23 18:56:43 +02001896/* Call Control Specific transaction release.
1897 * gets called by trans_free, DO NOT CALL YOURSELF! */
1898void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001899{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001900 gsm48_stop_cc_timer(trans);
1901
1902 /* send release to L4, if callref still exists */
1903 if (trans->callref) {
1904 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02001905 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001906 GSM48_CAUSE_LOC_PRN_S_LU,
1907 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001908 }
Harald Weltedcaf5652009-07-23 18:56:43 +02001909 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001910 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02001911 if (trans->lchan)
1912 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001913}
1914
1915static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1916
Harald Welte09e38af2009-02-16 22:52:23 +00001917/* call-back from paging the B-end of the connection */
1918static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001919 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001920{
Harald Welte7ccf7782009-02-17 01:43:01 +00001921 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001922 struct gsm_subscriber *subscr = param;
1923 struct gsm_trans *transt, *tmp;
1924 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001925
Harald Welte09e38af2009-02-16 22:52:23 +00001926 if (hooknum != GSM_HOOK_RR_PAGING)
1927 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001928
1929 if (!subscr)
1930 return -EINVAL;
1931 net = subscr->net;
1932 if (!net) {
1933 DEBUGP(DCC, "Error Network not set!\n");
1934 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00001935 }
Harald Welte7584aea2009-02-11 11:44:12 +00001936
Harald Welte4bfdfe72009-06-10 23:11:52 +08001937 /* check all tranactions (without lchan) for subscriber */
1938 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1939 if (transt->subscr != subscr || transt->lchan)
1940 continue;
1941 switch (event) {
1942 case GSM_PAGING_SUCCEEDED:
1943 if (!lchan) // paranoid
1944 break;
1945 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1946 subscr->extension);
1947 /* Assign lchan */
1948 if (!transt->lchan) {
1949 transt->lchan = lchan;
1950 use_lchan(lchan);
1951 }
1952 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02001953 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001954 break;
1955 case GSM_PAGING_EXPIRED:
1956 DEBUGP(DCC, "Paging subscr %s expired!\n",
1957 subscr->extension);
1958 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02001959 mncc_release_ind(transt->subscr->net, transt,
1960 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001961 GSM48_CAUSE_LOC_PRN_S_LU,
1962 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001963 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02001964 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001965 break;
1966 }
1967 }
Harald Welte09e38af2009-02-16 22:52:23 +00001968 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00001969}
Harald Welte7584aea2009-02-11 11:44:12 +00001970
Harald Welte805f6442009-07-28 18:25:29 +02001971/* some other part of the code sends us a signal */
1972static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
1973 void *handler_data, void *signal_data)
1974{
1975 struct gsm_lchan *lchan = signal_data;
1976 struct gsm_bts_trx_ts *ts;
1977 int rc;
1978
1979 if (subsys != SS_ABISIP)
1980 return 0;
1981
1982 /* in case we use direct BTS-to-BTS RTP */
1983 if (ipacc_rtp_direct)
1984 return 0;
1985
1986 ts = lchan->ts;
1987
1988 switch (signal) {
1989 case S_ABISIP_BIND_ACK:
1990 /* the BTS has successfully bound a TCH to a local ip/port,
1991 * which means we can connect our UDP socket to it */
1992 if (ts->abis_ip.rtp_socket) {
1993 rtp_socket_free(ts->abis_ip.rtp_socket);
1994 ts->abis_ip.rtp_socket = NULL;
1995 }
1996
1997 ts->abis_ip.rtp_socket = rtp_socket_create();
1998 if (!ts->abis_ip.rtp_socket)
1999 goto out_err;
2000
2001 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2002 ts->abis_ip.bound_ip,
2003 ts->abis_ip.bound_port);
2004 if (rc < 0)
2005 goto out_err;
2006 break;
2007 case S_ABISIP_DISC_IND:
2008 /* the BTS tells us a RTP stream has been disconnected */
2009 if (ts->abis_ip.rtp_socket) {
2010 rtp_socket_free(ts->abis_ip.rtp_socket);
2011 ts->abis_ip.rtp_socket = NULL;
2012 }
2013 break;
2014 }
2015
2016 return 0;
2017out_err:
2018 /* FIXME: do something */
2019 return 0;
2020}
2021
2022/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2023static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2024{
2025 struct gsm_bts_trx_ts *ts = lchan->ts;
2026 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2027 int rc;
2028
2029 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2030 ntohs(rs->rtp.sin_local.sin_port),
2031 ts->abis_ip.conn_id,
2032 /* FIXME: use RTP payload of bound socket, not BTS*/
2033 ts->abis_ip.rtp_payload2);
2034
2035 return rc;
2036}
2037
Harald Welte49f48b82009-02-17 15:29:33 +00002038/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002039static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002040{
Harald Welte11fa29c2009-02-19 17:24:39 +00002041 struct gsm_bts *bts = lchan->ts->trx->bts;
2042 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002043 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002044 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002045
Harald Welte11fa29c2009-02-19 17:24:39 +00002046 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2047 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2048 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2049
2050 if (bts->type != remote_bts->type) {
2051 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2052 return -EINVAL;
2053 }
Harald Welte49f48b82009-02-17 15:29:33 +00002054
Harald Welte11fa29c2009-02-19 17:24:39 +00002055 switch (bts->type) {
2056 case GSM_BTS_TYPE_NANOBTS_900:
2057 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002058 if (!ipacc_rtp_direct) {
2059 /* connect the TCH's to our RTP proxy */
2060 rc = ipacc_connect_proxy_bind(lchan);
2061 if (rc < 0)
2062 return rc;
2063 rc = ipacc_connect_proxy_bind(remote_lchan);
2064
2065 /* connect them with each other */
2066 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2067 remote_lchan->ts->abis_ip.rtp_socket);
2068 } else {
2069 /* directly connect TCH RTP streams to each other */
2070 ts = remote_lchan->ts;
2071 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2072 ts->abis_ip.bound_port,
2073 lchan->ts->abis_ip.conn_id,
2074 ts->abis_ip.rtp_payload2);
2075 if (rc < 0)
2076 return rc;
2077 ts = lchan->ts;
2078 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2079 ts->abis_ip.bound_port,
2080 remote_lchan->ts->abis_ip.conn_id,
2081 ts->abis_ip.rtp_payload2);
2082 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002083 break;
2084 case GSM_BTS_TYPE_BS11:
2085 trau_mux_map_lchan(lchan, remote_lchan);
2086 break;
2087 default:
2088 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002089 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002090 break;
2091 }
Harald Welte49f48b82009-02-17 15:29:33 +00002092
2093 return 0;
2094}
2095
Harald Welte4bfdfe72009-06-10 23:11:52 +08002096/* bridge channels of two transactions */
2097static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002098{
Harald Weltedcaf5652009-07-23 18:56:43 +02002099 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2100 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002101
Harald Welte4bfdfe72009-06-10 23:11:52 +08002102 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002103 return -EIO;
2104
Harald Welte4bfdfe72009-06-10 23:11:52 +08002105 if (!trans1->lchan || !trans2->lchan)
2106 return -EIO;
2107
2108 /* through-connect channel */
2109 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002110}
2111
Harald Welte4bfdfe72009-06-10 23:11:52 +08002112/* enable receive of channels to upqueue */
2113static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2114{
2115 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002116
Harald Welte4bfdfe72009-06-10 23:11:52 +08002117 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002118 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002119 if (!trans)
2120 return -EIO;
2121 if (!trans->lchan)
2122 return 0;
2123
2124 // todo IPACCESS
2125 if (enable)
2126 return trau_recv_lchan(trans->lchan, data->callref);
2127 return trau_mux_unmap(NULL, data->callref);
2128}
2129
2130/* send a frame to channel */
2131static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2132{
2133 struct gsm_trans *trans;
2134
2135 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002136 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002137 if (!trans)
2138 return -EIO;
2139 if (!trans->lchan)
2140 return 0;
2141 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2142 trans->lchan->type != GSM_LCHAN_TCH_H)
2143 return 0;
2144
2145 // todo IPACCESS
2146 return trau_send_lchan(trans->lchan,
2147 (struct decoded_trau_frame *)frame->data);
2148}
2149
2150
2151static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2152{
2153 DEBUGP(DCC, "-> STATUS ENQ\n");
2154 return gsm48_cc_tx_status(trans, msg);
2155}
2156
2157static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2158static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2159
2160static void gsm48_cc_timeout(void *arg)
2161{
2162 struct gsm_trans *trans = arg;
2163 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002164 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2165 int mo_location = GSM48_CAUSE_LOC_USER;
2166 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2167 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002168 struct gsm_mncc mo_rel, l4_rel;
2169
2170 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2171 mo_rel.callref = trans->callref;
2172 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2173 l4_rel.callref = trans->callref;
2174
Harald Weltedcaf5652009-07-23 18:56:43 +02002175 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002176 case 0x303:
2177 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002178 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002179 break;
2180 case 0x310:
2181 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002182 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002183 break;
2184 case 0x313:
2185 disconnect = 1;
2186 /* unknown, did not find it in the specs */
2187 break;
2188 case 0x301:
2189 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002190 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002191 break;
2192 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002193 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002194 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002195 gsm48_cc_tx_release(trans, &trans->cc.msg);
2196 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002197 break; /* stay in release state */
2198 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002199 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002200 return;
2201// release = 1;
2202// l4_cause = 14;
2203// break;
2204 case 0x306:
2205 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002206 mo_cause = trans->cc.msg.cause.value;
2207 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002208 break;
2209 case 0x323:
2210 disconnect = 1;
2211 break;
2212 default:
2213 release = 1;
2214 }
2215
2216 if (release && trans->callref) {
2217 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002218 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002219 l4_location, l4_cause);
2220 trans->callref = 0;
2221 }
2222
2223 if (disconnect && trans->callref) {
2224 /* process disconnect towards layer 4 */
2225 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002226 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002227 }
2228
2229 /* process disconnect towards mobile station */
2230 if (disconnect || release) {
2231 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002232 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2233 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2234 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002235 mo_rel.cause.diag_len = 3;
2236
2237 if (disconnect)
2238 gsm48_cc_tx_disconnect(trans, &mo_rel);
2239 if (release)
2240 gsm48_cc_tx_release(trans, &mo_rel);
2241 }
2242
2243}
2244
2245static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2246 int sec, int micro)
2247{
2248 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002249 trans->cc.timer.cb = gsm48_cc_timeout;
2250 trans->cc.timer.data = trans;
2251 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2252 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002253}
2254
2255static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2256{
2257 struct gsm48_hdr *gh = msgb_l3(msg);
2258 u_int8_t msg_type = gh->msg_type & 0xbf;
2259 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2260 struct tlv_parsed tp;
2261 struct gsm_mncc setup;
2262
2263 memset(&setup, 0, sizeof(struct gsm_mncc));
2264 setup.callref = trans->callref;
2265 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2266 /* emergency setup is identified by msg_type */
2267 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2268 setup.emergency = 1;
2269
2270 /* use subscriber as calling party number */
2271 if (trans->subscr) {
2272 setup.fields |= MNCC_F_CALLING;
2273 strncpy(setup.calling.number, trans->subscr->extension,
2274 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002275 strncpy(setup.imsi, trans->subscr->imsi,
2276 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002277 }
2278 /* bearer capability */
2279 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2280 setup.fields |= MNCC_F_BEARER_CAP;
2281 decode_bearer_cap(&setup.bearer_cap,
2282 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2283 }
2284 /* facility */
2285 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2286 setup.fields |= MNCC_F_FACILITY;
2287 decode_facility(&setup.facility,
2288 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2289 }
2290 /* called party bcd number */
2291 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2292 setup.fields |= MNCC_F_CALLED;
2293 decode_called(&setup.called,
2294 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2295 }
2296 /* user-user */
2297 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2298 setup.fields |= MNCC_F_USERUSER;
2299 decode_useruser(&setup.useruser,
2300 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2301 }
2302 /* ss-version */
2303 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2304 setup.fields |= MNCC_F_SSVERSION;
2305 decode_ssversion(&setup.ssversion,
2306 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2307 }
2308 /* CLIR suppression */
2309 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2310 setup.clir.sup = 1;
2311 /* CLIR invocation */
2312 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2313 setup.clir.inv = 1;
2314 /* cc cap */
2315 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2316 setup.fields |= MNCC_F_CCCAP;
2317 decode_cccap(&setup.cccap,
2318 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2319 }
2320
Harald Welte4bfdfe72009-06-10 23:11:52 +08002321 new_cc_state(trans, GSM_CSTATE_INITIATED);
2322
2323 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002324 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002325
Harald Welte13cac662009-07-29 12:10:35 +02002326 /* MNCC code will modify the channel asynchronously, we should
2327 * ipaccess-bind only after the modification has been made to the
2328 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002329 return 0;
2330}
2331
2332static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002333{
2334 struct msgb *msg = gsm48_msgb_alloc();
2335 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002336 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002337 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002338
Harald Welte7ccf7782009-02-17 01:43:01 +00002339 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002340
Harald Welte4bfdfe72009-06-10 23:11:52 +08002341 /* transaction id must not be assigned */
2342 if (trans->transaction_id != 0xff) { /* unasssigned */
2343 DEBUGP(DCC, "TX Setup with assigned transaction. "
2344 "This is not allowed!\n");
2345 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002346 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002347 GSM48_CAUSE_LOC_PRN_S_LU,
2348 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002349 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002350 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002351 return rc;
2352 }
2353
2354 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002355 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2356 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002357 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002358 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002359 GSM48_CAUSE_LOC_PRN_S_LU,
2360 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002361 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002362 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002363 return rc;
2364 }
Harald Welte78283ef2009-07-23 21:36:44 +02002365 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002366
Harald Welte65e74cc2008-12-29 01:55:35 +00002367 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002368
Harald Welte4bfdfe72009-06-10 23:11:52 +08002369 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002370
Harald Welte4bfdfe72009-06-10 23:11:52 +08002371 /* bearer capability */
2372 if (setup->fields & MNCC_F_BEARER_CAP)
2373 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2374 /* facility */
2375 if (setup->fields & MNCC_F_FACILITY)
2376 encode_facility(msg, 0, &setup->facility);
2377 /* progress */
2378 if (setup->fields & MNCC_F_PROGRESS)
2379 encode_progress(msg, 0, &setup->progress);
2380 /* calling party BCD number */
2381 if (setup->fields & MNCC_F_CALLING)
2382 encode_calling(msg, &setup->calling);
2383 /* called party BCD number */
2384 if (setup->fields & MNCC_F_CALLED)
2385 encode_called(msg, &setup->called);
2386 /* user-user */
2387 if (setup->fields & MNCC_F_USERUSER)
2388 encode_useruser(msg, 0, &setup->useruser);
2389 /* redirecting party BCD number */
2390 if (setup->fields & MNCC_F_REDIRECTING)
2391 encode_redirecting(msg, &setup->redirecting);
2392 /* signal */
2393 if (setup->fields & MNCC_F_SIGNAL)
2394 encode_signal(msg, setup->signal);
2395
2396 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002397
Harald Welte39e2ead2009-07-23 21:13:03 +02002398 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002399}
2400
Harald Welte4bfdfe72009-06-10 23:11:52 +08002401static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2402{
2403 struct gsm48_hdr *gh = msgb_l3(msg);
2404 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2405 struct tlv_parsed tp;
2406 struct gsm_mncc call_conf;
2407
2408 gsm48_stop_cc_timer(trans);
2409 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2410
2411 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2412 call_conf.callref = trans->callref;
2413 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2414#if 0
2415 /* repeat */
2416 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2417 call_conf.repeat = 1;
2418 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2419 call_conf.repeat = 2;
2420#endif
2421 /* bearer capability */
2422 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2423 call_conf.fields |= MNCC_F_BEARER_CAP;
2424 decode_bearer_cap(&call_conf.bearer_cap,
2425 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2426 }
2427 /* cause */
2428 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2429 call_conf.fields |= MNCC_F_CAUSE;
2430 decode_cause(&call_conf.cause,
2431 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2432 }
2433 /* cc cap */
2434 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2435 call_conf.fields |= MNCC_F_CCCAP;
2436 decode_cccap(&call_conf.cccap,
2437 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2438 }
2439
2440 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2441
Harald Welte596fed42009-07-23 19:06:52 +02002442 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2443 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002444}
2445
2446static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2447{
2448 struct gsm_mncc *proceeding = arg;
2449 struct msgb *msg = gsm48_msgb_alloc();
2450 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2451
Harald Welte4bfdfe72009-06-10 23:11:52 +08002452 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2453
2454 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2455
2456 /* bearer capability */
2457 if (proceeding->fields & MNCC_F_BEARER_CAP)
2458 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2459 /* facility */
2460 if (proceeding->fields & MNCC_F_FACILITY)
2461 encode_facility(msg, 0, &proceeding->facility);
2462 /* progress */
2463 if (proceeding->fields & MNCC_F_PROGRESS)
2464 encode_progress(msg, 0, &proceeding->progress);
2465
Harald Welte39e2ead2009-07-23 21:13:03 +02002466 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002467}
2468
2469static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2470{
2471 struct gsm48_hdr *gh = msgb_l3(msg);
2472 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2473 struct tlv_parsed tp;
2474 struct gsm_mncc alerting;
2475
2476 gsm48_stop_cc_timer(trans);
2477 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2478
2479 memset(&alerting, 0, sizeof(struct gsm_mncc));
2480 alerting.callref = trans->callref;
2481 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2482 /* facility */
2483 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2484 alerting.fields |= MNCC_F_FACILITY;
2485 decode_facility(&alerting.facility,
2486 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2487 }
2488
2489 /* progress */
2490 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2491 alerting.fields |= MNCC_F_PROGRESS;
2492 decode_progress(&alerting.progress,
2493 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2494 }
2495 /* ss-version */
2496 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2497 alerting.fields |= MNCC_F_SSVERSION;
2498 decode_ssversion(&alerting.ssversion,
2499 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2500 }
2501
2502 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2503
Harald Welte596fed42009-07-23 19:06:52 +02002504 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2505 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002506}
2507
2508static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2509{
2510 struct gsm_mncc *alerting = arg;
2511 struct msgb *msg = gsm48_msgb_alloc();
2512 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2513
Harald Welte4bfdfe72009-06-10 23:11:52 +08002514 gh->msg_type = GSM48_MT_CC_ALERTING;
2515
2516 /* facility */
2517 if (alerting->fields & MNCC_F_FACILITY)
2518 encode_facility(msg, 0, &alerting->facility);
2519 /* progress */
2520 if (alerting->fields & MNCC_F_PROGRESS)
2521 encode_progress(msg, 0, &alerting->progress);
2522 /* user-user */
2523 if (alerting->fields & MNCC_F_USERUSER)
2524 encode_useruser(msg, 0, &alerting->useruser);
2525
2526 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2527
Harald Welte39e2ead2009-07-23 21:13:03 +02002528 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002529}
2530
2531static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2532{
2533 struct gsm_mncc *progress = arg;
2534 struct msgb *msg = gsm48_msgb_alloc();
2535 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2536
Harald Welte4bfdfe72009-06-10 23:11:52 +08002537 gh->msg_type = GSM48_MT_CC_PROGRESS;
2538
2539 /* progress */
2540 encode_progress(msg, 1, &progress->progress);
2541 /* user-user */
2542 if (progress->fields & MNCC_F_USERUSER)
2543 encode_useruser(msg, 0, &progress->useruser);
2544
Harald Welte39e2ead2009-07-23 21:13:03 +02002545 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002546}
2547
2548static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2549{
2550 struct gsm_mncc *connect = arg;
2551 struct msgb *msg = gsm48_msgb_alloc();
2552 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2553
Harald Welte4bfdfe72009-06-10 23:11:52 +08002554 gh->msg_type = GSM48_MT_CC_CONNECT;
2555
2556 gsm48_stop_cc_timer(trans);
2557 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2558
2559 /* facility */
2560 if (connect->fields & MNCC_F_FACILITY)
2561 encode_facility(msg, 0, &connect->facility);
2562 /* progress */
2563 if (connect->fields & MNCC_F_PROGRESS)
2564 encode_progress(msg, 0, &connect->progress);
2565 /* connected number */
2566 if (connect->fields & MNCC_F_CONNECTED)
2567 encode_connected(msg, &connect->connected);
2568 /* user-user */
2569 if (connect->fields & MNCC_F_USERUSER)
2570 encode_useruser(msg, 0, &connect->useruser);
2571
2572 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2573
Harald Welte39e2ead2009-07-23 21:13:03 +02002574 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002575}
2576
2577static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2578{
2579 struct gsm48_hdr *gh = msgb_l3(msg);
2580 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2581 struct tlv_parsed tp;
2582 struct gsm_mncc connect;
2583
2584 gsm48_stop_cc_timer(trans);
2585
2586 memset(&connect, 0, sizeof(struct gsm_mncc));
2587 connect.callref = trans->callref;
2588 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2589 /* use subscriber as connected party number */
2590 if (trans->subscr) {
2591 connect.fields |= MNCC_F_CONNECTED;
2592 strncpy(connect.connected.number, trans->subscr->extension,
2593 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002594 strncpy(connect.imsi, trans->subscr->imsi,
2595 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002596 }
2597 /* facility */
2598 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2599 connect.fields |= MNCC_F_FACILITY;
2600 decode_facility(&connect.facility,
2601 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2602 }
2603 /* user-user */
2604 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2605 connect.fields |= MNCC_F_USERUSER;
2606 decode_useruser(&connect.useruser,
2607 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2608 }
2609 /* ss-version */
2610 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2611 connect.fields |= MNCC_F_SSVERSION;
2612 decode_ssversion(&connect.ssversion,
2613 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2614 }
2615
2616 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2617
Harald Welte596fed42009-07-23 19:06:52 +02002618 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002619}
2620
2621
2622static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2623{
2624 struct gsm_mncc connect_ack;
2625
2626 gsm48_stop_cc_timer(trans);
2627
2628 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2629
2630 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2631 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002632 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002633 &connect_ack);
2634}
2635
2636static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2637{
2638 struct msgb *msg = gsm48_msgb_alloc();
2639 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2640
Harald Welte4bfdfe72009-06-10 23:11:52 +08002641 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2642
2643 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2644
Harald Welte39e2ead2009-07-23 21:13:03 +02002645 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002646}
2647
2648static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2649{
2650 struct gsm48_hdr *gh = msgb_l3(msg);
2651 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2652 struct tlv_parsed tp;
2653 struct gsm_mncc disc;
2654
2655 gsm48_stop_cc_timer(trans);
2656
2657 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2658
2659 memset(&disc, 0, sizeof(struct gsm_mncc));
2660 disc.callref = trans->callref;
2661 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2662 /* cause */
2663 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2664 disc.fields |= MNCC_F_CAUSE;
2665 decode_cause(&disc.cause,
2666 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2667 }
2668 /* facility */
2669 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2670 disc.fields |= MNCC_F_FACILITY;
2671 decode_facility(&disc.facility,
2672 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2673 }
2674 /* user-user */
2675 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2676 disc.fields |= MNCC_F_USERUSER;
2677 decode_useruser(&disc.useruser,
2678 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2679 }
2680 /* ss-version */
2681 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2682 disc.fields |= MNCC_F_SSVERSION;
2683 decode_ssversion(&disc.ssversion,
2684 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2685 }
2686
Harald Welte596fed42009-07-23 19:06:52 +02002687 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002688
2689}
2690
Harald Weltec66b71c2009-06-11 14:23:20 +08002691static struct gsm_mncc_cause default_cause = {
2692 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2693 .coding = 0,
2694 .rec = 0,
2695 .rec_val = 0,
2696 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2697 .diag_len = 0,
2698 .diag = { 0 },
2699};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002700
2701static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2702{
2703 struct gsm_mncc *disc = arg;
2704 struct msgb *msg = gsm48_msgb_alloc();
2705 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2706
Harald Welte4bfdfe72009-06-10 23:11:52 +08002707 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2708
2709 gsm48_stop_cc_timer(trans);
2710 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2711
2712 /* cause */
2713 if (disc->fields & MNCC_F_CAUSE)
2714 encode_cause(msg, 1, &disc->cause);
2715 else
2716 encode_cause(msg, 1, &default_cause);
2717
2718 /* facility */
2719 if (disc->fields & MNCC_F_FACILITY)
2720 encode_facility(msg, 0, &disc->facility);
2721 /* progress */
2722 if (disc->fields & MNCC_F_PROGRESS)
2723 encode_progress(msg, 0, &disc->progress);
2724 /* user-user */
2725 if (disc->fields & MNCC_F_USERUSER)
2726 encode_useruser(msg, 0, &disc->useruser);
2727
2728 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002729 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002730
2731 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2732
Harald Welte39e2ead2009-07-23 21:13:03 +02002733 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002734}
2735
2736static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2737{
2738 struct gsm48_hdr *gh = msgb_l3(msg);
2739 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2740 struct tlv_parsed tp;
2741 struct gsm_mncc rel;
2742 int rc;
2743
2744 gsm48_stop_cc_timer(trans);
2745
2746 memset(&rel, 0, sizeof(struct gsm_mncc));
2747 rel.callref = trans->callref;
2748 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2749 /* cause */
2750 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2751 rel.fields |= MNCC_F_CAUSE;
2752 decode_cause(&rel.cause,
2753 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2754 }
2755 /* facility */
2756 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2757 rel.fields |= MNCC_F_FACILITY;
2758 decode_facility(&rel.facility,
2759 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2760 }
2761 /* user-user */
2762 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2763 rel.fields |= MNCC_F_USERUSER;
2764 decode_useruser(&rel.useruser,
2765 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2766 }
2767 /* ss-version */
2768 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2769 rel.fields |= MNCC_F_SSVERSION;
2770 decode_ssversion(&rel.ssversion,
2771 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2772 }
2773
Harald Weltedcaf5652009-07-23 18:56:43 +02002774 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002775 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002776 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002777 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002778 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002779 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002780 GSM48_MT_CC_RELEASE_COMPL);
2781 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002782 }
2783
2784 new_cc_state(trans, GSM_CSTATE_NULL);
2785
2786 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002787 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002788
2789 return rc;
2790}
2791
2792static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2793{
2794 struct gsm_mncc *rel = arg;
2795 struct msgb *msg = gsm48_msgb_alloc();
2796 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2797
Harald Welte4bfdfe72009-06-10 23:11:52 +08002798 gh->msg_type = GSM48_MT_CC_RELEASE;
2799
2800 trans->callref = 0;
2801
2802 gsm48_stop_cc_timer(trans);
2803 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2804
2805 /* cause */
2806 if (rel->fields & MNCC_F_CAUSE)
2807 encode_cause(msg, 0, &rel->cause);
2808 /* facility */
2809 if (rel->fields & MNCC_F_FACILITY)
2810 encode_facility(msg, 0, &rel->facility);
2811 /* user-user */
2812 if (rel->fields & MNCC_F_USERUSER)
2813 encode_useruser(msg, 0, &rel->useruser);
2814
Harald Weltedcaf5652009-07-23 18:56:43 +02002815 trans->cc.T308_second = 0;
2816 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002817
Harald Weltedcaf5652009-07-23 18:56:43 +02002818 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002819 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2820
Harald Welte39e2ead2009-07-23 21:13:03 +02002821 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002822}
2823
2824static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2825{
2826 struct gsm48_hdr *gh = msgb_l3(msg);
2827 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2828 struct tlv_parsed tp;
2829 struct gsm_mncc rel;
2830 int rc = 0;
2831
2832 gsm48_stop_cc_timer(trans);
2833
2834 memset(&rel, 0, sizeof(struct gsm_mncc));
2835 rel.callref = trans->callref;
2836 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2837 /* cause */
2838 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2839 rel.fields |= MNCC_F_CAUSE;
2840 decode_cause(&rel.cause,
2841 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2842 }
2843 /* facility */
2844 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2845 rel.fields |= MNCC_F_FACILITY;
2846 decode_facility(&rel.facility,
2847 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2848 }
2849 /* user-user */
2850 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2851 rel.fields |= MNCC_F_USERUSER;
2852 decode_useruser(&rel.useruser,
2853 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2854 }
2855 /* ss-version */
2856 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2857 rel.fields |= MNCC_F_SSVERSION;
2858 decode_ssversion(&rel.ssversion,
2859 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2860 }
2861
2862 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002863 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002864 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002865 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002866 MNCC_REJ_IND, &rel);
2867 break;
2868 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002869 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002870 MNCC_REL_CNF, &rel);
2871 break;
2872 default:
Harald Welte596fed42009-07-23 19:06:52 +02002873 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002874 MNCC_REL_IND, &rel);
2875 }
2876 }
2877
2878 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002879 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002880
2881 return rc;
2882}
2883
2884static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2885{
2886 struct gsm_mncc *rel = arg;
2887 struct msgb *msg = gsm48_msgb_alloc();
2888 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2889
Harald Welte4bfdfe72009-06-10 23:11:52 +08002890 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2891
2892 trans->callref = 0;
2893
2894 gsm48_stop_cc_timer(trans);
2895
2896 /* cause */
2897 if (rel->fields & MNCC_F_CAUSE)
2898 encode_cause(msg, 0, &rel->cause);
2899 /* facility */
2900 if (rel->fields & MNCC_F_FACILITY)
2901 encode_facility(msg, 0, &rel->facility);
2902 /* user-user */
2903 if (rel->fields & MNCC_F_USERUSER)
2904 encode_useruser(msg, 0, &rel->useruser);
2905
Harald Weltedcaf5652009-07-23 18:56:43 +02002906 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002907
Harald Welte39e2ead2009-07-23 21:13:03 +02002908 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002909}
2910
2911static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2912{
2913 struct gsm48_hdr *gh = msgb_l3(msg);
2914 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2915 struct tlv_parsed tp;
2916 struct gsm_mncc fac;
2917
2918 memset(&fac, 0, sizeof(struct gsm_mncc));
2919 fac.callref = trans->callref;
2920 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2921 /* facility */
2922 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2923 fac.fields |= MNCC_F_FACILITY;
2924 decode_facility(&fac.facility,
2925 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2926 }
2927 /* ss-version */
2928 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2929 fac.fields |= MNCC_F_SSVERSION;
2930 decode_ssversion(&fac.ssversion,
2931 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2932 }
2933
Harald Welte596fed42009-07-23 19:06:52 +02002934 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002935}
2936
2937static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2938{
2939 struct gsm_mncc *fac = arg;
2940 struct msgb *msg = gsm48_msgb_alloc();
2941 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2942
Harald Welte4bfdfe72009-06-10 23:11:52 +08002943 gh->msg_type = GSM48_MT_CC_FACILITY;
2944
2945 /* facility */
2946 encode_facility(msg, 1, &fac->facility);
2947
Harald Welte39e2ead2009-07-23 21:13:03 +02002948 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002949}
2950
2951static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2952{
2953 struct gsm_mncc hold;
2954
2955 memset(&hold, 0, sizeof(struct gsm_mncc));
2956 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002957 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002958}
2959
2960static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2961{
2962 struct msgb *msg = gsm48_msgb_alloc();
2963 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2964
Harald Welte4bfdfe72009-06-10 23:11:52 +08002965 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
2966
Harald Welte39e2ead2009-07-23 21:13:03 +02002967 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002968}
2969
2970static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
2971{
2972 struct gsm_mncc *hold_rej = arg;
2973 struct msgb *msg = gsm48_msgb_alloc();
2974 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2975
Harald Welte4bfdfe72009-06-10 23:11:52 +08002976 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
2977
2978 /* cause */
2979 if (hold_rej->fields & MNCC_F_CAUSE)
2980 encode_cause(msg, 1, &hold_rej->cause);
2981 else
2982 encode_cause(msg, 1, &default_cause);
2983
Harald Welte39e2ead2009-07-23 21:13:03 +02002984 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002985}
2986
2987static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
2988{
2989 struct gsm_mncc retrieve;
2990
2991 memset(&retrieve, 0, sizeof(struct gsm_mncc));
2992 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002993 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
2994 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002995}
2996
2997static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
2998{
2999 struct msgb *msg = gsm48_msgb_alloc();
3000 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3001
Harald Welte4bfdfe72009-06-10 23:11:52 +08003002 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3003
Harald Welte39e2ead2009-07-23 21:13:03 +02003004 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003005}
3006
3007static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3008{
3009 struct gsm_mncc *retrieve_rej = arg;
3010 struct msgb *msg = gsm48_msgb_alloc();
3011 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3012
Harald Welte4bfdfe72009-06-10 23:11:52 +08003013 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3014
3015 /* cause */
3016 if (retrieve_rej->fields & MNCC_F_CAUSE)
3017 encode_cause(msg, 1, &retrieve_rej->cause);
3018 else
3019 encode_cause(msg, 1, &default_cause);
3020
Harald Welte39e2ead2009-07-23 21:13:03 +02003021 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003022}
3023
3024static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3025{
3026 struct gsm48_hdr *gh = msgb_l3(msg);
3027 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3028 struct tlv_parsed tp;
3029 struct gsm_mncc dtmf;
3030
3031 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3032 dtmf.callref = trans->callref;
3033 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3034 /* keypad facility */
3035 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3036 dtmf.fields |= MNCC_F_KEYPAD;
3037 decode_keypad(&dtmf.keypad,
3038 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3039 }
3040
Harald Welte596fed42009-07-23 19:06:52 +02003041 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003042}
3043
3044static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3045{
3046 struct gsm_mncc *dtmf = arg;
3047 struct msgb *msg = gsm48_msgb_alloc();
3048 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3049
Harald Welte4bfdfe72009-06-10 23:11:52 +08003050 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3051
3052 /* keypad */
3053 if (dtmf->fields & MNCC_F_KEYPAD)
3054 encode_keypad(msg, dtmf->keypad);
3055
Harald Welte39e2ead2009-07-23 21:13:03 +02003056 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003057}
3058
3059static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3060{
3061 struct gsm_mncc *dtmf = arg;
3062 struct msgb *msg = gsm48_msgb_alloc();
3063 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3064
Harald Welte4bfdfe72009-06-10 23:11:52 +08003065 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3066
3067 /* cause */
3068 if (dtmf->fields & MNCC_F_CAUSE)
3069 encode_cause(msg, 1, &dtmf->cause);
3070 else
3071 encode_cause(msg, 1, &default_cause);
3072
Harald Welte39e2ead2009-07-23 21:13:03 +02003073 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003074}
3075
3076static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3077{
3078 struct msgb *msg = gsm48_msgb_alloc();
3079 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3080
Harald Welte4bfdfe72009-06-10 23:11:52 +08003081 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3082
Harald Welte39e2ead2009-07-23 21:13:03 +02003083 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003084}
3085
3086static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3087{
3088 struct gsm_mncc dtmf;
3089
3090 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3091 dtmf.callref = trans->callref;
3092
Harald Welte596fed42009-07-23 19:06:52 +02003093 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003094}
3095
3096static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3097{
3098 struct gsm48_hdr *gh = msgb_l3(msg);
3099 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3100 struct tlv_parsed tp;
3101 struct gsm_mncc modify;
3102
3103 memset(&modify, 0, sizeof(struct gsm_mncc));
3104 modify.callref = trans->callref;
3105 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3106 /* bearer capability */
3107 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3108 modify.fields |= MNCC_F_BEARER_CAP;
3109 decode_bearer_cap(&modify.bearer_cap,
3110 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3111 }
3112
3113 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3114
Harald Welte596fed42009-07-23 19:06:52 +02003115 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003116}
3117
3118static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3119{
3120 struct gsm_mncc *modify = arg;
3121 struct msgb *msg = gsm48_msgb_alloc();
3122 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3123
Harald Welte4bfdfe72009-06-10 23:11:52 +08003124 gh->msg_type = GSM48_MT_CC_MODIFY;
3125
3126 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3127
3128 /* bearer capability */
3129 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3130
3131 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3132
Harald Welte39e2ead2009-07-23 21:13:03 +02003133 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003134}
3135
3136static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3137{
3138 struct gsm48_hdr *gh = msgb_l3(msg);
3139 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3140 struct tlv_parsed tp;
3141 struct gsm_mncc modify;
3142
3143 gsm48_stop_cc_timer(trans);
3144
3145 memset(&modify, 0, sizeof(struct gsm_mncc));
3146 modify.callref = trans->callref;
3147 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3148 /* bearer capability */
3149 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3150 modify.fields |= MNCC_F_BEARER_CAP;
3151 decode_bearer_cap(&modify.bearer_cap,
3152 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3153 }
3154
3155 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3156
Harald Welte596fed42009-07-23 19:06:52 +02003157 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003158}
3159
3160static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3161{
3162 struct gsm_mncc *modify = arg;
3163 struct msgb *msg = gsm48_msgb_alloc();
3164 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3165
Harald Welte4bfdfe72009-06-10 23:11:52 +08003166 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3167
3168 /* bearer capability */
3169 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3170
3171 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3172
Harald Welte39e2ead2009-07-23 21:13:03 +02003173 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003174}
3175
3176static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3177{
3178 struct gsm48_hdr *gh = msgb_l3(msg);
3179 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3180 struct tlv_parsed tp;
3181 struct gsm_mncc modify;
3182
3183 gsm48_stop_cc_timer(trans);
3184
3185 memset(&modify, 0, sizeof(struct gsm_mncc));
3186 modify.callref = trans->callref;
3187 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3188 /* bearer capability */
3189 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3190 modify.fields |= GSM48_IE_BEARER_CAP;
3191 decode_bearer_cap(&modify.bearer_cap,
3192 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3193 }
3194 /* cause */
3195 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3196 modify.fields |= MNCC_F_CAUSE;
3197 decode_cause(&modify.cause,
3198 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3199 }
3200
3201 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3202
Harald Welte596fed42009-07-23 19:06:52 +02003203 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003204}
3205
3206static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3207{
3208 struct gsm_mncc *modify = arg;
3209 struct msgb *msg = gsm48_msgb_alloc();
3210 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3211
Harald Welte4bfdfe72009-06-10 23:11:52 +08003212 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3213
3214 /* bearer capability */
3215 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3216 /* cause */
3217 encode_cause(msg, 1, &modify->cause);
3218
3219 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3220
Harald Welte39e2ead2009-07-23 21:13:03 +02003221 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003222}
3223
3224static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3225{
3226 struct gsm_mncc *notify = arg;
3227 struct msgb *msg = gsm48_msgb_alloc();
3228 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3229
Harald Welte4bfdfe72009-06-10 23:11:52 +08003230 gh->msg_type = GSM48_MT_CC_NOTIFY;
3231
3232 /* notify */
3233 encode_notify(msg, notify->notify);
3234
Harald Welte39e2ead2009-07-23 21:13:03 +02003235 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003236}
3237
3238static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3239{
3240 struct gsm48_hdr *gh = msgb_l3(msg);
3241 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3242// struct tlv_parsed tp;
3243 struct gsm_mncc notify;
3244
3245 memset(&notify, 0, sizeof(struct gsm_mncc));
3246 notify.callref = trans->callref;
3247// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3248 if (payload_len >= 1)
3249 decode_notify(&notify.notify, gh->data);
3250
Harald Welte596fed42009-07-23 19:06:52 +02003251 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003252}
3253
3254static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3255{
3256 struct gsm_mncc *user = arg;
3257 struct msgb *msg = gsm48_msgb_alloc();
3258 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3259
Harald Welte4bfdfe72009-06-10 23:11:52 +08003260 gh->msg_type = GSM48_MT_CC_USER_INFO;
3261
3262 /* user-user */
3263 if (user->fields & MNCC_F_USERUSER)
3264 encode_useruser(msg, 1, &user->useruser);
3265 /* more data */
3266 if (user->more)
3267 encode_more(msg);
3268
Harald Welte39e2ead2009-07-23 21:13:03 +02003269 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003270}
3271
3272static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3273{
3274 struct gsm48_hdr *gh = msgb_l3(msg);
3275 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3276 struct tlv_parsed tp;
3277 struct gsm_mncc user;
3278
3279 memset(&user, 0, sizeof(struct gsm_mncc));
3280 user.callref = trans->callref;
3281 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3282 /* user-user */
3283 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3284 user.fields |= MNCC_F_USERUSER;
3285 decode_useruser(&user.useruser,
3286 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3287 }
3288 /* more data */
3289 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3290 user.more = 1;
3291
Harald Welte596fed42009-07-23 19:06:52 +02003292 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003293}
3294
3295static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3296{
3297 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003298 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003299
Harald Welte13cac662009-07-29 12:10:35 +02003300 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3301 if (rc < 0)
3302 return rc;
3303
3304 /* FIXME: we not only need to do this after mode modify, but
3305 * also after channel activation */
3306 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3307 mode->lchan_mode != GSM48_CMODE_SIGN)
3308 rc = rsl_ipacc_bind(trans->lchan);
3309
3310 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003311}
3312
3313static struct downstate {
3314 u_int32_t states;
3315 int type;
3316 int (*rout) (struct gsm_trans *trans, void *arg);
3317} downstatelist[] = {
3318 /* mobile originating call establishment */
3319 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3320 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3321 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3322 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3323 {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 */
3324 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3325 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3326 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3327 /* mobile terminating call establishment */
3328 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3329 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3330 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3331 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3332 /* signalling during call */
3333 {SBIT(GSM_CSTATE_ACTIVE),
3334 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3335 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3336 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3337 {ALL_STATES,
3338 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3339 {ALL_STATES,
3340 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3341 {ALL_STATES,
3342 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3343 {SBIT(GSM_CSTATE_ACTIVE),
3344 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3345 {SBIT(GSM_CSTATE_ACTIVE),
3346 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3347 {SBIT(GSM_CSTATE_ACTIVE),
3348 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3349 {SBIT(GSM_CSTATE_ACTIVE),
3350 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3351 {SBIT(GSM_CSTATE_ACTIVE),
3352 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3353 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3354 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3355 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3356 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3357 {SBIT(GSM_CSTATE_ACTIVE),
3358 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3359 /* clearing */
3360 {SBIT(GSM_CSTATE_INITIATED),
3361 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3362 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3363 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3364 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3365 MNCC_REL_REQ, gsm48_cc_tx_release},
3366 /* special */
3367 {ALL_STATES,
3368 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3369};
3370
3371#define DOWNSLLEN \
3372 (sizeof(downstatelist) / sizeof(struct downstate))
3373
3374
3375int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3376{
3377 int i, j, k, l, rc = 0;
3378 struct gsm_trans *trans = NULL, *transt;
3379 struct gsm_subscriber *subscr;
3380 struct gsm_lchan *lchan = NULL, *lchant;
3381 struct gsm_bts *bts = NULL;
3382 struct gsm_bts_trx *trx;
3383 struct gsm_bts_trx_ts *ts;
3384 struct gsm_mncc *data = arg, rel;
3385
3386 /* handle special messages */
3387 switch(msg_type) {
3388 case MNCC_BRIDGE:
3389 return tch_bridge(net, arg);
3390 case MNCC_FRAME_DROP:
3391 return tch_recv(net, arg, 0);
3392 case MNCC_FRAME_RECV:
3393 return tch_recv(net, arg, 1);
3394 case GSM_TRAU_FRAME:
3395 return tch_frame(net, arg);
3396 }
3397
3398 memset(&rel, 0, sizeof(struct gsm_mncc));
3399 rel.callref = data->callref;
3400
3401 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003402 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003403
3404 /* Callref unknown */
3405 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003406 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003407 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3408 "Received '%s' from MNCC with "
3409 "unknown callref %d\n", data->called.number,
3410 get_mncc_name(msg_type), data->callref);
3411 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003412 return mncc_release_ind(net, NULL, data->callref,
3413 GSM48_CAUSE_LOC_PRN_S_LU,
3414 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003415 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003416 if (!data->called.number[0] && !data->imsi[0]) {
3417 DEBUGP(DCC, "(bts - trx - ts - ti) "
3418 "Received '%s' from MNCC with "
3419 "no number or IMSI\n", get_mncc_name(msg_type));
3420 /* Invalid number */
3421 return mncc_release_ind(net, NULL, data->callref,
3422 GSM48_CAUSE_LOC_PRN_S_LU,
3423 GSM48_CC_CAUSE_INV_NR_FORMAT);
3424 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003425 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003426 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003427 subscr = subscr_get_by_extension(net,
3428 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003429 else
Harald Welte9176bd42009-07-23 18:46:00 +02003430 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003431 /* If subscriber is not found */
3432 if (!subscr) {
3433 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3434 "Received '%s' from MNCC with "
3435 "unknown subscriber %s\n", data->called.number,
3436 get_mncc_name(msg_type), data->called.number);
3437 /* Unknown subscriber */
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_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003441 }
3442 /* If subscriber is not "attached" */
3443 if (!subscr->lac) {
3444 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3445 "Received '%s' from MNCC with "
3446 "detached subscriber %s\n", data->called.number,
3447 get_mncc_name(msg_type), data->called.number);
3448 subscr_put(subscr);
3449 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003450 return mncc_release_ind(net, NULL, data->callref,
3451 GSM48_CAUSE_LOC_PRN_S_LU,
3452 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003453 }
3454 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003455 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3456 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003457 DEBUGP(DCC, "No memory for trans.\n");
3458 subscr_put(subscr);
3459 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003460 mncc_release_ind(net, NULL, data->callref,
3461 GSM48_CAUSE_LOC_PRN_S_LU,
3462 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003463 return -ENOMEM;
3464 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003465 /* Find lchan */
3466 for (i = 0; i < net->num_bts; i++) {
Harald Weltee441d9c2009-06-21 16:17:15 +02003467 bts = gsm_bts_num(net, i);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003468 for (j = 0; j < bts->num_trx; j++) {
Harald Weltee441d9c2009-06-21 16:17:15 +02003469 trx = gsm_bts_trx_num(bts, j);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003470 for (k = 0; k < TRX_NR_TS; k++) {
3471 ts = &trx->ts[k];
3472 for (l = 0; l < TS_MAX_LCHAN; l++) {
3473 lchant = &ts->lchan[l];
3474 if (lchant->subscr == subscr) {
3475 lchan = lchant;
3476 break;
3477 }
3478 }
3479 }
3480 }
3481 }
3482
3483 /* If subscriber has no lchan */
3484 if (!lchan) {
3485 /* find transaction with this subscriber already paging */
3486 llist_for_each_entry(transt, &net->trans_list, entry) {
3487 /* Transaction of our lchan? */
3488 if (transt == trans ||
3489 transt->subscr != subscr)
3490 continue;
3491 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3492 "Received '%s' from MNCC with "
3493 "unallocated channel, paging already "
3494 "started.\n", bts->nr,
3495 data->called.number,
3496 get_mncc_name(msg_type));
3497 return 0;
3498 }
3499 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003500 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003501 /* Trigger paging */
3502 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3503 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003504 return 0;
3505 }
3506 /* Assign lchan */
3507 trans->lchan = lchan;
3508 use_lchan(lchan);
3509 }
3510 lchan = trans->lchan;
3511
3512 /* if paging did not respond yet */
3513 if (!lchan) {
3514 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3515 "Received '%s' from MNCC in paging state\n",
3516 (trans->subscr)?(trans->subscr->extension):"-",
3517 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003518 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3519 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003520 if (msg_type == MNCC_REL_REQ)
3521 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3522 else
3523 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3524 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003525 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003526 return rc;
3527 }
3528
3529 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3530 "Received '%s' from MNCC in state %d (%s)\n",
3531 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3532 trans->transaction_id,
3533 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003534 get_mncc_name(msg_type), trans->cc.state,
3535 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003536
3537 /* Find function for current state and message */
3538 for (i = 0; i < DOWNSLLEN; i++)
3539 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003540 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003541 break;
3542 if (i == DOWNSLLEN) {
3543 DEBUGP(DCC, "Message unhandled at this state.\n");
3544 return 0;
3545 }
3546
3547 rc = downstatelist[i].rout(trans, arg);
3548
3549 return rc;
3550}
3551
3552
3553static struct datastate {
3554 u_int32_t states;
3555 int type;
3556 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3557} datastatelist[] = {
3558 /* mobile originating call establishment */
3559 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3560 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3561 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3562 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3563 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3564 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3565 /* mobile terminating call establishment */
3566 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3567 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3568 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3569 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3570 {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 */
3571 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3572 /* signalling during call */
3573 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3574 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3575 {SBIT(GSM_CSTATE_ACTIVE),
3576 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3577 {ALL_STATES,
3578 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3579 {ALL_STATES,
3580 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3581 {ALL_STATES,
3582 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3583 {SBIT(GSM_CSTATE_ACTIVE),
3584 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3585 {SBIT(GSM_CSTATE_ACTIVE),
3586 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3587 {SBIT(GSM_CSTATE_ACTIVE),
3588 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3589 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3590 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3591 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3592 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3593 {SBIT(GSM_CSTATE_ACTIVE),
3594 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3595 /* clearing */
3596 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3597 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3598 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3599 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3600 {ALL_STATES, /* 5.4.3.4 */
3601 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3602};
3603
3604#define DATASLLEN \
3605 (sizeof(datastatelist) / sizeof(struct datastate))
3606
Harald Welte4bc90a12008-12-27 16:32:52 +00003607static int gsm0408_rcv_cc(struct msgb *msg)
3608{
3609 struct gsm48_hdr *gh = msgb_l3(msg);
3610 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003611 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003612 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003613 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003614 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003615
Harald Welte4bfdfe72009-06-10 23:11:52 +08003616 if (msg_type & 0x80) {
3617 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3618 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003619 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003620
3621 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003622 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003623
Harald Welte6f5aee02009-07-23 21:21:14 +02003624 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003625 "Received '%s' from MS in state %d (%s)\n",
3626 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3627 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003628 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3629 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003630
3631 /* Create transaction */
3632 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003633 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003634 "creating new trans.\n", transaction_id);
3635 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003636 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3637 transaction_id, new_callref++);
3638 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003639 DEBUGP(DCC, "No memory for trans.\n");
3640 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003641 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003642 GSM48_MT_CC_RELEASE_COMPL);
3643 return -ENOMEM;
3644 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003645 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003646 trans->lchan = lchan;
3647 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003648 }
3649
3650 /* find function for current state and message */
3651 for (i = 0; i < DATASLLEN; i++)
3652 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003653 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003654 break;
3655 if (i == DATASLLEN) {
3656 DEBUGP(DCC, "Message unhandled at this state.\n");
3657 return 0;
3658 }
3659
3660 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003661
3662 return rc;
3663}
3664
Harald Welte52b1f982008-12-23 20:25:15 +00003665/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3666int gsm0408_rcvmsg(struct msgb *msg)
3667{
3668 struct gsm48_hdr *gh = msgb_l3(msg);
3669 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003670 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003671
3672 switch (pdisc) {
3673 case GSM48_PDISC_CC:
3674 rc = gsm0408_rcv_cc(msg);
3675 break;
3676 case GSM48_PDISC_MM:
3677 rc = gsm0408_rcv_mm(msg);
3678 break;
3679 case GSM48_PDISC_RR:
3680 rc = gsm0408_rcv_rr(msg);
3681 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003682 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003683 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003684 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003685 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003686 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003687 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3688 pdisc);
3689 break;
3690 default:
3691 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3692 pdisc);
3693 break;
3694 }
3695
3696 return rc;
3697}
Harald Welte8470bf22008-12-25 23:28:35 +00003698
Harald Welte8470bf22008-12-25 23:28:35 +00003699/* Section 9.1.8 / Table 9.9 */
3700struct chreq {
3701 u_int8_t val;
3702 u_int8_t mask;
3703 enum chreq_type type;
3704};
3705
3706/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3707static const struct chreq chreq_type_neci1[] = {
3708 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3709 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3710 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3711 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3712 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3713 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3714 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3715 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3716 { 0x10, 0xf0, CHREQ_T_SDCCH },
3717 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3718 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3719 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3720};
3721
3722/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3723static const struct chreq chreq_type_neci0[] = {
3724 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3725 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3726 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3727 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3728 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3729 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3730 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3731 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3732};
3733
3734static const enum gsm_chan_t ctype_by_chreq[] = {
3735 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3736 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3737 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3738 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3739 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3740 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3741 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3742 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3743 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3744 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3745 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3746 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3747};
3748
Harald Weltee14a57c2008-12-29 04:08:28 +00003749static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3750 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3751 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3752 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3753 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3754 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3755 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3756 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3757 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3758 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3759 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3760 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3761 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3762};
3763
Harald Welte8470bf22008-12-25 23:28:35 +00003764enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3765{
3766 int i;
3767 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3768
3769 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3770 const struct chreq *chr = &chreq_type_neci0[i];
3771 if ((ra & chr->mask) == chr->val)
3772 return ctype_by_chreq[chr->type];
3773 }
3774 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3775 return GSM_LCHAN_SDCCH;
3776}
Harald Weltee14a57c2008-12-29 04:08:28 +00003777
3778enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3779{
3780 int i;
3781 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3782
3783 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3784 const struct chreq *chr = &chreq_type_neci0[i];
3785 if ((ra & chr->mask) == chr->val)
3786 return reason_by_chreq[chr->type];
3787 }
3788 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3789 return GSM_CHREQ_REASON_OTHER;
3790}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003791
3792/* dequeue messages to layer 4 */
3793int bsc_upqueue(struct gsm_network *net)
3794{
3795 struct gsm_mncc *mncc;
3796 struct msgb *msg;
3797 int work = 0;
3798
3799 if (net)
3800 while ((msg = msgb_dequeue(&net->upqueue))) {
3801 mncc = (struct gsm_mncc *)msg->data;
3802 if (net->mncc_recv)
3803 net->mncc_recv(net, mncc->msg_type, mncc);
3804 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003805 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003806 }
3807
3808 return work;
3809}
Harald Weltedcaf5652009-07-23 18:56:43 +02003810
Harald Welte805f6442009-07-28 18:25:29 +02003811/*
3812 * This will be ran by the linker when loading the DSO. We use it to
3813 * do system initialization, e.g. registration of signal handlers.
3814 */
3815static __attribute__((constructor)) void on_dso_load_0408(void)
3816{
3817 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3818 "loc_updating_oper");
3819 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3820 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3821}