blob: 3e307b15f134e4c78c2e5ffdfd79c169bf286fb5 [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",
Harald Welte76042182009-08-08 16:03:15 +02001613 subscr->name && strlen(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 Welte76042182009-08-08 16:03:15 +02001786 /* FIXME: Start Timer T3109 */
Harald Welteae0f2362009-07-19 18:36:49 +02001787
1788 /* Deactivate the SACCH on the BTS side */
1789 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001790}
1791
Harald Welte4bc90a12008-12-27 16:32:52 +00001792/* Call Control */
1793
Harald Welte7584aea2009-02-11 11:44:12 +00001794/* The entire call control code is written in accordance with Figure 7.10c
1795 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1796 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1797 * it for voice */
1798
Harald Welte4bfdfe72009-06-10 23:11:52 +08001799static void new_cc_state(struct gsm_trans *trans, int state)
1800{
1801 if (state > 31 || state < 0)
1802 return;
1803
1804 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001805 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001806
Harald Weltedcaf5652009-07-23 18:56:43 +02001807 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001808}
1809
1810static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001811{
1812 struct msgb *msg = gsm48_msgb_alloc();
1813 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1814 u_int8_t *cause, *call_state;
1815
Harald Welte4bc90a12008-12-27 16:32:52 +00001816 gh->msg_type = GSM48_MT_CC_STATUS;
1817
1818 cause = msgb_put(msg, 3);
1819 cause[0] = 2;
1820 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1821 cause[2] = 0x80 | 30; /* response to status inquiry */
1822
1823 call_state = msgb_put(msg, 1);
1824 call_state[0] = 0xc0 | 0x00;
1825
Harald Welte39e2ead2009-07-23 21:13:03 +02001826 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001827}
1828
Harald Welte6f4b7532008-12-29 00:39:37 +00001829static int gsm48_tx_simple(struct gsm_lchan *lchan,
1830 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001831{
1832 struct msgb *msg = gsm48_msgb_alloc();
1833 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1834
1835 msg->lchan = lchan;
1836
Harald Welte6f4b7532008-12-29 00:39:37 +00001837 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001838 gh->msg_type = msg_type;
1839
Harald Welte39e2ead2009-07-23 21:13:03 +02001840 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001841}
1842
Harald Welte4bfdfe72009-06-10 23:11:52 +08001843static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1844{
Harald Weltedcaf5652009-07-23 18:56:43 +02001845 if (bsc_timer_pending(&trans->cc.timer)) {
1846 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1847 bsc_del_timer(&trans->cc.timer);
1848 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001849 }
1850}
1851
1852static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1853 int msg_type, struct gsm_mncc *mncc)
1854{
1855 struct msgb *msg;
1856
1857 if (trans)
1858 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001859 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001860 "Sending '%s' to MNCC.\n",
1861 trans->lchan->ts->trx->bts->nr,
1862 trans->lchan->ts->trx->nr,
1863 trans->lchan->ts->nr, trans->transaction_id,
1864 (trans->subscr)?(trans->subscr->extension):"-",
1865 get_mncc_name(msg_type));
1866 else
1867 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1868 "Sending '%s' to MNCC.\n",
1869 (trans->subscr)?(trans->subscr->extension):"-",
1870 get_mncc_name(msg_type));
1871 else
1872 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1873 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1874
1875 mncc->msg_type = msg_type;
1876
Harald Welte966636f2009-06-26 19:39:35 +02001877 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001878 if (!msg)
1879 return -ENOMEM;
1880 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1881 msgb_enqueue(&net->upqueue, msg);
1882
1883 return 0;
1884}
1885
1886int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1887 u_int32_t callref, int location, int value)
1888{
1889 struct gsm_mncc rel;
1890
Harald Welte92f70c52009-06-12 01:54:08 +08001891 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001892 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001893 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001894 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1895}
1896
Harald Weltedcaf5652009-07-23 18:56:43 +02001897/* Call Control Specific transaction release.
1898 * gets called by trans_free, DO NOT CALL YOURSELF! */
1899void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001900{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001901 gsm48_stop_cc_timer(trans);
1902
1903 /* send release to L4, if callref still exists */
1904 if (trans->callref) {
1905 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02001906 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001907 GSM48_CAUSE_LOC_PRN_S_LU,
1908 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001909 }
Harald Weltedcaf5652009-07-23 18:56:43 +02001910 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001911 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02001912 if (trans->lchan)
1913 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001914}
1915
1916static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1917
Harald Welte09e38af2009-02-16 22:52:23 +00001918/* call-back from paging the B-end of the connection */
1919static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001920 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001921{
Harald Welte7ccf7782009-02-17 01:43:01 +00001922 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001923 struct gsm_subscriber *subscr = param;
1924 struct gsm_trans *transt, *tmp;
1925 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001926
Harald Welte09e38af2009-02-16 22:52:23 +00001927 if (hooknum != GSM_HOOK_RR_PAGING)
1928 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001929
1930 if (!subscr)
1931 return -EINVAL;
1932 net = subscr->net;
1933 if (!net) {
1934 DEBUGP(DCC, "Error Network not set!\n");
1935 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00001936 }
Harald Welte7584aea2009-02-11 11:44:12 +00001937
Harald Welte4bfdfe72009-06-10 23:11:52 +08001938 /* check all tranactions (without lchan) for subscriber */
1939 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1940 if (transt->subscr != subscr || transt->lchan)
1941 continue;
1942 switch (event) {
1943 case GSM_PAGING_SUCCEEDED:
1944 if (!lchan) // paranoid
1945 break;
1946 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1947 subscr->extension);
1948 /* Assign lchan */
1949 if (!transt->lchan) {
1950 transt->lchan = lchan;
1951 use_lchan(lchan);
1952 }
1953 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02001954 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001955 break;
1956 case GSM_PAGING_EXPIRED:
1957 DEBUGP(DCC, "Paging subscr %s expired!\n",
1958 subscr->extension);
1959 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02001960 mncc_release_ind(transt->subscr->net, transt,
1961 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001962 GSM48_CAUSE_LOC_PRN_S_LU,
1963 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001964 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02001965 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001966 break;
1967 }
1968 }
Harald Welte09e38af2009-02-16 22:52:23 +00001969 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00001970}
Harald Welte7584aea2009-02-11 11:44:12 +00001971
Harald Welte805f6442009-07-28 18:25:29 +02001972/* some other part of the code sends us a signal */
1973static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
1974 void *handler_data, void *signal_data)
1975{
1976 struct gsm_lchan *lchan = signal_data;
1977 struct gsm_bts_trx_ts *ts;
1978 int rc;
1979
1980 if (subsys != SS_ABISIP)
1981 return 0;
1982
1983 /* in case we use direct BTS-to-BTS RTP */
1984 if (ipacc_rtp_direct)
1985 return 0;
1986
1987 ts = lchan->ts;
1988
1989 switch (signal) {
1990 case S_ABISIP_BIND_ACK:
1991 /* the BTS has successfully bound a TCH to a local ip/port,
1992 * which means we can connect our UDP socket to it */
1993 if (ts->abis_ip.rtp_socket) {
1994 rtp_socket_free(ts->abis_ip.rtp_socket);
1995 ts->abis_ip.rtp_socket = NULL;
1996 }
1997
1998 ts->abis_ip.rtp_socket = rtp_socket_create();
1999 if (!ts->abis_ip.rtp_socket)
2000 goto out_err;
2001
2002 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2003 ts->abis_ip.bound_ip,
2004 ts->abis_ip.bound_port);
2005 if (rc < 0)
2006 goto out_err;
2007 break;
2008 case S_ABISIP_DISC_IND:
2009 /* the BTS tells us a RTP stream has been disconnected */
2010 if (ts->abis_ip.rtp_socket) {
2011 rtp_socket_free(ts->abis_ip.rtp_socket);
2012 ts->abis_ip.rtp_socket = NULL;
2013 }
2014 break;
2015 }
2016
2017 return 0;
2018out_err:
2019 /* FIXME: do something */
2020 return 0;
2021}
2022
2023/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2024static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2025{
2026 struct gsm_bts_trx_ts *ts = lchan->ts;
2027 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2028 int rc;
2029
2030 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2031 ntohs(rs->rtp.sin_local.sin_port),
2032 ts->abis_ip.conn_id,
2033 /* FIXME: use RTP payload of bound socket, not BTS*/
2034 ts->abis_ip.rtp_payload2);
2035
2036 return rc;
2037}
2038
Harald Welte49f48b82009-02-17 15:29:33 +00002039/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002040static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002041{
Harald Welte11fa29c2009-02-19 17:24:39 +00002042 struct gsm_bts *bts = lchan->ts->trx->bts;
2043 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002044 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002045 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002046
Harald Welte11fa29c2009-02-19 17:24:39 +00002047 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2048 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2049 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2050
2051 if (bts->type != remote_bts->type) {
2052 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2053 return -EINVAL;
2054 }
Harald Welte49f48b82009-02-17 15:29:33 +00002055
Harald Welte11fa29c2009-02-19 17:24:39 +00002056 switch (bts->type) {
2057 case GSM_BTS_TYPE_NANOBTS_900:
2058 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002059 if (!ipacc_rtp_direct) {
2060 /* connect the TCH's to our RTP proxy */
2061 rc = ipacc_connect_proxy_bind(lchan);
2062 if (rc < 0)
2063 return rc;
2064 rc = ipacc_connect_proxy_bind(remote_lchan);
2065
2066 /* connect them with each other */
2067 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2068 remote_lchan->ts->abis_ip.rtp_socket);
2069 } else {
2070 /* directly connect TCH RTP streams to each other */
2071 ts = remote_lchan->ts;
2072 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2073 ts->abis_ip.bound_port,
2074 lchan->ts->abis_ip.conn_id,
2075 ts->abis_ip.rtp_payload2);
2076 if (rc < 0)
2077 return rc;
2078 ts = lchan->ts;
2079 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2080 ts->abis_ip.bound_port,
2081 remote_lchan->ts->abis_ip.conn_id,
2082 ts->abis_ip.rtp_payload2);
2083 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002084 break;
2085 case GSM_BTS_TYPE_BS11:
2086 trau_mux_map_lchan(lchan, remote_lchan);
2087 break;
2088 default:
2089 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002090 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002091 break;
2092 }
Harald Welte49f48b82009-02-17 15:29:33 +00002093
2094 return 0;
2095}
2096
Harald Welte4bfdfe72009-06-10 23:11:52 +08002097/* bridge channels of two transactions */
2098static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002099{
Harald Weltedcaf5652009-07-23 18:56:43 +02002100 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2101 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002102
Harald Welte4bfdfe72009-06-10 23:11:52 +08002103 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002104 return -EIO;
2105
Harald Welte4bfdfe72009-06-10 23:11:52 +08002106 if (!trans1->lchan || !trans2->lchan)
2107 return -EIO;
2108
2109 /* through-connect channel */
2110 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002111}
2112
Harald Welte4bfdfe72009-06-10 23:11:52 +08002113/* enable receive of channels to upqueue */
2114static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2115{
2116 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002117
Harald Welte4bfdfe72009-06-10 23:11:52 +08002118 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002119 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002120 if (!trans)
2121 return -EIO;
2122 if (!trans->lchan)
2123 return 0;
2124
2125 // todo IPACCESS
2126 if (enable)
2127 return trau_recv_lchan(trans->lchan, data->callref);
2128 return trau_mux_unmap(NULL, data->callref);
2129}
2130
2131/* send a frame to channel */
2132static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2133{
2134 struct gsm_trans *trans;
2135
2136 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002137 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002138 if (!trans)
2139 return -EIO;
2140 if (!trans->lchan)
2141 return 0;
2142 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2143 trans->lchan->type != GSM_LCHAN_TCH_H)
2144 return 0;
2145
2146 // todo IPACCESS
2147 return trau_send_lchan(trans->lchan,
2148 (struct decoded_trau_frame *)frame->data);
2149}
2150
2151
2152static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2153{
2154 DEBUGP(DCC, "-> STATUS ENQ\n");
2155 return gsm48_cc_tx_status(trans, msg);
2156}
2157
2158static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2159static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2160
2161static void gsm48_cc_timeout(void *arg)
2162{
2163 struct gsm_trans *trans = arg;
2164 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002165 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2166 int mo_location = GSM48_CAUSE_LOC_USER;
2167 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2168 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002169 struct gsm_mncc mo_rel, l4_rel;
2170
2171 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2172 mo_rel.callref = trans->callref;
2173 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2174 l4_rel.callref = trans->callref;
2175
Harald Weltedcaf5652009-07-23 18:56:43 +02002176 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002177 case 0x303:
2178 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002179 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002180 break;
2181 case 0x310:
2182 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002183 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002184 break;
2185 case 0x313:
2186 disconnect = 1;
2187 /* unknown, did not find it in the specs */
2188 break;
2189 case 0x301:
2190 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002191 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002192 break;
2193 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002194 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002195 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002196 gsm48_cc_tx_release(trans, &trans->cc.msg);
2197 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002198 break; /* stay in release state */
2199 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002200 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002201 return;
2202// release = 1;
2203// l4_cause = 14;
2204// break;
2205 case 0x306:
2206 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002207 mo_cause = trans->cc.msg.cause.value;
2208 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002209 break;
2210 case 0x323:
2211 disconnect = 1;
2212 break;
2213 default:
2214 release = 1;
2215 }
2216
2217 if (release && trans->callref) {
2218 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002219 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002220 l4_location, l4_cause);
2221 trans->callref = 0;
2222 }
2223
2224 if (disconnect && trans->callref) {
2225 /* process disconnect towards layer 4 */
2226 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002227 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002228 }
2229
2230 /* process disconnect towards mobile station */
2231 if (disconnect || release) {
2232 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002233 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2234 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2235 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002236 mo_rel.cause.diag_len = 3;
2237
2238 if (disconnect)
2239 gsm48_cc_tx_disconnect(trans, &mo_rel);
2240 if (release)
2241 gsm48_cc_tx_release(trans, &mo_rel);
2242 }
2243
2244}
2245
2246static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2247 int sec, int micro)
2248{
2249 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002250 trans->cc.timer.cb = gsm48_cc_timeout;
2251 trans->cc.timer.data = trans;
2252 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2253 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002254}
2255
2256static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2257{
2258 struct gsm48_hdr *gh = msgb_l3(msg);
2259 u_int8_t msg_type = gh->msg_type & 0xbf;
2260 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2261 struct tlv_parsed tp;
2262 struct gsm_mncc setup;
2263
2264 memset(&setup, 0, sizeof(struct gsm_mncc));
2265 setup.callref = trans->callref;
2266 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2267 /* emergency setup is identified by msg_type */
2268 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2269 setup.emergency = 1;
2270
2271 /* use subscriber as calling party number */
2272 if (trans->subscr) {
2273 setup.fields |= MNCC_F_CALLING;
2274 strncpy(setup.calling.number, trans->subscr->extension,
2275 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002276 strncpy(setup.imsi, trans->subscr->imsi,
2277 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002278 }
2279 /* bearer capability */
2280 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2281 setup.fields |= MNCC_F_BEARER_CAP;
2282 decode_bearer_cap(&setup.bearer_cap,
2283 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2284 }
2285 /* facility */
2286 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2287 setup.fields |= MNCC_F_FACILITY;
2288 decode_facility(&setup.facility,
2289 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2290 }
2291 /* called party bcd number */
2292 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2293 setup.fields |= MNCC_F_CALLED;
2294 decode_called(&setup.called,
2295 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2296 }
2297 /* user-user */
2298 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2299 setup.fields |= MNCC_F_USERUSER;
2300 decode_useruser(&setup.useruser,
2301 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2302 }
2303 /* ss-version */
2304 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2305 setup.fields |= MNCC_F_SSVERSION;
2306 decode_ssversion(&setup.ssversion,
2307 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2308 }
2309 /* CLIR suppression */
2310 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2311 setup.clir.sup = 1;
2312 /* CLIR invocation */
2313 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2314 setup.clir.inv = 1;
2315 /* cc cap */
2316 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2317 setup.fields |= MNCC_F_CCCAP;
2318 decode_cccap(&setup.cccap,
2319 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2320 }
2321
Harald Welte4bfdfe72009-06-10 23:11:52 +08002322 new_cc_state(trans, GSM_CSTATE_INITIATED);
2323
2324 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002325 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002326
Harald Welte13cac662009-07-29 12:10:35 +02002327 /* MNCC code will modify the channel asynchronously, we should
2328 * ipaccess-bind only after the modification has been made to the
2329 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002330 return 0;
2331}
2332
2333static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002334{
2335 struct msgb *msg = gsm48_msgb_alloc();
2336 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002337 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002338 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002339
Harald Welte7ccf7782009-02-17 01:43:01 +00002340 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002341
Harald Welte4bfdfe72009-06-10 23:11:52 +08002342 /* transaction id must not be assigned */
2343 if (trans->transaction_id != 0xff) { /* unasssigned */
2344 DEBUGP(DCC, "TX Setup with assigned transaction. "
2345 "This is not allowed!\n");
2346 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002347 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002348 GSM48_CAUSE_LOC_PRN_S_LU,
2349 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002350 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002351 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002352 return rc;
2353 }
2354
2355 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002356 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2357 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002358 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002359 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002360 GSM48_CAUSE_LOC_PRN_S_LU,
2361 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002362 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002363 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002364 return rc;
2365 }
Harald Welte78283ef2009-07-23 21:36:44 +02002366 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002367
Harald Welte65e74cc2008-12-29 01:55:35 +00002368 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002369
Harald Welte4bfdfe72009-06-10 23:11:52 +08002370 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002371
Harald Welte4bfdfe72009-06-10 23:11:52 +08002372 /* bearer capability */
2373 if (setup->fields & MNCC_F_BEARER_CAP)
2374 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2375 /* facility */
2376 if (setup->fields & MNCC_F_FACILITY)
2377 encode_facility(msg, 0, &setup->facility);
2378 /* progress */
2379 if (setup->fields & MNCC_F_PROGRESS)
2380 encode_progress(msg, 0, &setup->progress);
2381 /* calling party BCD number */
2382 if (setup->fields & MNCC_F_CALLING)
2383 encode_calling(msg, &setup->calling);
2384 /* called party BCD number */
2385 if (setup->fields & MNCC_F_CALLED)
2386 encode_called(msg, &setup->called);
2387 /* user-user */
2388 if (setup->fields & MNCC_F_USERUSER)
2389 encode_useruser(msg, 0, &setup->useruser);
2390 /* redirecting party BCD number */
2391 if (setup->fields & MNCC_F_REDIRECTING)
2392 encode_redirecting(msg, &setup->redirecting);
2393 /* signal */
2394 if (setup->fields & MNCC_F_SIGNAL)
2395 encode_signal(msg, setup->signal);
2396
2397 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002398
Harald Welte39e2ead2009-07-23 21:13:03 +02002399 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002400}
2401
Harald Welte4bfdfe72009-06-10 23:11:52 +08002402static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2403{
2404 struct gsm48_hdr *gh = msgb_l3(msg);
2405 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2406 struct tlv_parsed tp;
2407 struct gsm_mncc call_conf;
2408
2409 gsm48_stop_cc_timer(trans);
2410 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2411
2412 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2413 call_conf.callref = trans->callref;
2414 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2415#if 0
2416 /* repeat */
2417 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2418 call_conf.repeat = 1;
2419 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2420 call_conf.repeat = 2;
2421#endif
2422 /* bearer capability */
2423 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2424 call_conf.fields |= MNCC_F_BEARER_CAP;
2425 decode_bearer_cap(&call_conf.bearer_cap,
2426 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2427 }
2428 /* cause */
2429 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2430 call_conf.fields |= MNCC_F_CAUSE;
2431 decode_cause(&call_conf.cause,
2432 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2433 }
2434 /* cc cap */
2435 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2436 call_conf.fields |= MNCC_F_CCCAP;
2437 decode_cccap(&call_conf.cccap,
2438 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2439 }
2440
2441 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2442
Harald Welte596fed42009-07-23 19:06:52 +02002443 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2444 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002445}
2446
2447static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2448{
2449 struct gsm_mncc *proceeding = arg;
2450 struct msgb *msg = gsm48_msgb_alloc();
2451 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2452
Harald Welte4bfdfe72009-06-10 23:11:52 +08002453 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2454
2455 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2456
2457 /* bearer capability */
2458 if (proceeding->fields & MNCC_F_BEARER_CAP)
2459 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2460 /* facility */
2461 if (proceeding->fields & MNCC_F_FACILITY)
2462 encode_facility(msg, 0, &proceeding->facility);
2463 /* progress */
2464 if (proceeding->fields & MNCC_F_PROGRESS)
2465 encode_progress(msg, 0, &proceeding->progress);
2466
Harald Welte39e2ead2009-07-23 21:13:03 +02002467 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002468}
2469
2470static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2471{
2472 struct gsm48_hdr *gh = msgb_l3(msg);
2473 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2474 struct tlv_parsed tp;
2475 struct gsm_mncc alerting;
2476
2477 gsm48_stop_cc_timer(trans);
2478 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2479
2480 memset(&alerting, 0, sizeof(struct gsm_mncc));
2481 alerting.callref = trans->callref;
2482 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2483 /* facility */
2484 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2485 alerting.fields |= MNCC_F_FACILITY;
2486 decode_facility(&alerting.facility,
2487 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2488 }
2489
2490 /* progress */
2491 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2492 alerting.fields |= MNCC_F_PROGRESS;
2493 decode_progress(&alerting.progress,
2494 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2495 }
2496 /* ss-version */
2497 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2498 alerting.fields |= MNCC_F_SSVERSION;
2499 decode_ssversion(&alerting.ssversion,
2500 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2501 }
2502
2503 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2504
Harald Welte596fed42009-07-23 19:06:52 +02002505 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2506 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002507}
2508
2509static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2510{
2511 struct gsm_mncc *alerting = arg;
2512 struct msgb *msg = gsm48_msgb_alloc();
2513 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2514
Harald Welte4bfdfe72009-06-10 23:11:52 +08002515 gh->msg_type = GSM48_MT_CC_ALERTING;
2516
2517 /* facility */
2518 if (alerting->fields & MNCC_F_FACILITY)
2519 encode_facility(msg, 0, &alerting->facility);
2520 /* progress */
2521 if (alerting->fields & MNCC_F_PROGRESS)
2522 encode_progress(msg, 0, &alerting->progress);
2523 /* user-user */
2524 if (alerting->fields & MNCC_F_USERUSER)
2525 encode_useruser(msg, 0, &alerting->useruser);
2526
2527 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2528
Harald Welte39e2ead2009-07-23 21:13:03 +02002529 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002530}
2531
2532static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2533{
2534 struct gsm_mncc *progress = arg;
2535 struct msgb *msg = gsm48_msgb_alloc();
2536 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2537
Harald Welte4bfdfe72009-06-10 23:11:52 +08002538 gh->msg_type = GSM48_MT_CC_PROGRESS;
2539
2540 /* progress */
2541 encode_progress(msg, 1, &progress->progress);
2542 /* user-user */
2543 if (progress->fields & MNCC_F_USERUSER)
2544 encode_useruser(msg, 0, &progress->useruser);
2545
Harald Welte39e2ead2009-07-23 21:13:03 +02002546 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002547}
2548
2549static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2550{
2551 struct gsm_mncc *connect = arg;
2552 struct msgb *msg = gsm48_msgb_alloc();
2553 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2554
Harald Welte4bfdfe72009-06-10 23:11:52 +08002555 gh->msg_type = GSM48_MT_CC_CONNECT;
2556
2557 gsm48_stop_cc_timer(trans);
2558 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2559
2560 /* facility */
2561 if (connect->fields & MNCC_F_FACILITY)
2562 encode_facility(msg, 0, &connect->facility);
2563 /* progress */
2564 if (connect->fields & MNCC_F_PROGRESS)
2565 encode_progress(msg, 0, &connect->progress);
2566 /* connected number */
2567 if (connect->fields & MNCC_F_CONNECTED)
2568 encode_connected(msg, &connect->connected);
2569 /* user-user */
2570 if (connect->fields & MNCC_F_USERUSER)
2571 encode_useruser(msg, 0, &connect->useruser);
2572
2573 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2574
Harald Welte39e2ead2009-07-23 21:13:03 +02002575 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002576}
2577
2578static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2579{
2580 struct gsm48_hdr *gh = msgb_l3(msg);
2581 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2582 struct tlv_parsed tp;
2583 struct gsm_mncc connect;
2584
2585 gsm48_stop_cc_timer(trans);
2586
2587 memset(&connect, 0, sizeof(struct gsm_mncc));
2588 connect.callref = trans->callref;
2589 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2590 /* use subscriber as connected party number */
2591 if (trans->subscr) {
2592 connect.fields |= MNCC_F_CONNECTED;
2593 strncpy(connect.connected.number, trans->subscr->extension,
2594 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002595 strncpy(connect.imsi, trans->subscr->imsi,
2596 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002597 }
2598 /* facility */
2599 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2600 connect.fields |= MNCC_F_FACILITY;
2601 decode_facility(&connect.facility,
2602 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2603 }
2604 /* user-user */
2605 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2606 connect.fields |= MNCC_F_USERUSER;
2607 decode_useruser(&connect.useruser,
2608 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2609 }
2610 /* ss-version */
2611 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2612 connect.fields |= MNCC_F_SSVERSION;
2613 decode_ssversion(&connect.ssversion,
2614 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2615 }
2616
2617 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2618
Harald Welte596fed42009-07-23 19:06:52 +02002619 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002620}
2621
2622
2623static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2624{
2625 struct gsm_mncc connect_ack;
2626
2627 gsm48_stop_cc_timer(trans);
2628
2629 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2630
2631 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2632 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002633 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002634 &connect_ack);
2635}
2636
2637static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2638{
2639 struct msgb *msg = gsm48_msgb_alloc();
2640 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2641
Harald Welte4bfdfe72009-06-10 23:11:52 +08002642 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2643
2644 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2645
Harald Welte39e2ead2009-07-23 21:13:03 +02002646 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002647}
2648
2649static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2650{
2651 struct gsm48_hdr *gh = msgb_l3(msg);
2652 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2653 struct tlv_parsed tp;
2654 struct gsm_mncc disc;
2655
2656 gsm48_stop_cc_timer(trans);
2657
2658 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2659
2660 memset(&disc, 0, sizeof(struct gsm_mncc));
2661 disc.callref = trans->callref;
2662 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2663 /* cause */
2664 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2665 disc.fields |= MNCC_F_CAUSE;
2666 decode_cause(&disc.cause,
2667 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2668 }
2669 /* facility */
2670 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2671 disc.fields |= MNCC_F_FACILITY;
2672 decode_facility(&disc.facility,
2673 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2674 }
2675 /* user-user */
2676 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2677 disc.fields |= MNCC_F_USERUSER;
2678 decode_useruser(&disc.useruser,
2679 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2680 }
2681 /* ss-version */
2682 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2683 disc.fields |= MNCC_F_SSVERSION;
2684 decode_ssversion(&disc.ssversion,
2685 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2686 }
2687
Harald Welte596fed42009-07-23 19:06:52 +02002688 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002689
2690}
2691
Harald Weltec66b71c2009-06-11 14:23:20 +08002692static struct gsm_mncc_cause default_cause = {
2693 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2694 .coding = 0,
2695 .rec = 0,
2696 .rec_val = 0,
2697 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2698 .diag_len = 0,
2699 .diag = { 0 },
2700};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002701
2702static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2703{
2704 struct gsm_mncc *disc = arg;
2705 struct msgb *msg = gsm48_msgb_alloc();
2706 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2707
Harald Welte4bfdfe72009-06-10 23:11:52 +08002708 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2709
2710 gsm48_stop_cc_timer(trans);
2711 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2712
2713 /* cause */
2714 if (disc->fields & MNCC_F_CAUSE)
2715 encode_cause(msg, 1, &disc->cause);
2716 else
2717 encode_cause(msg, 1, &default_cause);
2718
2719 /* facility */
2720 if (disc->fields & MNCC_F_FACILITY)
2721 encode_facility(msg, 0, &disc->facility);
2722 /* progress */
2723 if (disc->fields & MNCC_F_PROGRESS)
2724 encode_progress(msg, 0, &disc->progress);
2725 /* user-user */
2726 if (disc->fields & MNCC_F_USERUSER)
2727 encode_useruser(msg, 0, &disc->useruser);
2728
2729 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002730 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002731
2732 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2733
Harald Welte39e2ead2009-07-23 21:13:03 +02002734 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002735}
2736
2737static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2738{
2739 struct gsm48_hdr *gh = msgb_l3(msg);
2740 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2741 struct tlv_parsed tp;
2742 struct gsm_mncc rel;
2743 int rc;
2744
2745 gsm48_stop_cc_timer(trans);
2746
2747 memset(&rel, 0, sizeof(struct gsm_mncc));
2748 rel.callref = trans->callref;
2749 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2750 /* cause */
2751 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2752 rel.fields |= MNCC_F_CAUSE;
2753 decode_cause(&rel.cause,
2754 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2755 }
2756 /* facility */
2757 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2758 rel.fields |= MNCC_F_FACILITY;
2759 decode_facility(&rel.facility,
2760 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2761 }
2762 /* user-user */
2763 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2764 rel.fields |= MNCC_F_USERUSER;
2765 decode_useruser(&rel.useruser,
2766 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2767 }
2768 /* ss-version */
2769 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2770 rel.fields |= MNCC_F_SSVERSION;
2771 decode_ssversion(&rel.ssversion,
2772 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2773 }
2774
Harald Weltedcaf5652009-07-23 18:56:43 +02002775 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002776 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002777 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002778 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002779 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002780 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002781 GSM48_MT_CC_RELEASE_COMPL);
2782 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002783 }
2784
2785 new_cc_state(trans, GSM_CSTATE_NULL);
2786
2787 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002788 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002789
2790 return rc;
2791}
2792
2793static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2794{
2795 struct gsm_mncc *rel = arg;
2796 struct msgb *msg = gsm48_msgb_alloc();
2797 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2798
Harald Welte4bfdfe72009-06-10 23:11:52 +08002799 gh->msg_type = GSM48_MT_CC_RELEASE;
2800
2801 trans->callref = 0;
2802
2803 gsm48_stop_cc_timer(trans);
2804 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2805
2806 /* cause */
2807 if (rel->fields & MNCC_F_CAUSE)
2808 encode_cause(msg, 0, &rel->cause);
2809 /* facility */
2810 if (rel->fields & MNCC_F_FACILITY)
2811 encode_facility(msg, 0, &rel->facility);
2812 /* user-user */
2813 if (rel->fields & MNCC_F_USERUSER)
2814 encode_useruser(msg, 0, &rel->useruser);
2815
Harald Weltedcaf5652009-07-23 18:56:43 +02002816 trans->cc.T308_second = 0;
2817 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002818
Harald Weltedcaf5652009-07-23 18:56:43 +02002819 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002820 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2821
Harald Welte39e2ead2009-07-23 21:13:03 +02002822 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002823}
2824
2825static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2826{
2827 struct gsm48_hdr *gh = msgb_l3(msg);
2828 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2829 struct tlv_parsed tp;
2830 struct gsm_mncc rel;
2831 int rc = 0;
2832
2833 gsm48_stop_cc_timer(trans);
2834
2835 memset(&rel, 0, sizeof(struct gsm_mncc));
2836 rel.callref = trans->callref;
2837 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2838 /* cause */
2839 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2840 rel.fields |= MNCC_F_CAUSE;
2841 decode_cause(&rel.cause,
2842 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2843 }
2844 /* facility */
2845 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2846 rel.fields |= MNCC_F_FACILITY;
2847 decode_facility(&rel.facility,
2848 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2849 }
2850 /* user-user */
2851 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2852 rel.fields |= MNCC_F_USERUSER;
2853 decode_useruser(&rel.useruser,
2854 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2855 }
2856 /* ss-version */
2857 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2858 rel.fields |= MNCC_F_SSVERSION;
2859 decode_ssversion(&rel.ssversion,
2860 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2861 }
2862
2863 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002864 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002865 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002866 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002867 MNCC_REJ_IND, &rel);
2868 break;
2869 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002870 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002871 MNCC_REL_CNF, &rel);
2872 break;
2873 default:
Harald Welte596fed42009-07-23 19:06:52 +02002874 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002875 MNCC_REL_IND, &rel);
2876 }
2877 }
2878
2879 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002880 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002881
2882 return rc;
2883}
2884
2885static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2886{
2887 struct gsm_mncc *rel = arg;
2888 struct msgb *msg = gsm48_msgb_alloc();
2889 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2890
Harald Welte4bfdfe72009-06-10 23:11:52 +08002891 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2892
2893 trans->callref = 0;
2894
2895 gsm48_stop_cc_timer(trans);
2896
2897 /* cause */
2898 if (rel->fields & MNCC_F_CAUSE)
2899 encode_cause(msg, 0, &rel->cause);
2900 /* facility */
2901 if (rel->fields & MNCC_F_FACILITY)
2902 encode_facility(msg, 0, &rel->facility);
2903 /* user-user */
2904 if (rel->fields & MNCC_F_USERUSER)
2905 encode_useruser(msg, 0, &rel->useruser);
2906
Harald Weltedcaf5652009-07-23 18:56:43 +02002907 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002908
Harald Welte39e2ead2009-07-23 21:13:03 +02002909 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002910}
2911
2912static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2913{
2914 struct gsm48_hdr *gh = msgb_l3(msg);
2915 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2916 struct tlv_parsed tp;
2917 struct gsm_mncc fac;
2918
2919 memset(&fac, 0, sizeof(struct gsm_mncc));
2920 fac.callref = trans->callref;
2921 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2922 /* facility */
2923 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2924 fac.fields |= MNCC_F_FACILITY;
2925 decode_facility(&fac.facility,
2926 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2927 }
2928 /* ss-version */
2929 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2930 fac.fields |= MNCC_F_SSVERSION;
2931 decode_ssversion(&fac.ssversion,
2932 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2933 }
2934
Harald Welte596fed42009-07-23 19:06:52 +02002935 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002936}
2937
2938static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2939{
2940 struct gsm_mncc *fac = arg;
2941 struct msgb *msg = gsm48_msgb_alloc();
2942 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2943
Harald Welte4bfdfe72009-06-10 23:11:52 +08002944 gh->msg_type = GSM48_MT_CC_FACILITY;
2945
2946 /* facility */
2947 encode_facility(msg, 1, &fac->facility);
2948
Harald Welte39e2ead2009-07-23 21:13:03 +02002949 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002950}
2951
2952static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2953{
2954 struct gsm_mncc hold;
2955
2956 memset(&hold, 0, sizeof(struct gsm_mncc));
2957 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002958 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002959}
2960
2961static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2962{
2963 struct msgb *msg = gsm48_msgb_alloc();
2964 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2965
Harald Welte4bfdfe72009-06-10 23:11:52 +08002966 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
2967
Harald Welte39e2ead2009-07-23 21:13:03 +02002968 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002969}
2970
2971static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
2972{
2973 struct gsm_mncc *hold_rej = arg;
2974 struct msgb *msg = gsm48_msgb_alloc();
2975 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2976
Harald Welte4bfdfe72009-06-10 23:11:52 +08002977 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
2978
2979 /* cause */
2980 if (hold_rej->fields & MNCC_F_CAUSE)
2981 encode_cause(msg, 1, &hold_rej->cause);
2982 else
2983 encode_cause(msg, 1, &default_cause);
2984
Harald Welte39e2ead2009-07-23 21:13:03 +02002985 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002986}
2987
2988static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
2989{
2990 struct gsm_mncc retrieve;
2991
2992 memset(&retrieve, 0, sizeof(struct gsm_mncc));
2993 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002994 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
2995 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002996}
2997
2998static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
2999{
3000 struct msgb *msg = gsm48_msgb_alloc();
3001 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3002
Harald Welte4bfdfe72009-06-10 23:11:52 +08003003 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3004
Harald Welte39e2ead2009-07-23 21:13:03 +02003005 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003006}
3007
3008static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3009{
3010 struct gsm_mncc *retrieve_rej = arg;
3011 struct msgb *msg = gsm48_msgb_alloc();
3012 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3013
Harald Welte4bfdfe72009-06-10 23:11:52 +08003014 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3015
3016 /* cause */
3017 if (retrieve_rej->fields & MNCC_F_CAUSE)
3018 encode_cause(msg, 1, &retrieve_rej->cause);
3019 else
3020 encode_cause(msg, 1, &default_cause);
3021
Harald Welte39e2ead2009-07-23 21:13:03 +02003022 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003023}
3024
3025static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3026{
3027 struct gsm48_hdr *gh = msgb_l3(msg);
3028 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3029 struct tlv_parsed tp;
3030 struct gsm_mncc dtmf;
3031
3032 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3033 dtmf.callref = trans->callref;
3034 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3035 /* keypad facility */
3036 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3037 dtmf.fields |= MNCC_F_KEYPAD;
3038 decode_keypad(&dtmf.keypad,
3039 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3040 }
3041
Harald Welte596fed42009-07-23 19:06:52 +02003042 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003043}
3044
3045static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3046{
3047 struct gsm_mncc *dtmf = arg;
3048 struct msgb *msg = gsm48_msgb_alloc();
3049 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3050
Harald Welte4bfdfe72009-06-10 23:11:52 +08003051 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3052
3053 /* keypad */
3054 if (dtmf->fields & MNCC_F_KEYPAD)
3055 encode_keypad(msg, dtmf->keypad);
3056
Harald Welte39e2ead2009-07-23 21:13:03 +02003057 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003058}
3059
3060static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3061{
3062 struct gsm_mncc *dtmf = arg;
3063 struct msgb *msg = gsm48_msgb_alloc();
3064 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3065
Harald Welte4bfdfe72009-06-10 23:11:52 +08003066 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3067
3068 /* cause */
3069 if (dtmf->fields & MNCC_F_CAUSE)
3070 encode_cause(msg, 1, &dtmf->cause);
3071 else
3072 encode_cause(msg, 1, &default_cause);
3073
Harald Welte39e2ead2009-07-23 21:13:03 +02003074 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003075}
3076
3077static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3078{
3079 struct msgb *msg = gsm48_msgb_alloc();
3080 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3081
Harald Welte4bfdfe72009-06-10 23:11:52 +08003082 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3083
Harald Welte39e2ead2009-07-23 21:13:03 +02003084 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003085}
3086
3087static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3088{
3089 struct gsm_mncc dtmf;
3090
3091 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3092 dtmf.callref = trans->callref;
3093
Harald Welte596fed42009-07-23 19:06:52 +02003094 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003095}
3096
3097static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3098{
3099 struct gsm48_hdr *gh = msgb_l3(msg);
3100 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3101 struct tlv_parsed tp;
3102 struct gsm_mncc modify;
3103
3104 memset(&modify, 0, sizeof(struct gsm_mncc));
3105 modify.callref = trans->callref;
3106 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3107 /* bearer capability */
3108 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3109 modify.fields |= MNCC_F_BEARER_CAP;
3110 decode_bearer_cap(&modify.bearer_cap,
3111 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3112 }
3113
3114 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3115
Harald Welte596fed42009-07-23 19:06:52 +02003116 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003117}
3118
3119static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3120{
3121 struct gsm_mncc *modify = arg;
3122 struct msgb *msg = gsm48_msgb_alloc();
3123 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3124
Harald Welte4bfdfe72009-06-10 23:11:52 +08003125 gh->msg_type = GSM48_MT_CC_MODIFY;
3126
3127 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3128
3129 /* bearer capability */
3130 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3131
3132 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3133
Harald Welte39e2ead2009-07-23 21:13:03 +02003134 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003135}
3136
3137static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3138{
3139 struct gsm48_hdr *gh = msgb_l3(msg);
3140 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3141 struct tlv_parsed tp;
3142 struct gsm_mncc modify;
3143
3144 gsm48_stop_cc_timer(trans);
3145
3146 memset(&modify, 0, sizeof(struct gsm_mncc));
3147 modify.callref = trans->callref;
3148 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3149 /* bearer capability */
3150 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3151 modify.fields |= MNCC_F_BEARER_CAP;
3152 decode_bearer_cap(&modify.bearer_cap,
3153 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3154 }
3155
3156 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3157
Harald Welte596fed42009-07-23 19:06:52 +02003158 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003159}
3160
3161static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3162{
3163 struct gsm_mncc *modify = arg;
3164 struct msgb *msg = gsm48_msgb_alloc();
3165 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3166
Harald Welte4bfdfe72009-06-10 23:11:52 +08003167 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3168
3169 /* bearer capability */
3170 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3171
3172 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3173
Harald Welte39e2ead2009-07-23 21:13:03 +02003174 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003175}
3176
3177static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3178{
3179 struct gsm48_hdr *gh = msgb_l3(msg);
3180 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3181 struct tlv_parsed tp;
3182 struct gsm_mncc modify;
3183
3184 gsm48_stop_cc_timer(trans);
3185
3186 memset(&modify, 0, sizeof(struct gsm_mncc));
3187 modify.callref = trans->callref;
3188 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3189 /* bearer capability */
3190 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3191 modify.fields |= GSM48_IE_BEARER_CAP;
3192 decode_bearer_cap(&modify.bearer_cap,
3193 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3194 }
3195 /* cause */
3196 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3197 modify.fields |= MNCC_F_CAUSE;
3198 decode_cause(&modify.cause,
3199 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3200 }
3201
3202 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3203
Harald Welte596fed42009-07-23 19:06:52 +02003204 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003205}
3206
3207static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3208{
3209 struct gsm_mncc *modify = arg;
3210 struct msgb *msg = gsm48_msgb_alloc();
3211 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3212
Harald Welte4bfdfe72009-06-10 23:11:52 +08003213 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3214
3215 /* bearer capability */
3216 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3217 /* cause */
3218 encode_cause(msg, 1, &modify->cause);
3219
3220 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3221
Harald Welte39e2ead2009-07-23 21:13:03 +02003222 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003223}
3224
3225static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3226{
3227 struct gsm_mncc *notify = arg;
3228 struct msgb *msg = gsm48_msgb_alloc();
3229 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3230
Harald Welte4bfdfe72009-06-10 23:11:52 +08003231 gh->msg_type = GSM48_MT_CC_NOTIFY;
3232
3233 /* notify */
3234 encode_notify(msg, notify->notify);
3235
Harald Welte39e2ead2009-07-23 21:13:03 +02003236 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003237}
3238
3239static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3240{
3241 struct gsm48_hdr *gh = msgb_l3(msg);
3242 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3243// struct tlv_parsed tp;
3244 struct gsm_mncc notify;
3245
3246 memset(&notify, 0, sizeof(struct gsm_mncc));
3247 notify.callref = trans->callref;
3248// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3249 if (payload_len >= 1)
3250 decode_notify(&notify.notify, gh->data);
3251
Harald Welte596fed42009-07-23 19:06:52 +02003252 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003253}
3254
3255static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3256{
3257 struct gsm_mncc *user = arg;
3258 struct msgb *msg = gsm48_msgb_alloc();
3259 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3260
Harald Welte4bfdfe72009-06-10 23:11:52 +08003261 gh->msg_type = GSM48_MT_CC_USER_INFO;
3262
3263 /* user-user */
3264 if (user->fields & MNCC_F_USERUSER)
3265 encode_useruser(msg, 1, &user->useruser);
3266 /* more data */
3267 if (user->more)
3268 encode_more(msg);
3269
Harald Welte39e2ead2009-07-23 21:13:03 +02003270 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003271}
3272
3273static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3274{
3275 struct gsm48_hdr *gh = msgb_l3(msg);
3276 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3277 struct tlv_parsed tp;
3278 struct gsm_mncc user;
3279
3280 memset(&user, 0, sizeof(struct gsm_mncc));
3281 user.callref = trans->callref;
3282 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3283 /* user-user */
3284 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3285 user.fields |= MNCC_F_USERUSER;
3286 decode_useruser(&user.useruser,
3287 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3288 }
3289 /* more data */
3290 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3291 user.more = 1;
3292
Harald Welte596fed42009-07-23 19:06:52 +02003293 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003294}
3295
3296static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3297{
3298 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003299 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003300
Harald Welte13cac662009-07-29 12:10:35 +02003301 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3302 if (rc < 0)
3303 return rc;
3304
3305 /* FIXME: we not only need to do this after mode modify, but
3306 * also after channel activation */
3307 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3308 mode->lchan_mode != GSM48_CMODE_SIGN)
3309 rc = rsl_ipacc_bind(trans->lchan);
3310
3311 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003312}
3313
3314static struct downstate {
3315 u_int32_t states;
3316 int type;
3317 int (*rout) (struct gsm_trans *trans, void *arg);
3318} downstatelist[] = {
3319 /* mobile originating call establishment */
3320 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3321 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3322 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3323 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3324 {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 */
3325 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3326 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3327 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3328 /* mobile terminating call establishment */
3329 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3330 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3331 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3332 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3333 /* signalling during call */
3334 {SBIT(GSM_CSTATE_ACTIVE),
3335 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3336 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3337 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3338 {ALL_STATES,
3339 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3340 {ALL_STATES,
3341 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3342 {ALL_STATES,
3343 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3344 {SBIT(GSM_CSTATE_ACTIVE),
3345 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3346 {SBIT(GSM_CSTATE_ACTIVE),
3347 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3348 {SBIT(GSM_CSTATE_ACTIVE),
3349 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3350 {SBIT(GSM_CSTATE_ACTIVE),
3351 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3352 {SBIT(GSM_CSTATE_ACTIVE),
3353 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3354 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3355 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3356 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3357 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3358 {SBIT(GSM_CSTATE_ACTIVE),
3359 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3360 /* clearing */
3361 {SBIT(GSM_CSTATE_INITIATED),
3362 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3363 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3364 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3365 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3366 MNCC_REL_REQ, gsm48_cc_tx_release},
3367 /* special */
3368 {ALL_STATES,
3369 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3370};
3371
3372#define DOWNSLLEN \
3373 (sizeof(downstatelist) / sizeof(struct downstate))
3374
3375
3376int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3377{
Harald Welte1a6f7982009-08-09 18:52:33 +02003378 int i, rc = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003379 struct gsm_trans *trans = NULL, *transt;
3380 struct gsm_subscriber *subscr;
Harald Welte1a6f7982009-08-09 18:52:33 +02003381 struct gsm_lchan *lchan = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003382 struct gsm_bts *bts = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003383 struct gsm_mncc *data = arg, rel;
3384
3385 /* handle special messages */
3386 switch(msg_type) {
3387 case MNCC_BRIDGE:
3388 return tch_bridge(net, arg);
3389 case MNCC_FRAME_DROP:
3390 return tch_recv(net, arg, 0);
3391 case MNCC_FRAME_RECV:
3392 return tch_recv(net, arg, 1);
3393 case GSM_TRAU_FRAME:
3394 return tch_frame(net, arg);
3395 }
3396
3397 memset(&rel, 0, sizeof(struct gsm_mncc));
3398 rel.callref = data->callref;
3399
3400 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003401 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003402
3403 /* Callref unknown */
3404 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003405 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003406 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3407 "Received '%s' from MNCC with "
3408 "unknown callref %d\n", data->called.number,
3409 get_mncc_name(msg_type), data->callref);
3410 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003411 return mncc_release_ind(net, NULL, data->callref,
3412 GSM48_CAUSE_LOC_PRN_S_LU,
3413 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003414 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003415 if (!data->called.number[0] && !data->imsi[0]) {
3416 DEBUGP(DCC, "(bts - trx - ts - ti) "
3417 "Received '%s' from MNCC with "
3418 "no number or IMSI\n", get_mncc_name(msg_type));
3419 /* Invalid number */
3420 return mncc_release_ind(net, NULL, data->callref,
3421 GSM48_CAUSE_LOC_PRN_S_LU,
3422 GSM48_CC_CAUSE_INV_NR_FORMAT);
3423 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003424 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003425 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003426 subscr = subscr_get_by_extension(net,
3427 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003428 else
Harald Welte9176bd42009-07-23 18:46:00 +02003429 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003430 /* If subscriber is not found */
3431 if (!subscr) {
3432 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3433 "Received '%s' from MNCC with "
3434 "unknown subscriber %s\n", data->called.number,
3435 get_mncc_name(msg_type), data->called.number);
3436 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003437 return mncc_release_ind(net, NULL, data->callref,
3438 GSM48_CAUSE_LOC_PRN_S_LU,
3439 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003440 }
3441 /* If subscriber is not "attached" */
3442 if (!subscr->lac) {
3443 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3444 "Received '%s' from MNCC with "
3445 "detached subscriber %s\n", data->called.number,
3446 get_mncc_name(msg_type), data->called.number);
3447 subscr_put(subscr);
3448 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003449 return mncc_release_ind(net, NULL, data->callref,
3450 GSM48_CAUSE_LOC_PRN_S_LU,
3451 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003452 }
3453 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003454 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3455 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003456 DEBUGP(DCC, "No memory for trans.\n");
3457 subscr_put(subscr);
3458 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003459 mncc_release_ind(net, NULL, data->callref,
3460 GSM48_CAUSE_LOC_PRN_S_LU,
3461 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003462 return -ENOMEM;
3463 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003464 /* Find lchan */
Harald Welte1a6f7982009-08-09 18:52:33 +02003465 lchan = lchan_for_subscr(subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003466 /* If subscriber has no lchan */
3467 if (!lchan) {
3468 /* find transaction with this subscriber already paging */
3469 llist_for_each_entry(transt, &net->trans_list, entry) {
3470 /* Transaction of our lchan? */
3471 if (transt == trans ||
3472 transt->subscr != subscr)
3473 continue;
3474 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3475 "Received '%s' from MNCC with "
3476 "unallocated channel, paging already "
3477 "started.\n", bts->nr,
3478 data->called.number,
3479 get_mncc_name(msg_type));
3480 return 0;
3481 }
3482 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003483 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003484 /* Trigger paging */
3485 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3486 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003487 return 0;
3488 }
3489 /* Assign lchan */
3490 trans->lchan = lchan;
3491 use_lchan(lchan);
3492 }
3493 lchan = trans->lchan;
3494
3495 /* if paging did not respond yet */
3496 if (!lchan) {
3497 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3498 "Received '%s' from MNCC in paging state\n",
3499 (trans->subscr)?(trans->subscr->extension):"-",
3500 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003501 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3502 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003503 if (msg_type == MNCC_REL_REQ)
3504 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3505 else
3506 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3507 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003508 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003509 return rc;
3510 }
3511
3512 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3513 "Received '%s' from MNCC in state %d (%s)\n",
3514 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3515 trans->transaction_id,
3516 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003517 get_mncc_name(msg_type), trans->cc.state,
3518 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003519
3520 /* Find function for current state and message */
3521 for (i = 0; i < DOWNSLLEN; i++)
3522 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003523 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003524 break;
3525 if (i == DOWNSLLEN) {
3526 DEBUGP(DCC, "Message unhandled at this state.\n");
3527 return 0;
3528 }
3529
3530 rc = downstatelist[i].rout(trans, arg);
3531
3532 return rc;
3533}
3534
3535
3536static struct datastate {
3537 u_int32_t states;
3538 int type;
3539 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3540} datastatelist[] = {
3541 /* mobile originating call establishment */
3542 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3543 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3544 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3545 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3546 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3547 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3548 /* mobile terminating call establishment */
3549 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3550 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3551 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3552 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3553 {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 */
3554 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3555 /* signalling during call */
3556 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3557 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3558 {SBIT(GSM_CSTATE_ACTIVE),
3559 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3560 {ALL_STATES,
3561 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3562 {ALL_STATES,
3563 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3564 {ALL_STATES,
3565 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3566 {SBIT(GSM_CSTATE_ACTIVE),
3567 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3568 {SBIT(GSM_CSTATE_ACTIVE),
3569 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3570 {SBIT(GSM_CSTATE_ACTIVE),
3571 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3572 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3573 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3574 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3575 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3576 {SBIT(GSM_CSTATE_ACTIVE),
3577 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3578 /* clearing */
3579 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3580 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3581 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3582 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3583 {ALL_STATES, /* 5.4.3.4 */
3584 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3585};
3586
3587#define DATASLLEN \
3588 (sizeof(datastatelist) / sizeof(struct datastate))
3589
Harald Welte4bc90a12008-12-27 16:32:52 +00003590static int gsm0408_rcv_cc(struct msgb *msg)
3591{
3592 struct gsm48_hdr *gh = msgb_l3(msg);
3593 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003594 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003595 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003596 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003597 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003598
Harald Welte4bfdfe72009-06-10 23:11:52 +08003599 if (msg_type & 0x80) {
3600 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3601 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003602 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003603
3604 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003605 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003606
Harald Welte6f5aee02009-07-23 21:21:14 +02003607 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003608 "Received '%s' from MS in state %d (%s)\n",
3609 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3610 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003611 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3612 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003613
3614 /* Create transaction */
3615 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003616 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003617 "creating new trans.\n", transaction_id);
3618 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003619 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3620 transaction_id, new_callref++);
3621 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003622 DEBUGP(DCC, "No memory for trans.\n");
3623 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003624 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003625 GSM48_MT_CC_RELEASE_COMPL);
3626 return -ENOMEM;
3627 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003628 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003629 trans->lchan = lchan;
3630 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003631 }
3632
3633 /* find function for current state and message */
3634 for (i = 0; i < DATASLLEN; i++)
3635 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003636 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003637 break;
3638 if (i == DATASLLEN) {
3639 DEBUGP(DCC, "Message unhandled at this state.\n");
3640 return 0;
3641 }
3642
3643 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003644
3645 return rc;
3646}
3647
Harald Welte52b1f982008-12-23 20:25:15 +00003648/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3649int gsm0408_rcvmsg(struct msgb *msg)
3650{
3651 struct gsm48_hdr *gh = msgb_l3(msg);
3652 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003653 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003654
3655 switch (pdisc) {
3656 case GSM48_PDISC_CC:
3657 rc = gsm0408_rcv_cc(msg);
3658 break;
3659 case GSM48_PDISC_MM:
3660 rc = gsm0408_rcv_mm(msg);
3661 break;
3662 case GSM48_PDISC_RR:
3663 rc = gsm0408_rcv_rr(msg);
3664 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003665 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003666 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003667 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003668 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003669 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003670 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3671 pdisc);
3672 break;
3673 default:
3674 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3675 pdisc);
3676 break;
3677 }
3678
3679 return rc;
3680}
Harald Welte8470bf22008-12-25 23:28:35 +00003681
Harald Welte8470bf22008-12-25 23:28:35 +00003682/* Section 9.1.8 / Table 9.9 */
3683struct chreq {
3684 u_int8_t val;
3685 u_int8_t mask;
3686 enum chreq_type type;
3687};
3688
3689/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3690static const struct chreq chreq_type_neci1[] = {
3691 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3692 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3693 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3694 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3695 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3696 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3697 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3698 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3699 { 0x10, 0xf0, CHREQ_T_SDCCH },
3700 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3701 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3702 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3703};
3704
3705/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3706static const struct chreq chreq_type_neci0[] = {
3707 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3708 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3709 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3710 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3711 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3712 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3713 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3714 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3715};
3716
3717static const enum gsm_chan_t ctype_by_chreq[] = {
3718 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3719 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3720 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3721 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3722 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3723 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3724 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3725 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3726 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3727 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3728 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3729 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3730};
3731
Harald Weltee14a57c2008-12-29 04:08:28 +00003732static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3733 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3734 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3735 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3736 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3737 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3738 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3739 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3740 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3741 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3742 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3743 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3744 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3745};
3746
Harald Welte8470bf22008-12-25 23:28:35 +00003747enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3748{
3749 int i;
3750 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3751
3752 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3753 const struct chreq *chr = &chreq_type_neci0[i];
3754 if ((ra & chr->mask) == chr->val)
3755 return ctype_by_chreq[chr->type];
3756 }
3757 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3758 return GSM_LCHAN_SDCCH;
3759}
Harald Weltee14a57c2008-12-29 04:08:28 +00003760
3761enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3762{
3763 int i;
3764 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
3765
3766 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3767 const struct chreq *chr = &chreq_type_neci0[i];
3768 if ((ra & chr->mask) == chr->val)
3769 return reason_by_chreq[chr->type];
3770 }
3771 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3772 return GSM_CHREQ_REASON_OTHER;
3773}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003774
3775/* dequeue messages to layer 4 */
3776int bsc_upqueue(struct gsm_network *net)
3777{
3778 struct gsm_mncc *mncc;
3779 struct msgb *msg;
3780 int work = 0;
3781
3782 if (net)
3783 while ((msg = msgb_dequeue(&net->upqueue))) {
3784 mncc = (struct gsm_mncc *)msg->data;
3785 if (net->mncc_recv)
3786 net->mncc_recv(net, mncc->msg_type, mncc);
3787 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003788 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003789 }
3790
3791 return work;
3792}
Harald Weltedcaf5652009-07-23 18:56:43 +02003793
Harald Welte805f6442009-07-28 18:25:29 +02003794/*
3795 * This will be ran by the linker when loading the DSO. We use it to
3796 * do system initialization, e.g. registration of signal handlers.
3797 */
3798static __attribute__((constructor)) void on_dso_load_0408(void)
3799{
3800 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3801 "loc_updating_oper");
3802 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3803 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3804}