blob: f0ec3ff9655a0a749ec46a284fce34757546f348 [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)) {
Harald Welteee5ad162009-08-09 19:07:00 +0200367 int rc;
368
Holger Freytherd51524f2009-06-09 08:27:07 +0000369 db_subscriber_alloc_tmsi(lchan->subscr);
Holger Freytherd51524f2009-06-09 08:27:07 +0000370 tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
371 release_loc_updating_req(lchan);
Harald Welteee5ad162009-08-09 19:07:00 +0200372 rc = gsm0408_loc_upd_acc(msg->lchan, tmsi);
373 /* call subscr_update after putting the loc_upd_acc
374 * in the transmit queue, since S_SUBSCR_ATTACHED might
375 * trigger further action like SMS delivery */
376 subscr_update(lchan->subscr, msg->trx->bts,
377 GSM_SUBSCRIBER_UPDATE_ATTACHED);
378 return rc;
Holger Freytherd51524f2009-06-09 08:27:07 +0000379 }
380
381 return 0;
382}
383
Holger Freyther7c19f742009-06-06 13:54:35 +0000384static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
385 void *handler_data, void *signal_data)
386{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800387 struct gsm_trans *trans, *temp;
388
Holger Freyther7c19f742009-06-06 13:54:35 +0000389 if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
390 return 0;
391
392 /*
393 * Cancel any outstanding location updating request
394 * operation taking place on the lchan.
395 */
Harald Welte1a5c6bd2009-07-04 09:35:21 +0200396 struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
Harald Weltec05677b2009-06-26 20:17:06 +0200397 if (!lchan)
398 return 0;
399
Holger Freyther7c19f742009-06-06 13:54:35 +0000400 release_loc_updating_req(lchan);
401
Harald Welte4bfdfe72009-06-10 23:11:52 +0800402 /* Free all transactions that are associated with the released lchan */
Harald Weltedcaf5652009-07-23 18:56:43 +0200403 /* FIXME: this is not neccessarily the right thing to do, we should
404 * only set trans->lchan to NULL and wait for another lchan to be
405 * established to the same MM entity (phone/subscriber) */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800406 llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
407 if (trans->lchan == lchan)
Harald Weltedcaf5652009-07-23 18:56:43 +0200408 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800409 }
410
Holger Freyther7c19f742009-06-06 13:54:35 +0000411 return 0;
412}
413
Harald Welte52b1f982008-12-23 20:25:15 +0000414static void to_bcd(u_int8_t *bcd, u_int16_t val)
415{
Harald Welte4b634542008-12-27 01:55:51 +0000416 bcd[2] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000417 val = val / 10;
418 bcd[1] = val % 10;
419 val = val / 10;
Harald Welte4b634542008-12-27 01:55:51 +0000420 bcd[0] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000421 val = val / 10;
422}
423
Holger Freyther17746612008-12-28 16:32:44 +0000424void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
Harald Welte52b1f982008-12-23 20:25:15 +0000425 u_int16_t mnc, u_int16_t lac)
426{
427 u_int8_t bcd[3];
428
429 to_bcd(bcd, mcc);
430 lai48->digits[0] = bcd[0] | (bcd[1] << 4);
431 lai48->digits[1] = bcd[2];
432
433 to_bcd(bcd, mnc);
Harald Welte4b634542008-12-27 01:55:51 +0000434 /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
435#if 0
Harald Welte8470bf22008-12-25 23:28:35 +0000436 lai48->digits[1] |= bcd[2] << 4;
437 lai48->digits[2] = bcd[0] | (bcd[1] << 4);
Harald Welte4b634542008-12-27 01:55:51 +0000438#else
439 lai48->digits[1] |= 0xf << 4;
440 lai48->digits[2] = bcd[1] | (bcd[2] << 4);
441#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000442
Harald Welte4b634542008-12-27 01:55:51 +0000443 lai48->lac = htons(lac);
Harald Welte52b1f982008-12-23 20:25:15 +0000444}
445
Harald Welte255539c2008-12-28 02:26:27 +0000446#define TMSI_LEN 5
Harald Welte52b1f982008-12-23 20:25:15 +0000447#define MID_TMSI_LEN (TMSI_LEN + 2)
448
Harald Welte255539c2008-12-28 02:26:27 +0000449int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +0000450{
Harald Welte65e74cc2008-12-29 01:55:35 +0000451 u_int32_t *tptr = (u_int32_t *) &buf[3];
Harald Welte255539c2008-12-28 02:26:27 +0000452
Harald Welte4b634542008-12-27 01:55:51 +0000453 buf[0] = GSM48_IE_MOBILE_ID;
Harald Welte1a412182008-12-27 22:13:43 +0000454 buf[1] = TMSI_LEN;
Harald Welte4b634542008-12-27 01:55:51 +0000455 buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
Harald Welte255539c2008-12-28 02:26:27 +0000456 *tptr = htonl(tmsi);
457
458 return 7;
Harald Welte52b1f982008-12-23 20:25:15 +0000459}
460
Harald Welte09e38af2009-02-16 22:52:23 +0000461static const char bcd_num_digits[] = {
462 '0', '1', '2', '3', '4', '5', '6', '7',
463 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
464};
465
Harald Welte0c389302009-06-10 12:08:54 +0800466/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
467int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
468 int h_len)
Harald Welte09e38af2009-02-16 22:52:23 +0000469{
470 u_int8_t in_len = bcd_lv[0];
471 int i;
472
Harald Welte0c389302009-06-10 12:08:54 +0800473 for (i = 1 + h_len; i <= in_len; i++) {
Harald Welte09e38af2009-02-16 22:52:23 +0000474 /* lower nibble */
475 output_len--;
476 if (output_len <= 1)
477 break;
478 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
479
480 /* higher nibble */
481 output_len--;
482 if (output_len <= 1)
483 break;
484 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
485 }
486 if (output_len >= 1)
487 *output++ = '\0';
488
Harald Welte0c389302009-06-10 12:08:54 +0800489 return 0;
Harald Welte09e38af2009-02-16 22:52:23 +0000490}
491
492/* convert a single ASCII character to call-control BCD */
493static int asc_to_bcd(const char asc)
494{
495 int i;
496
497 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
498 if (bcd_num_digits[i] == asc)
499 return i;
500 }
501 return -EINVAL;
502}
503
Harald Welte0c389302009-06-10 12:08:54 +0800504/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
Harald Welte09e38af2009-02-16 22:52:23 +0000505int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
Harald Welte0c389302009-06-10 12:08:54 +0800506 int h_len, const char *input)
Harald Welte09e38af2009-02-16 22:52:23 +0000507{
508 int in_len = strlen(input);
509 int i;
Harald Welte0c389302009-06-10 12:08:54 +0800510 u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000511
512 /* two digits per byte, plus type byte */
Harald Welte0c389302009-06-10 12:08:54 +0800513 bcd_lv[0] = in_len/2 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000514 if (in_len % 2)
515 bcd_lv[0]++;
516
Harald Welte0c389302009-06-10 12:08:54 +0800517 if (bcd_lv[0] > max_len)
518 return -EIO;
Harald Welte09e38af2009-02-16 22:52:23 +0000519
520 for (i = 0; i < in_len; i++) {
521 int rc = asc_to_bcd(input[i]);
522 if (rc < 0)
523 return rc;
524 if (i % 2 == 0)
525 *bcd_cur = rc;
526 else
527 *bcd_cur++ |= (rc << 4);
528 }
529 /* append padding nibble in case of odd length */
530 if (i % 2)
531 *bcd_cur++ |= 0xf0;
532
533 /* return how many bytes we used */
534 return (bcd_cur - bcd_lv);
535}
536
Harald Welte0c389302009-06-10 12:08:54 +0800537/* decode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800538static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
Harald Welte0c389302009-06-10 12:08:54 +0800539 const u_int8_t *lv)
540{
541 u_int8_t in_len = lv[0];
542 int i, s;
543
544 if (in_len < 1)
545 return -EINVAL;
546
Harald Welte4bfdfe72009-06-10 23:11:52 +0800547 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
Harald Welte0c389302009-06-10 12:08:54 +0800548
549 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800550 bcap->transfer = lv[1] & 0x07;
551 bcap->mode = (lv[1] & 0x08) >> 3;
552 bcap->coding = (lv[1] & 0x10) >> 4;
553 bcap->radio = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800554
555 i = 1;
556 s = 0;
557 while(!(lv[i] & 0x80)) {
558 i++; /* octet 3a etc */
559 if (in_len < i)
560 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800561 bcap->speech_ver[s++] = lv[i] & 0x0f;
562 bcap->speech_ver[s] = -1; /* end of list */
Harald Welte0c389302009-06-10 12:08:54 +0800563 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800564 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800565 if (s == 7) /* maximum speech versions + end of list */
566 return 0;
567 }
568
569 return 0;
570}
571
572/* encode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800573static int encode_bearer_cap(struct msgb *msg, int lv_only,
574 const struct gsm_mncc_bearer_cap *bcap)
Harald Welte0c389302009-06-10 12:08:54 +0800575{
576 u_int8_t lv[32 + 1];
577 int i, s;
578
Harald Welte4bfdfe72009-06-10 23:11:52 +0800579 lv[1] = bcap->transfer;
580 lv[1] |= bcap->mode << 3;
581 lv[1] |= bcap->coding << 4;
582 lv[1] |= bcap->radio << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800583
584 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800585 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
Harald Welte0c389302009-06-10 12:08:54 +0800586 i++; /* octet 3a etc */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800587 lv[i] = bcap->speech_ver[s];
Harald Welte0c389302009-06-10 12:08:54 +0800588 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800589 lv[i] |= bcap->speech_ctm << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800590 }
591 lv[i] |= 0x80; /* last IE of octet 3 etc */
592
593 lv[0] = i;
594 if (lv_only)
595 msgb_lv_put(msg, lv[0], lv+1);
596 else
597 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
598
599 return 0;
600}
601
602/* decode 'call control cap' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800603static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800604{
605 u_int8_t in_len = lv[0];
606
607 if (in_len < 1)
608 return -EINVAL;
609
610 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800611 ccap->dtmf = lv[1] & 0x01;
612 ccap->pcp = (lv[1] & 0x02) >> 1;
Harald Welte0c389302009-06-10 12:08:54 +0800613
614 return 0;
615}
616
617/* decode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800618static int decode_called(struct gsm_mncc_number *called,
619 const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800620{
621 u_int8_t in_len = lv[0];
622
623 if (in_len < 1)
624 return -EINVAL;
625
626 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800627 called->plan = lv[1] & 0x0f;
628 called->type = (lv[1] & 0x70) >> 4;
Harald Welte0c389302009-06-10 12:08:54 +0800629
630 /* octet 4..N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800631 decode_bcd_number(called->number, sizeof(called->number), lv, 1);
Harald Welte0c389302009-06-10 12:08:54 +0800632
633 return 0;
634}
635
636/* encode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800637static int encode_called(struct msgb *msg,
638 const struct gsm_mncc_number *called)
Harald Welte0c389302009-06-10 12:08:54 +0800639{
640 u_int8_t lv[18];
641 int ret;
642
643 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800644 lv[1] = called->plan;
645 lv[1] |= called->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800646
647 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800648 ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
Harald Welte0c389302009-06-10 12:08:54 +0800649 if (ret < 0)
650 return ret;
651
652 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
653
654 return 0;
655}
656
657/* encode callerid of various IEs */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800658static int encode_callerid(struct msgb *msg, int ie,
659 const struct gsm_mncc_number *callerid)
Harald Welte0c389302009-06-10 12:08:54 +0800660{
661 u_int8_t lv[13];
662 int h_len = 1;
663 int ret;
664
665 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800666 lv[1] = callerid->plan;
667 lv[1] |= callerid->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800668
Harald Welte4bfdfe72009-06-10 23:11:52 +0800669 if (callerid->present || callerid->screen) {
Harald Welte0c389302009-06-10 12:08:54 +0800670 /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800671 lv[2] = callerid->screen;
672 lv[2] |= callerid->present << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800673 lv[2] |= 0x80;
674 h_len++;
675 } else
676 lv[1] |= 0x80;
677
678 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800679 ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
Harald Welte0c389302009-06-10 12:08:54 +0800680 if (ret < 0)
681 return ret;
682
683 msgb_tlv_put(msg, ie, lv[0], lv+1);
684
685 return 0;
686}
687
688/* decode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800689static int decode_cause(struct gsm_mncc_cause *cause,
Harald Welte0c389302009-06-10 12:08:54 +0800690 const u_int8_t *lv)
691{
692 u_int8_t in_len = lv[0];
693 int i;
694
695 if (in_len < 2)
696 return -EINVAL;
697
Harald Welte4bfdfe72009-06-10 23:11:52 +0800698 cause->diag_len = 0;
Harald Welte0c389302009-06-10 12:08:54 +0800699
700 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800701 cause->location = lv[1] & 0x0f;
702 cause->coding = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800703
704 i = 1;
705 if (!(lv[i] & 0x80)) {
706 i++; /* octet 3a */
707 if (in_len < i+1)
708 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800709 cause->rec = 1;
710 cause->rec_val = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800711
712 }
713 i++;
714
715 /* octet 4 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800716 cause->value = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800717 i++;
718
719 if (in_len < i) /* no diag */
720 return 0;
721
722 if (in_len - (i-1) > 32) /* maximum 32 octets */
723 return 0;
724
725 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800726 memcpy(cause->diag, lv + i, in_len - (i-1));
727 cause->diag_len = in_len - (i-1);
Harald Welte0c389302009-06-10 12:08:54 +0800728
729 return 0;
730}
731
732/* encode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800733static int encode_cause(struct msgb *msg, int lv_only,
734 const struct gsm_mncc_cause *cause)
Harald Welte0c389302009-06-10 12:08:54 +0800735{
736 u_int8_t lv[32+4];
737 int i;
738
Harald Welte4bfdfe72009-06-10 23:11:52 +0800739 if (cause->diag_len > 32)
Harald Welte0c389302009-06-10 12:08:54 +0800740 return -EINVAL;
741
742 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800743 lv[1] = cause->location;
744 lv[1] |= cause->coding << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800745
746 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800747 if (cause->rec) {
Harald Welte0c389302009-06-10 12:08:54 +0800748 i++; /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800749 lv[i] = cause->rec_val;
Harald Welte0c389302009-06-10 12:08:54 +0800750 }
751 lv[i] |= 0x80; /* end of octet 3 */
752
753 /* octet 4 */
754 i++;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800755 lv[i] = 0x80 | cause->value;
Harald Welte0c389302009-06-10 12:08:54 +0800756
757 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800758 if (cause->diag_len) {
759 memcpy(lv + i, cause->diag, cause->diag_len);
760 i += cause->diag_len;
Harald Welte0c389302009-06-10 12:08:54 +0800761 }
762
763 lv[0] = i;
764 if (lv_only)
765 msgb_lv_put(msg, lv[0], lv+1);
766 else
767 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
768
769 return 0;
770}
771
772/* encode 'calling number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800773static int encode_calling(struct msgb *msg,
774 const struct gsm_mncc_number *calling)
Harald Welte0c389302009-06-10 12:08:54 +0800775{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800776 return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
Harald Welte0c389302009-06-10 12:08:54 +0800777}
778
779/* encode 'connected number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800780static int encode_connected(struct msgb *msg,
781 const struct gsm_mncc_number *connected)
Harald Welte0c389302009-06-10 12:08:54 +0800782{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800783 return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
Harald Welte0c389302009-06-10 12:08:54 +0800784}
785
786/* encode 'redirecting number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800787static int encode_redirecting(struct msgb *msg,
788 const struct gsm_mncc_number *redirecting)
Harald Welte0c389302009-06-10 12:08:54 +0800789{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800790 return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
Harald Welte0c389302009-06-10 12:08:54 +0800791}
792
793/* decode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800794static int decode_facility(struct gsm_mncc_facility *facility,
Harald Welte0c389302009-06-10 12:08:54 +0800795 const u_int8_t *lv)
796{
797 u_int8_t in_len = lv[0];
798
799 if (in_len < 1)
800 return -EINVAL;
801
Harald Welte4bfdfe72009-06-10 23:11:52 +0800802 if (in_len > sizeof(facility->info))
Harald Welte0c389302009-06-10 12:08:54 +0800803 return -EINVAL;
804
Harald Welte4bfdfe72009-06-10 23:11:52 +0800805 memcpy(facility->info, lv+1, in_len);
806 facility->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800807
808 return 0;
809}
810
811/* encode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800812static int encode_facility(struct msgb *msg, int lv_only,
813 const struct gsm_mncc_facility *facility)
Harald Welte0c389302009-06-10 12:08:54 +0800814{
815 u_int8_t lv[GSM_MAX_FACILITY + 1];
816
Harald Welte4bfdfe72009-06-10 23:11:52 +0800817 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
Harald Welte0c389302009-06-10 12:08:54 +0800818 return -EINVAL;
819
Harald Welte4bfdfe72009-06-10 23:11:52 +0800820 memcpy(lv+1, facility->info, facility->len);
821 lv[0] = facility->len;
Harald Welte0c389302009-06-10 12:08:54 +0800822 if (lv_only)
823 msgb_lv_put(msg, lv[0], lv+1);
824 else
825 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
826
827 return 0;
828}
829
830/* decode 'notify' */
831static int decode_notify(int *notify, const u_int8_t *v)
832{
833 *notify = v[0] & 0x7f;
834
835 return 0;
836}
837
838/* encode 'notify' */
839static int encode_notify(struct msgb *msg, int notify)
840{
841 msgb_v_put(msg, notify | 0x80);
842
843 return 0;
844}
845
846/* encode 'signal' */
847static int encode_signal(struct msgb *msg, int signal)
848{
849 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
850
851 return 0;
852}
853
854/* decode 'keypad' */
855static int decode_keypad(int *keypad, const u_int8_t *lv)
856{
857 u_int8_t in_len = lv[0];
858
859 if (in_len < 1)
860 return -EINVAL;
861
862 *keypad = lv[1] & 0x7f;
863
864 return 0;
865}
866
867/* encode 'keypad' */
868static int encode_keypad(struct msgb *msg, int keypad)
869{
870 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
871
872 return 0;
873}
874
875/* decode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800876static int decode_progress(struct gsm_mncc_progress *progress,
Harald Welte0c389302009-06-10 12:08:54 +0800877 const u_int8_t *lv)
878{
879 u_int8_t in_len = lv[0];
880
881 if (in_len < 2)
882 return -EINVAL;
883
Harald Welte4bfdfe72009-06-10 23:11:52 +0800884 progress->coding = (lv[1] & 0x60) >> 5;
885 progress->location = lv[1] & 0x0f;
886 progress->descr = lv[2] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800887
888 return 0;
889}
890
891/* encode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800892static int encode_progress(struct msgb *msg, int lv_only,
893 const struct gsm_mncc_progress *p)
Harald Welte0c389302009-06-10 12:08:54 +0800894{
895 u_int8_t lv[3];
896
897 lv[0] = 2;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800898 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
899 lv[2] = 0x80 | (p->descr & 0x7f);
Harald Welte0c389302009-06-10 12:08:54 +0800900 if (lv_only)
901 msgb_lv_put(msg, lv[0], lv+1);
902 else
903 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
904
905 return 0;
906}
907
908/* decode 'user-user' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800909static int decode_useruser(struct gsm_mncc_useruser *uu,
Harald Welte0c389302009-06-10 12:08:54 +0800910 const u_int8_t *lv)
911{
912 u_int8_t in_len = lv[0];
Harald Welte4bfdfe72009-06-10 23:11:52 +0800913 char *info = uu->info;
914 int info_len = sizeof(uu->info);
Harald Welte0c389302009-06-10 12:08:54 +0800915 int i;
916
917 if (in_len < 1)
918 return -EINVAL;
919
Harald Welte4bfdfe72009-06-10 23:11:52 +0800920 uu->proto = lv[1];
Harald Welte0c389302009-06-10 12:08:54 +0800921
922 for (i = 2; i <= in_len; i++) {
923 info_len--;
924 if (info_len <= 1)
925 break;
926 *info++ = lv[i];
927 }
928 if (info_len >= 1)
929 *info++ = '\0';
930
931 return 0;
932}
933
934/* encode 'useruser' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800935static int encode_useruser(struct msgb *msg, int lv_only,
936 const struct gsm_mncc_useruser *uu)
Harald Welte0c389302009-06-10 12:08:54 +0800937{
938 u_int8_t lv[GSM_MAX_USERUSER + 2];
939
Harald Welte4bfdfe72009-06-10 23:11:52 +0800940 if (strlen(uu->info) > GSM_MAX_USERUSER)
Harald Welte0c389302009-06-10 12:08:54 +0800941 return -EINVAL;
942
Harald Welte4bfdfe72009-06-10 23:11:52 +0800943 lv[0] = 1 + strlen(uu->info);
944 lv[1] = uu->proto;
945 memcpy(lv + 2, uu->info, strlen(uu->info));
Harald Welte0c389302009-06-10 12:08:54 +0800946 if (lv_only)
947 msgb_lv_put(msg, lv[0], lv+1);
948 else
949 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
950
951 return 0;
952}
953
954/* decode 'ss version' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800955static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
Harald Welte0c389302009-06-10 12:08:54 +0800956 const u_int8_t *lv)
957{
958 u_int8_t in_len = lv[0];
959
Harald Welte4bfdfe72009-06-10 23:11:52 +0800960 if (in_len < 1 || in_len < sizeof(ssv->info))
Harald Welte0c389302009-06-10 12:08:54 +0800961 return -EINVAL;
962
Harald Welte4bfdfe72009-06-10 23:11:52 +0800963 memcpy(ssv->info, lv + 1, in_len);
964 ssv->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800965
966 return 0;
967}
968
969/* encode 'more data' */
970static int encode_more(struct msgb *msg)
971{
972 u_int8_t *ie;
973
974 ie = msgb_put(msg, 1);
975 ie[0] = GSM48_IE_MORE_DATA;
976
977 return 0;
978}
979
Holger Freyther819dd202009-01-04 03:52:50 +0000980struct msgb *gsm48_msgb_alloc(void)
Harald Welte8470bf22008-12-25 23:28:35 +0000981{
Harald Welte966636f2009-06-26 19:39:35 +0200982 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
983 "GSM 04.08");
Harald Welte8470bf22008-12-25 23:28:35 +0000984}
985
Harald Welte39e2ead2009-07-23 21:13:03 +0200986int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
Harald Welte52b1f982008-12-23 20:25:15 +0000987{
Harald Welte39e2ead2009-07-23 21:13:03 +0200988 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
989
990 /* if we get passed a transaction reference, do some common
991 * work that the caller no longer has to do */
992 if (trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +0200993 gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
Harald Welte39e2ead2009-07-23 21:13:03 +0200994 msg->lchan = trans->lchan;
995 }
996
Harald Welte65e74cc2008-12-29 01:55:35 +0000997 if (msg->lchan) {
Harald Welte8470bf22008-12-25 23:28:35 +0000998 msg->trx = msg->lchan->ts->trx;
Harald Welte52b1f982008-12-23 20:25:15 +0000999
Harald Welte4bfdfe72009-06-10 23:11:52 +08001000 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
1001 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
1002 "Sending '%s' to MS.\n", msg->trx->bts->nr,
1003 msg->trx->nr, msg->lchan->ts->nr,
1004 gh->proto_discr & 0xf0,
1005 cc_msg_names[gh->msg_type & 0x3f]);
1006 else
1007 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
1008 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
1009 msg->trx->nr, msg->lchan->ts->nr,
1010 gh->proto_discr, gh->msg_type);
Harald Welte65e74cc2008-12-29 01:55:35 +00001011 }
1012
Harald Welte4b634542008-12-27 01:55:51 +00001013 msg->l3h = msg->data;
1014
Harald Welte8470bf22008-12-25 23:28:35 +00001015 return rsl_data_request(msg, 0);
Harald Welte52b1f982008-12-23 20:25:15 +00001016}
1017
Holger Freyther429e7762008-12-30 13:28:30 +00001018/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
Harald Welte8470bf22008-12-25 23:28:35 +00001019int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
Harald Welte52b1f982008-12-23 20:25:15 +00001020{
Harald Welte8470bf22008-12-25 23:28:35 +00001021 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001022 struct gsm48_hdr *gh;
1023
Harald Welte8470bf22008-12-25 23:28:35 +00001024 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001025
1026 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1027 gh->proto_discr = GSM48_PDISC_MM;
Harald Welte10b487b2008-12-27 19:53:37 +00001028 gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
Harald Welte52b1f982008-12-23 20:25:15 +00001029 gh->data[0] = cause;
1030
Harald Weltedb253af2008-12-30 17:56:55 +00001031 DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
1032
Harald Welte39e2ead2009-07-23 21:13:03 +02001033 return gsm48_sendmsg(msg, NULL);
Harald Welte52b1f982008-12-23 20:25:15 +00001034}
1035
1036/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
Harald Welte75a983f2008-12-27 21:34:06 +00001037int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +00001038{
Harald Welte8470bf22008-12-25 23:28:35 +00001039 struct gsm_bts *bts = lchan->ts->trx->bts;
1040 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001041 struct gsm48_hdr *gh;
1042 struct gsm48_loc_area_id *lai;
1043 u_int8_t *mid;
Holger Freyther07cc8d82008-12-29 06:23:46 +00001044 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001045
Harald Welte8470bf22008-12-25 23:28:35 +00001046 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001047
1048 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1049 gh->proto_discr = GSM48_PDISC_MM;
1050 gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
1051
1052 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
Holger Freyther17746612008-12-28 16:32:44 +00001053 gsm0408_generate_lai(lai, bts->network->country_code,
Harald Welte52b1f982008-12-23 20:25:15 +00001054 bts->network->network_code, bts->location_area_code);
1055
1056 mid = msgb_put(msg, MID_TMSI_LEN);
1057 generate_mid_from_tmsi(mid, tmsi);
1058
1059 DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
1060
Harald Welte39e2ead2009-07-23 21:13:03 +02001061 ret = gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001062
Harald Welteee5ad162009-08-09 19:07:00 +02001063 /* send MM INFO with network name */
Harald Weltedb253af2008-12-30 17:56:55 +00001064 ret = gsm48_tx_mm_info(lchan);
Harald Weltedb253af2008-12-30 17:56:55 +00001065
Holger Freyther07cc8d82008-12-29 06:23:46 +00001066 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001067}
1068
Harald Weltefc977a82008-12-27 10:19:37 +00001069static char bcd2char(u_int8_t bcd)
1070{
1071 if (bcd < 0xa)
1072 return '0' + bcd;
1073 else
1074 return 'A' + (bcd - 0xa);
1075}
1076
Harald Weltebf5e8df2009-02-03 12:59:45 +00001077/* Convert Mobile Identity (10.5.1.4) to string */
Harald Weltefc977a82008-12-27 10:19:37 +00001078static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
1079{
1080 int i;
1081 u_int8_t mi_type;
1082 char *str_cur = string;
Harald Welte4ed0e922009-01-10 03:17:30 +00001083 u_int32_t tmsi;
Harald Weltefc977a82008-12-27 10:19:37 +00001084
1085 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1086
1087 switch (mi_type) {
1088 case GSM_MI_TYPE_NONE:
1089 break;
1090 case GSM_MI_TYPE_TMSI:
Harald Welte4ed0e922009-01-10 03:17:30 +00001091 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
1092 if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
1093 memcpy(&tmsi, &mi[1], 4);
1094 tmsi = ntohl(tmsi);
1095 return snprintf(string, str_len, "%u", tmsi);
Harald Weltefc977a82008-12-27 10:19:37 +00001096 }
1097 break;
1098 case GSM_MI_TYPE_IMSI:
1099 case GSM_MI_TYPE_IMEI:
1100 case GSM_MI_TYPE_IMEISV:
Harald Weltedb253af2008-12-30 17:56:55 +00001101 *str_cur++ = bcd2char(mi[0] >> 4);
1102
1103 for (i = 1; i < mi_len; i++) {
Harald Weltefc977a82008-12-27 10:19:37 +00001104 if (str_cur + 2 >= string + str_len)
1105 return str_cur - string;
1106 *str_cur++ = bcd2char(mi[i] & 0xf);
Harald Weltedb253af2008-12-30 17:56:55 +00001107 /* skip last nibble in last input byte when GSM_EVEN */
1108 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
1109 *str_cur++ = bcd2char(mi[i] >> 4);
Harald Weltefc977a82008-12-27 10:19:37 +00001110 }
1111 break;
1112 default:
1113 break;
1114 }
Harald Weltefc977a82008-12-27 10:19:37 +00001115 *str_cur++ = '\0';
Harald Weltedb253af2008-12-30 17:56:55 +00001116
Harald Weltefc977a82008-12-27 10:19:37 +00001117 return str_cur - string;
1118}
1119
Harald Weltebf5e8df2009-02-03 12:59:45 +00001120/* Transmit Chapter 9.2.10 Identity Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001121static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
1122{
1123 struct msgb *msg = gsm48_msgb_alloc();
1124 struct gsm48_hdr *gh;
Harald Weltefc977a82008-12-27 10:19:37 +00001125
Harald Welte231ad4f2008-12-27 11:15:38 +00001126 msg->lchan = lchan;
1127
1128 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1129 gh->proto_discr = GSM48_PDISC_MM;
1130 gh->msg_type = GSM48_MT_MM_ID_REQ;
1131 gh->data[0] = id_type;
1132
Harald Welte39e2ead2009-07-23 21:13:03 +02001133 return gsm48_sendmsg(msg, NULL);
Harald Welte231ad4f2008-12-27 11:15:38 +00001134}
1135
1136#define MI_SIZE 32
1137
Harald Weltebf5e8df2009-02-03 12:59:45 +00001138/* Parse Chapter 9.2.11 Identity Response */
Harald Welte231ad4f2008-12-27 11:15:38 +00001139static int mm_rx_id_resp(struct msgb *msg)
1140{
1141 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte75a983f2008-12-27 21:34:06 +00001142 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001143 struct gsm_bts *bts = lchan->ts->trx->bts;
1144 struct gsm_network *net = bts->network;
Harald Welte231ad4f2008-12-27 11:15:38 +00001145 u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
1146 char mi_string[MI_SIZE];
1147
1148 mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
Harald Welte61253062008-12-27 11:25:50 +00001149 DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
Harald Welte231ad4f2008-12-27 11:15:38 +00001150 mi_type, mi_string);
1151
Harald Welte75a983f2008-12-27 21:34:06 +00001152 switch (mi_type) {
1153 case GSM_MI_TYPE_IMSI:
Jan Luebbe370b41d2009-08-12 10:19:34 +02001154 /* look up subscriber based on IMSI, create if not found */
1155 if (!lchan->subscr) {
1156 lchan->subscr = subscr_get_by_imsi(net, mi_string);
1157 }
Jan Luebbeb0dfc312009-08-12 10:12:52 +02001158 if (!lchan->subscr) {
Harald Welte9176bd42009-07-23 18:46:00 +02001159 lchan->subscr = db_create_subscriber(net, mi_string);
Jan Luebbeb0dfc312009-08-12 10:12:52 +02001160 if (lchan->subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
1161 dispatch_signal(SS_SUBSCR, S_SUBSCR_FIRST_CONTACT, &lchan->subscr);
1162 }
1163 }
Holger Freyther73487a22008-12-31 18:53:57 +00001164 if (lchan->loc_operation)
1165 lchan->loc_operation->waiting_for_imsi = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001166 break;
1167 case GSM_MI_TYPE_IMEI:
Harald Welte255539c2008-12-28 02:26:27 +00001168 case GSM_MI_TYPE_IMEISV:
Harald Welte75a983f2008-12-27 21:34:06 +00001169 /* update subscribe <-> IMEI mapping */
1170 if (lchan->subscr)
1171 db_subscriber_assoc_imei(lchan->subscr, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001172 if (lchan->loc_operation)
1173 lchan->loc_operation->waiting_for_imei = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001174 break;
1175 }
Holger Freyther73487a22008-12-31 18:53:57 +00001176
1177 /* Check if we can let the mobile station enter */
Holger Freytherd51524f2009-06-09 08:27:07 +00001178 return gsm0408_authorize(lchan, msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001179}
1180
Harald Welte255539c2008-12-28 02:26:27 +00001181
1182static void loc_upd_rej_cb(void *data)
1183{
1184 struct gsm_lchan *lchan = data;
1185
Holger Freyther73487a22008-12-31 18:53:57 +00001186 release_loc_updating_req(lchan);
Holger Freythere97f7fb2008-12-31 18:52:11 +00001187 gsm0408_loc_upd_rej(lchan, reject_cause);
Holger Freyther67b4b9a2009-01-01 03:46:11 +00001188 lchan_auto_release(lchan);
Harald Welte255539c2008-12-28 02:26:27 +00001189}
1190
Holger Freytherb7193e42008-12-29 17:44:08 +00001191static void schedule_reject(struct gsm_lchan *lchan)
1192{
Holger Freyther73487a22008-12-31 18:53:57 +00001193 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1194 lchan->loc_operation->updating_timer.data = lchan;
Harald Welteff117a82009-05-23 05:22:08 +00001195 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
Holger Freytherb7193e42008-12-29 17:44:08 +00001196}
1197
Harald Welte2a139372009-02-22 21:14:55 +00001198static const char *lupd_name(u_int8_t type)
1199{
1200 switch (type) {
1201 case GSM48_LUPD_NORMAL:
1202 return "NORMAL";
1203 case GSM48_LUPD_PERIODIC:
1204 return "PEROIDOC";
1205 case GSM48_LUPD_IMSI_ATT:
1206 return "IMSI ATTACH";
1207 default:
1208 return "UNKNOWN";
1209 }
1210}
1211
Harald Welte231ad4f2008-12-27 11:15:38 +00001212#define MI_SIZE 32
Harald Weltebf5e8df2009-02-03 12:59:45 +00001213/* Chapter 9.2.15: Receive Location Updating Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001214static int mm_rx_loc_upd_req(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001215{
Harald Welte8470bf22008-12-25 23:28:35 +00001216 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001217 struct gsm48_loc_upd_req *lu;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001218 struct gsm_subscriber *subscr = NULL;
Harald Welte255539c2008-12-28 02:26:27 +00001219 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001220 struct gsm_bts *bts = lchan->ts->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +00001221 u_int8_t mi_type;
Harald Welte231ad4f2008-12-27 11:15:38 +00001222 char mi_string[MI_SIZE];
1223 int rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001224
Harald Welte8470bf22008-12-25 23:28:35 +00001225 lu = (struct gsm48_loc_upd_req *) gh->data;
1226
1227 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
Harald Welte52b1f982008-12-23 20:25:15 +00001228
Harald Weltefc977a82008-12-27 10:19:37 +00001229 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1230
Harald Weltea0368542009-06-27 02:58:43 +02001231 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte2a139372009-02-22 21:14:55 +00001232 lupd_name(lu->type));
Holger Freyther73487a22008-12-31 18:53:57 +00001233
Holger Freythereaf04692009-06-06 13:54:44 +00001234 /*
1235 * Pseudo Spoof detection: Just drop a second/concurrent
1236 * location updating request.
1237 */
1238 if (lchan->loc_operation) {
Harald Weltea0368542009-06-27 02:58:43 +02001239 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Holger Freythereaf04692009-06-06 13:54:44 +00001240 lchan->loc_operation);
1241 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1242 return 0;
1243 }
1244
Holger Freyther73487a22008-12-31 18:53:57 +00001245 allocate_loc_updating_req(lchan);
1246
Harald Welte52b1f982008-12-23 20:25:15 +00001247 switch (mi_type) {
1248 case GSM_MI_TYPE_IMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001249 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001250 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001251 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001252 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001253
Jan Luebbe370b41d2009-08-12 10:19:34 +02001254 /* look up subscriber based on IMSI, create if not found */
1255 subscr = subscr_get_by_imsi(bts->network, mi_string);
1256 if (!subscr) {
1257 subscr = db_create_subscriber(bts->network, mi_string);
1258 }
Jan Luebbeb0dfc312009-08-12 10:12:52 +02001259 if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
1260 dispatch_signal(SS_SUBSCR, S_SUBSCR_FIRST_CONTACT, &subscr);
1261 }
Harald Welte4b634542008-12-27 01:55:51 +00001262 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001263 case GSM_MI_TYPE_TMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001264 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001265 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001266 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001267 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001268
Harald Welte52b1f982008-12-23 20:25:15 +00001269 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welte9176bd42009-07-23 18:46:00 +02001270 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte52b1f982008-12-23 20:25:15 +00001271 if (!subscr) {
Harald Welte231ad4f2008-12-27 11:15:38 +00001272 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte255539c2008-12-28 02:26:27 +00001273 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
Holger Freyther73487a22008-12-31 18:53:57 +00001274 lchan->loc_operation->waiting_for_imsi = 1;
Harald Welte52b1f982008-12-23 20:25:15 +00001275 }
1276 break;
1277 case GSM_MI_TYPE_IMEI:
1278 case GSM_MI_TYPE_IMEISV:
1279 /* no sim card... FIXME: what to do ? */
Harald Weltea0368542009-06-27 02:58:43 +02001280 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001281 break;
1282 default:
Harald Weltea0368542009-06-27 02:58:43 +02001283 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001284 break;
1285 }
1286
Harald Welte24516ea2009-07-04 10:18:00 +02001287 /* schedule the reject timer */
1288 schedule_reject(lchan);
1289
Harald Welte4bfdfe72009-06-10 23:11:52 +08001290 if (!subscr) {
Harald Weltea0368542009-06-27 02:58:43 +02001291 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001292 /* FIXME: request id? close channel? */
1293 return -EINVAL;
1294 }
1295
Harald Welte255539c2008-12-28 02:26:27 +00001296 lchan->subscr = subscr;
1297
Harald Welte24516ea2009-07-04 10:18:00 +02001298 /* check if we can let the subscriber into our network immediately
1299 * or if we need to wait for identity responses. */
Holger Freytherd51524f2009-06-09 08:27:07 +00001300 return gsm0408_authorize(lchan, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001301}
1302
Harald Welte13cac662009-07-29 12:10:35 +02001303/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Harald Welte7584aea2009-02-11 11:44:12 +00001304int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1305{
1306 struct msgb *msg = gsm48_msgb_alloc();
1307 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1308 struct gsm48_chan_mode_modify *cmm =
1309 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
Harald Welte4a543e82009-02-28 13:17:55 +00001310 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
Harald Welte7584aea2009-02-11 11:44:12 +00001311
Harald Welte4a543e82009-02-28 13:17:55 +00001312 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
Harald Welte7ccf7782009-02-17 01:43:01 +00001313
Harald Welte45b407a2009-05-23 15:51:12 +00001314 lchan->tch_mode = mode;
Harald Welte7584aea2009-02-11 11:44:12 +00001315 msg->lchan = lchan;
1316 gh->proto_discr = GSM48_PDISC_RR;
1317 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1318
1319 /* fill the channel information element, this code
1320 * should probably be shared with rsl_rx_chan_rqd() */
1321 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte02b0e092009-02-28 13:11:07 +00001322 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
Harald Welte7584aea2009-02-11 11:44:12 +00001323 cmm->chan_desc.h0.h = 0;
1324 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1325 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1326 cmm->mode = mode;
1327
Harald Welte39e2ead2009-07-23 21:13:03 +02001328 return gsm48_sendmsg(msg, NULL);
Harald Welte7584aea2009-02-11 11:44:12 +00001329}
1330
Harald Welte4bfdfe72009-06-10 23:11:52 +08001331#if 0
1332static u_int8_t to_bcd8(u_int8_t val)
1333{
1334 return ((val / 10) << 4) | (val % 10);
1335}
1336#endif
1337
Harald Weltedb253af2008-12-30 17:56:55 +00001338/* Section 9.2.15a */
1339int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1340{
1341 struct msgb *msg = gsm48_msgb_alloc();
1342 struct gsm48_hdr *gh;
1343 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Weltedb253af2008-12-30 17:56:55 +00001344 u_int8_t *ptr8;
1345 u_int16_t *ptr16;
1346 int name_len;
Harald Weltedb253af2008-12-30 17:56:55 +00001347 int i;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001348#if 0
1349 time_t cur_t;
1350 struct tm* cur_time;
1351 int tz15min;
1352#endif
Harald Weltedb253af2008-12-30 17:56:55 +00001353
1354 msg->lchan = lchan;
1355
1356 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1357 gh->proto_discr = GSM48_PDISC_MM;
1358 gh->msg_type = GSM48_MT_MM_INFO;
1359
1360 if (net->name_long) {
1361 name_len = strlen(net->name_long);
1362 /* 10.5.3.5a */
1363 ptr8 = msgb_put(msg, 3);
1364 ptr8[0] = GSM48_IE_NAME_LONG;
1365 ptr8[1] = name_len*2 +1;
1366 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1367
1368 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1369 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001370 ptr16[i] = htons(net->name_long[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001371
1372 /* FIXME: Use Cell Broadcast, not UCS-2, since
1373 * UCS-2 is only supported by later revisions of the spec */
1374 }
1375
1376 if (net->name_short) {
1377 name_len = strlen(net->name_short);
1378 /* 10.5.3.5a */
1379 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Welte7543eb72009-07-19 17:51:36 +02001380 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Weltedb253af2008-12-30 17:56:55 +00001381 ptr8[1] = name_len*2 + 1;
1382 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1383
Harald Weltee872cb12009-01-01 00:33:37 +00001384 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
Harald Weltedb253af2008-12-30 17:56:55 +00001385 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001386 ptr16[i] = htons(net->name_short[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001387 }
1388
1389#if 0
1390 /* Section 10.5.3.9 */
1391 cur_t = time(NULL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001392 cur_time = gmtime(&cur_t);
Harald Weltedb253af2008-12-30 17:56:55 +00001393 ptr8 = msgb_put(msg, 8);
1394 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1395 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1396 ptr8[2] = to_bcd8(cur_time->tm_mon);
1397 ptr8[3] = to_bcd8(cur_time->tm_mday);
1398 ptr8[4] = to_bcd8(cur_time->tm_hour);
1399 ptr8[5] = to_bcd8(cur_time->tm_min);
1400 ptr8[6] = to_bcd8(cur_time->tm_sec);
1401 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1402 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001403 ptr8[7] = to_bcd8(tz15min);
Harald Weltedb253af2008-12-30 17:56:55 +00001404 if (tz15min < 0)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001405 ptr8[7] |= 0x80;
Harald Weltedb253af2008-12-30 17:56:55 +00001406#endif
1407
Harald Welte39e2ead2009-07-23 21:13:03 +02001408 return gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001409}
1410
Harald Welte7984d5c2009-08-12 22:56:50 +02001411/* Section 9.2.2 */
1412int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand)
1413{
1414 struct msgb *msg = gsm48_msgb_alloc();
1415 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1416 u_int8_t *r;
1417
1418 DEBUGP(DMM, "-> AUTH REQ\n");
1419
1420 msg->lchan = lchan;
1421 gh->proto_discr = GSM48_PDISC_MM;
1422 gh->msg_type = GSM48_MT_MM_AUTH_REQ;
1423
1424 /* 16 bytes RAND parameters */
1425 r = msgb_put(msg, 16);
1426 if (rand)
1427 memcpy(r, rand, 16);
1428
1429 return gsm48_sendmsg(msg, NULL);
1430}
1431
1432/* Section 9.2.1 */
1433int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan)
1434{
1435 DEBUGP(DMM, "-> AUTH REJECT\n");
1436 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ);
1437}
1438
Harald Welte4b634542008-12-27 01:55:51 +00001439static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1440{
Harald Welte4b634542008-12-27 01:55:51 +00001441 DEBUGP(DMM, "-> CM SERVICE ACK\n");
Harald Welte65e74cc2008-12-29 01:55:35 +00001442 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
Harald Welte4b634542008-12-27 01:55:51 +00001443}
Harald Welteba4cf162009-01-10 01:49:35 +00001444
1445/* 9.2.6 CM service reject */
1446static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1447 enum gsm48_reject_value value)
1448{
1449 struct msgb *msg = gsm48_msgb_alloc();
1450 struct gsm48_hdr *gh;
1451
1452 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1453
1454 msg->lchan = lchan;
1455 use_lchan(lchan);
1456
1457 gh->proto_discr = GSM48_PDISC_MM;
1458 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1459 gh->data[0] = value;
1460 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1461
Harald Welte39e2ead2009-07-23 21:13:03 +02001462 return gsm48_sendmsg(msg, NULL);
Harald Welteba4cf162009-01-10 01:49:35 +00001463}
1464
Harald Welte3ac7f102009-08-10 10:12:45 +02001465static int send_siemens_mrpci(struct gsm_lchan *lchan,
1466 u_int8_t *classmark2_lv)
1467{
1468 struct rsl_mrpci mrpci;
1469
1470 if (classmark2_lv[0] < 2)
1471 return -EINVAL;
1472
1473 mrpci.power_class = classmark2_lv[1] & 0x7;
1474 mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
1475 mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
1476 mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
1477
1478 return rsl_siemens_mrpci(lchan, &mrpci);
1479}
Harald Welte4ed0e922009-01-10 03:17:30 +00001480
1481/*
1482 * Handle CM Service Requests
1483 * a) Verify that the packet is long enough to contain the information
1484 * we require otherwsie reject with INCORRECT_MESSAGE
1485 * b) Try to parse the TMSI. If we do not have one reject
1486 * c) Check that we know the subscriber with the TMSI otherwise reject
1487 * with a HLR cause
1488 * d) Set the subscriber on the gsm_lchan and accept
1489 */
Harald Welte4b634542008-12-27 01:55:51 +00001490static int gsm48_rx_mm_serv_req(struct msgb *msg)
1491{
Harald Welteba4cf162009-01-10 01:49:35 +00001492 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001493 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001494
Harald Welte9176bd42009-07-23 18:46:00 +02001495 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welteba4cf162009-01-10 01:49:35 +00001496 struct gsm_subscriber *subscr;
1497 struct gsm48_hdr *gh = msgb_l3(msg);
1498 struct gsm48_service_request *req =
1499 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001500 /* unfortunately in Phase1 the classmar2 length is variable */
1501 u_int8_t classmark2_len = gh->data[1];
1502 u_int8_t *classmark2 = gh->data+2;
1503 u_int8_t mi_len = *(classmark2 + classmark2_len);
1504 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001505
Harald Weltec9e02182009-05-01 19:07:53 +00001506 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001507 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001508 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001509 return gsm48_tx_mm_serv_rej(msg->lchan,
1510 GSM48_REJECT_INCORRECT_MESSAGE);
1511 }
1512
1513 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001514 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001515 return gsm48_tx_mm_serv_rej(msg->lchan,
1516 GSM48_REJECT_INCORRECT_MESSAGE);
1517 }
1518
Harald Weltec9e02182009-05-01 19:07:53 +00001519 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001520 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001521 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001522 return gsm48_tx_mm_serv_rej(msg->lchan,
1523 GSM48_REJECT_INCORRECT_MESSAGE);
1524 }
1525
Harald Weltec9e02182009-05-01 19:07:53 +00001526 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001527 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001528 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001529
Harald Welte3ac7f102009-08-10 10:12:45 +02001530 if (is_siemens_bts(bts))
1531 send_siemens_mrpci(msg->lchan, classmark2-1);
1532
Harald Welte9176bd42009-07-23 18:46:00 +02001533 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Holger Freythereb443982009-06-04 13:58:42 +00001534
Harald Welte2a139372009-02-22 21:14:55 +00001535 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001536 if (!subscr)
1537 return gsm48_tx_mm_serv_rej(msg->lchan,
1538 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1539
1540 if (!msg->lchan->subscr)
1541 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001542 else if (msg->lchan->subscr != subscr) {
1543 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1544 subscr_put(subscr);
1545 }
1546
Harald Weltec2e302d2009-07-05 14:08:13 +02001547 subscr->equipment.classmark2_len = classmark2_len;
1548 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1549 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001550
Harald Welte4b634542008-12-27 01:55:51 +00001551 return gsm48_tx_mm_serv_ack(msg->lchan);
1552}
1553
Harald Welte2a139372009-02-22 21:14:55 +00001554static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1555{
Harald Welte9176bd42009-07-23 18:46:00 +02001556 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2a139372009-02-22 21:14:55 +00001557 struct gsm48_hdr *gh = msgb_l3(msg);
1558 struct gsm48_imsi_detach_ind *idi =
1559 (struct gsm48_imsi_detach_ind *) gh->data;
1560 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1561 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001562 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001563
1564 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1565 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1566 mi_type, mi_string);
1567
1568 switch (mi_type) {
1569 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001570 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001571 break;
1572 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001573 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001574 break;
1575 case GSM_MI_TYPE_IMEI:
1576 case GSM_MI_TYPE_IMEISV:
1577 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001578 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001579 break;
1580 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001581 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001582 break;
1583 }
1584
Holger Freyther4a49e772009-04-12 05:37:29 +00001585 if (subscr) {
1586 subscr_update(subscr, msg->trx->bts,
1587 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001588 DEBUGP(DMM, "Subscriber: %s\n",
1589 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001590 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001591 } else
Harald Welte2a139372009-02-22 21:14:55 +00001592 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1593
Harald Welte2a139372009-02-22 21:14:55 +00001594 return 0;
1595}
1596
Harald Welted2a7f5a2009-06-05 20:08:20 +00001597static int gsm48_rx_mm_status(struct msgb *msg)
1598{
1599 struct gsm48_hdr *gh = msgb_l3(msg);
1600
1601 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1602
1603 return 0;
1604}
1605
Harald Weltebf5e8df2009-02-03 12:59:45 +00001606/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001607static int gsm0408_rcv_mm(struct msgb *msg)
1608{
1609 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001610 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001611
1612 switch (gh->msg_type & 0xbf) {
1613 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001614 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001615 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001616 break;
1617 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001618 rc = mm_rx_id_resp(msg);
1619 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001620 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001621 rc = gsm48_rx_mm_serv_req(msg);
1622 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001623 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001624 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001625 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001626 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001627 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1628 msg->lchan->subscr ?
1629 msg->lchan->subscr->imsi :
1630 "unknown subscriber");
1631 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001632 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001633 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1634 break;
1635 case GSM48_MT_MM_CM_REEST_REQ:
1636 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1637 break;
1638 case GSM48_MT_MM_AUTH_RESP:
1639 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001640 break;
1641 default:
1642 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1643 gh->msg_type);
1644 break;
1645 }
1646
1647 return rc;
1648}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001649
Harald Welte2d35ae62009-02-06 12:02:13 +00001650/* Receive a PAGING RESPONSE message from the MS */
1651static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1652{
Harald Welte9176bd42009-07-23 18:46:00 +02001653 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2d35ae62009-02-06 12:02:13 +00001654 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001655 u_int8_t *classmark2_lv = gh->data + 1;
1656 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1657 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001658 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001659 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001660 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001661 int rc = 0;
1662
Harald Welte61548982009-02-22 21:26:29 +00001663 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001664 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1665 mi_type, mi_string);
Harald Welte3ac7f102009-08-10 10:12:45 +02001666
1667 if (is_siemens_bts(bts))
1668 send_siemens_mrpci(msg->lchan, classmark2_lv);
1669
Harald Weltefe18d8f2009-02-22 21:14:24 +00001670 switch (mi_type) {
1671 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001672 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001673 break;
1674 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001675 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001676 break;
1677 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001678
1679 if (!subscr) {
1680 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001681 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001682 return -EINVAL;
1683 }
1684 DEBUGP(DRR, "<- Channel was requested by %s\n",
Harald Welte76042182009-08-08 16:03:15 +02001685 subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001686
Harald Weltec2e302d2009-07-05 14:08:13 +02001687 subscr->equipment.classmark2_len = *classmark2_lv;
1688 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1689 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001690
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001691 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001692 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001693 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001694 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1695 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001696 return -EINVAL;
1697 } else {
1698 DEBUGP(DRR, "<- Channel already owned by us\n");
1699 subscr_put(subscr);
1700 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001701 }
1702
Harald Welte595ad7b2009-02-16 22:05:44 +00001703 sig_data.subscr = subscr;
1704 sig_data.bts = msg->lchan->ts->trx->bts;
1705 sig_data.lchan = msg->lchan;
1706
1707 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001708
1709 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001710 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001711
Harald Welte7584aea2009-02-11 11:44:12 +00001712 /* FIXME: somehow signal the completion of the PAGING to
1713 * the entity that requested the paging */
1714
Harald Welte2d35ae62009-02-06 12:02:13 +00001715 return rc;
1716}
1717
Harald Weltef7c43522009-06-09 20:24:21 +00001718static int gsm48_rx_rr_classmark(struct msgb *msg)
1719{
1720 struct gsm48_hdr *gh = msgb_l3(msg);
1721 struct gsm_subscriber *subscr = msg->lchan->subscr;
1722 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1723 u_int8_t cm2_len, cm3_len = 0;
1724 u_int8_t *cm2, *cm3 = NULL;
1725
1726 DEBUGP(DRR, "CLASSMARK CHANGE ");
1727
1728 /* classmark 2 */
1729 cm2_len = gh->data[0];
1730 cm2 = &gh->data[1];
1731 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1732
1733 if (payload_len > cm2_len + 1) {
1734 /* we must have a classmark3 */
1735 if (gh->data[cm2_len+1] != 0x20) {
1736 DEBUGPC(DRR, "ERR CM3 TAG\n");
1737 return -EINVAL;
1738 }
1739 if (cm2_len > 3) {
1740 DEBUGPC(DRR, "CM2 too long!\n");
1741 return -EINVAL;
1742 }
1743
1744 cm3_len = gh->data[cm2_len+2];
1745 cm3 = &gh->data[cm2_len+3];
1746 if (cm3_len > 14) {
1747 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1748 return -EINVAL;
1749 }
1750 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1751 }
1752 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001753 subscr->equipment.classmark2_len = cm2_len;
1754 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001755 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001756 subscr->equipment.classmark3_len = cm3_len;
1757 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001758 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001759 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001760 }
1761
Harald Weltef7c43522009-06-09 20:24:21 +00001762 return 0;
1763}
1764
Harald Weltecf5b3592009-05-01 18:28:42 +00001765static int gsm48_rx_rr_status(struct msgb *msg)
1766{
1767 struct gsm48_hdr *gh = msgb_l3(msg);
1768
1769 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1770 rr_cause_name(gh->data[0]));
1771
1772 return 0;
1773}
1774
Harald Weltef7c43522009-06-09 20:24:21 +00001775static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1776{
1777 struct gsm48_hdr *gh = msgb_l3(msg);
1778 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1779 static struct gsm_meas_rep meas_rep;
1780
Harald Welte10d0e672009-06-27 02:53:10 +02001781 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001782 parse_meas_rep(&meas_rep, gh->data, payload_len);
1783 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001784 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001785 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001786 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001787 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001788 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001789 else
Harald Welte10d0e672009-06-27 02:53:10 +02001790 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001791 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1792 meas_rep.rxqual_sub);
1793
Harald Welte10d0e672009-06-27 02:53:10 +02001794 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001795
1796 /* FIXME: put the results somwhere */
1797
1798 return 0;
1799}
1800
Harald Weltebf5e8df2009-02-03 12:59:45 +00001801/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001802static int gsm0408_rcv_rr(struct msgb *msg)
1803{
1804 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001805 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001806
1807 switch (gh->msg_type) {
1808 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001809 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001810 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001811 case GSM48_MT_RR_GPRS_SUSP_REQ:
1812 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1813 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001814 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001815 rc = gsm48_rr_rx_pag_resp(msg);
1816 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001817 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1818 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte13cac662009-07-29 12:10:35 +02001819 /* We've successfully modified the MS side of the channel,
1820 * now go on to modify the BTS side of the channel */
Harald Welte9943c5b2009-07-29 15:41:29 +02001821 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
Harald Welte2c38aa82009-02-18 03:44:24 +00001822 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001823 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001824 case GSM48_MT_RR_STATUS:
1825 rc = gsm48_rx_rr_status(msg);
1826 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001827 case GSM48_MT_RR_MEAS_REP:
1828 rc = gsm48_rx_rr_meas_rep(msg);
1829 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001830 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001831 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001832 gh->msg_type);
1833 break;
1834 }
1835
Harald Welte2d35ae62009-02-06 12:02:13 +00001836 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001837}
1838
Harald Welte115d1032009-08-10 11:43:22 +02001839/* 7.1.7 and 9.1.7: RR CHANnel RELease */
Holger Freythere64a7a32009-02-06 21:55:37 +00001840int gsm48_send_rr_release(struct gsm_lchan *lchan)
1841{
1842 struct msgb *msg = gsm48_msgb_alloc();
1843 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1844 u_int8_t *cause;
1845
1846 msg->lchan = lchan;
1847 gh->proto_discr = GSM48_PDISC_RR;
1848 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1849
1850 cause = msgb_put(msg, 1);
1851 cause[0] = GSM48_RR_CAUSE_NORMAL;
1852
1853 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1854 lchan->nr, lchan->type);
1855
Harald Welteae0f2362009-07-19 18:36:49 +02001856 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001857 gsm48_sendmsg(msg, NULL);
Harald Welte76042182009-08-08 16:03:15 +02001858 /* FIXME: Start Timer T3109 */
Harald Welteae0f2362009-07-19 18:36:49 +02001859
1860 /* Deactivate the SACCH on the BTS side */
1861 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001862}
1863
Harald Welte4bc90a12008-12-27 16:32:52 +00001864/* Call Control */
1865
Harald Welte7584aea2009-02-11 11:44:12 +00001866/* The entire call control code is written in accordance with Figure 7.10c
1867 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1868 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1869 * it for voice */
1870
Harald Welte4bfdfe72009-06-10 23:11:52 +08001871static void new_cc_state(struct gsm_trans *trans, int state)
1872{
1873 if (state > 31 || state < 0)
1874 return;
1875
1876 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001877 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001878
Harald Weltedcaf5652009-07-23 18:56:43 +02001879 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001880}
1881
1882static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001883{
1884 struct msgb *msg = gsm48_msgb_alloc();
1885 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1886 u_int8_t *cause, *call_state;
1887
Harald Welte4bc90a12008-12-27 16:32:52 +00001888 gh->msg_type = GSM48_MT_CC_STATUS;
1889
1890 cause = msgb_put(msg, 3);
1891 cause[0] = 2;
1892 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1893 cause[2] = 0x80 | 30; /* response to status inquiry */
1894
1895 call_state = msgb_put(msg, 1);
1896 call_state[0] = 0xc0 | 0x00;
1897
Harald Welte39e2ead2009-07-23 21:13:03 +02001898 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001899}
1900
Harald Welte6f4b7532008-12-29 00:39:37 +00001901static int gsm48_tx_simple(struct gsm_lchan *lchan,
1902 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001903{
1904 struct msgb *msg = gsm48_msgb_alloc();
1905 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1906
1907 msg->lchan = lchan;
1908
Harald Welte6f4b7532008-12-29 00:39:37 +00001909 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001910 gh->msg_type = msg_type;
1911
Harald Welte39e2ead2009-07-23 21:13:03 +02001912 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001913}
1914
Harald Welte4bfdfe72009-06-10 23:11:52 +08001915static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1916{
Harald Weltedcaf5652009-07-23 18:56:43 +02001917 if (bsc_timer_pending(&trans->cc.timer)) {
1918 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1919 bsc_del_timer(&trans->cc.timer);
1920 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001921 }
1922}
1923
1924static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1925 int msg_type, struct gsm_mncc *mncc)
1926{
1927 struct msgb *msg;
1928
1929 if (trans)
1930 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001931 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001932 "Sending '%s' to MNCC.\n",
1933 trans->lchan->ts->trx->bts->nr,
1934 trans->lchan->ts->trx->nr,
1935 trans->lchan->ts->nr, trans->transaction_id,
1936 (trans->subscr)?(trans->subscr->extension):"-",
1937 get_mncc_name(msg_type));
1938 else
1939 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1940 "Sending '%s' to MNCC.\n",
1941 (trans->subscr)?(trans->subscr->extension):"-",
1942 get_mncc_name(msg_type));
1943 else
1944 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1945 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1946
1947 mncc->msg_type = msg_type;
1948
Harald Welte966636f2009-06-26 19:39:35 +02001949 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001950 if (!msg)
1951 return -ENOMEM;
1952 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1953 msgb_enqueue(&net->upqueue, msg);
1954
1955 return 0;
1956}
1957
1958int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1959 u_int32_t callref, int location, int value)
1960{
1961 struct gsm_mncc rel;
1962
Harald Welte92f70c52009-06-12 01:54:08 +08001963 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001964 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001965 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001966 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1967}
1968
Harald Weltedcaf5652009-07-23 18:56:43 +02001969/* Call Control Specific transaction release.
1970 * gets called by trans_free, DO NOT CALL YOURSELF! */
1971void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001972{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001973 gsm48_stop_cc_timer(trans);
1974
1975 /* send release to L4, if callref still exists */
1976 if (trans->callref) {
1977 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02001978 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001979 GSM48_CAUSE_LOC_PRN_S_LU,
1980 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001981 }
Harald Weltedcaf5652009-07-23 18:56:43 +02001982 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001983 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02001984 if (trans->lchan)
1985 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001986}
1987
1988static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1989
Harald Welte09e38af2009-02-16 22:52:23 +00001990/* call-back from paging the B-end of the connection */
1991static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001992 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001993{
Harald Welte7ccf7782009-02-17 01:43:01 +00001994 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001995 struct gsm_subscriber *subscr = param;
1996 struct gsm_trans *transt, *tmp;
1997 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001998
Harald Welte09e38af2009-02-16 22:52:23 +00001999 if (hooknum != GSM_HOOK_RR_PAGING)
2000 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002001
2002 if (!subscr)
2003 return -EINVAL;
2004 net = subscr->net;
2005 if (!net) {
2006 DEBUGP(DCC, "Error Network not set!\n");
2007 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00002008 }
Harald Welte7584aea2009-02-11 11:44:12 +00002009
Harald Welte4bfdfe72009-06-10 23:11:52 +08002010 /* check all tranactions (without lchan) for subscriber */
2011 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
2012 if (transt->subscr != subscr || transt->lchan)
2013 continue;
2014 switch (event) {
2015 case GSM_PAGING_SUCCEEDED:
2016 if (!lchan) // paranoid
2017 break;
2018 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
2019 subscr->extension);
2020 /* Assign lchan */
2021 if (!transt->lchan) {
2022 transt->lchan = lchan;
2023 use_lchan(lchan);
2024 }
2025 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02002026 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002027 break;
2028 case GSM_PAGING_EXPIRED:
2029 DEBUGP(DCC, "Paging subscr %s expired!\n",
2030 subscr->extension);
2031 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002032 mncc_release_ind(transt->subscr->net, transt,
2033 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002034 GSM48_CAUSE_LOC_PRN_S_LU,
2035 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002036 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002037 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002038 break;
2039 }
2040 }
Harald Welte09e38af2009-02-16 22:52:23 +00002041 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00002042}
Harald Welte7584aea2009-02-11 11:44:12 +00002043
Harald Welte805f6442009-07-28 18:25:29 +02002044/* some other part of the code sends us a signal */
2045static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
2046 void *handler_data, void *signal_data)
2047{
2048 struct gsm_lchan *lchan = signal_data;
2049 struct gsm_bts_trx_ts *ts;
2050 int rc;
2051
2052 if (subsys != SS_ABISIP)
2053 return 0;
2054
2055 /* in case we use direct BTS-to-BTS RTP */
2056 if (ipacc_rtp_direct)
2057 return 0;
2058
2059 ts = lchan->ts;
2060
2061 switch (signal) {
2062 case S_ABISIP_BIND_ACK:
2063 /* the BTS has successfully bound a TCH to a local ip/port,
2064 * which means we can connect our UDP socket to it */
2065 if (ts->abis_ip.rtp_socket) {
2066 rtp_socket_free(ts->abis_ip.rtp_socket);
2067 ts->abis_ip.rtp_socket = NULL;
2068 }
2069
2070 ts->abis_ip.rtp_socket = rtp_socket_create();
2071 if (!ts->abis_ip.rtp_socket)
2072 goto out_err;
2073
2074 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2075 ts->abis_ip.bound_ip,
2076 ts->abis_ip.bound_port);
2077 if (rc < 0)
2078 goto out_err;
2079 break;
2080 case S_ABISIP_DISC_IND:
2081 /* the BTS tells us a RTP stream has been disconnected */
2082 if (ts->abis_ip.rtp_socket) {
2083 rtp_socket_free(ts->abis_ip.rtp_socket);
2084 ts->abis_ip.rtp_socket = NULL;
2085 }
2086 break;
2087 }
2088
2089 return 0;
2090out_err:
2091 /* FIXME: do something */
2092 return 0;
2093}
2094
2095/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2096static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2097{
2098 struct gsm_bts_trx_ts *ts = lchan->ts;
2099 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2100 int rc;
2101
2102 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2103 ntohs(rs->rtp.sin_local.sin_port),
2104 ts->abis_ip.conn_id,
2105 /* FIXME: use RTP payload of bound socket, not BTS*/
2106 ts->abis_ip.rtp_payload2);
2107
2108 return rc;
2109}
2110
Harald Welte49f48b82009-02-17 15:29:33 +00002111/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002112static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002113{
Harald Welte11fa29c2009-02-19 17:24:39 +00002114 struct gsm_bts *bts = lchan->ts->trx->bts;
2115 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002116 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002117 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002118
Harald Welte11fa29c2009-02-19 17:24:39 +00002119 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2120 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2121 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2122
2123 if (bts->type != remote_bts->type) {
2124 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2125 return -EINVAL;
2126 }
Harald Welte49f48b82009-02-17 15:29:33 +00002127
Harald Welte11fa29c2009-02-19 17:24:39 +00002128 switch (bts->type) {
2129 case GSM_BTS_TYPE_NANOBTS_900:
2130 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002131 if (!ipacc_rtp_direct) {
2132 /* connect the TCH's to our RTP proxy */
2133 rc = ipacc_connect_proxy_bind(lchan);
2134 if (rc < 0)
2135 return rc;
2136 rc = ipacc_connect_proxy_bind(remote_lchan);
2137
2138 /* connect them with each other */
2139 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2140 remote_lchan->ts->abis_ip.rtp_socket);
2141 } else {
2142 /* directly connect TCH RTP streams to each other */
2143 ts = remote_lchan->ts;
2144 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2145 ts->abis_ip.bound_port,
2146 lchan->ts->abis_ip.conn_id,
2147 ts->abis_ip.rtp_payload2);
2148 if (rc < 0)
2149 return rc;
2150 ts = lchan->ts;
2151 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2152 ts->abis_ip.bound_port,
2153 remote_lchan->ts->abis_ip.conn_id,
2154 ts->abis_ip.rtp_payload2);
2155 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002156 break;
2157 case GSM_BTS_TYPE_BS11:
2158 trau_mux_map_lchan(lchan, remote_lchan);
2159 break;
2160 default:
2161 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002162 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002163 break;
2164 }
Harald Welte49f48b82009-02-17 15:29:33 +00002165
2166 return 0;
2167}
2168
Harald Welte4bfdfe72009-06-10 23:11:52 +08002169/* bridge channels of two transactions */
2170static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002171{
Harald Weltedcaf5652009-07-23 18:56:43 +02002172 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2173 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002174
Harald Welte4bfdfe72009-06-10 23:11:52 +08002175 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002176 return -EIO;
2177
Harald Welte4bfdfe72009-06-10 23:11:52 +08002178 if (!trans1->lchan || !trans2->lchan)
2179 return -EIO;
2180
2181 /* through-connect channel */
2182 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002183}
2184
Harald Welte4bfdfe72009-06-10 23:11:52 +08002185/* enable receive of channels to upqueue */
2186static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2187{
2188 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002189
Harald Welte4bfdfe72009-06-10 23:11:52 +08002190 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002191 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002192 if (!trans)
2193 return -EIO;
2194 if (!trans->lchan)
2195 return 0;
2196
2197 // todo IPACCESS
2198 if (enable)
2199 return trau_recv_lchan(trans->lchan, data->callref);
2200 return trau_mux_unmap(NULL, data->callref);
2201}
2202
2203/* send a frame to channel */
2204static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2205{
2206 struct gsm_trans *trans;
2207
2208 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002209 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002210 if (!trans)
2211 return -EIO;
2212 if (!trans->lchan)
2213 return 0;
2214 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2215 trans->lchan->type != GSM_LCHAN_TCH_H)
2216 return 0;
2217
2218 // todo IPACCESS
2219 return trau_send_lchan(trans->lchan,
2220 (struct decoded_trau_frame *)frame->data);
2221}
2222
2223
2224static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2225{
2226 DEBUGP(DCC, "-> STATUS ENQ\n");
2227 return gsm48_cc_tx_status(trans, msg);
2228}
2229
2230static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2231static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2232
2233static void gsm48_cc_timeout(void *arg)
2234{
2235 struct gsm_trans *trans = arg;
2236 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002237 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2238 int mo_location = GSM48_CAUSE_LOC_USER;
2239 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2240 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002241 struct gsm_mncc mo_rel, l4_rel;
2242
2243 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2244 mo_rel.callref = trans->callref;
2245 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2246 l4_rel.callref = trans->callref;
2247
Harald Weltedcaf5652009-07-23 18:56:43 +02002248 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002249 case 0x303:
2250 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002251 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002252 break;
2253 case 0x310:
2254 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002255 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002256 break;
2257 case 0x313:
2258 disconnect = 1;
2259 /* unknown, did not find it in the specs */
2260 break;
2261 case 0x301:
2262 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002263 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002264 break;
2265 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002266 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002267 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002268 gsm48_cc_tx_release(trans, &trans->cc.msg);
2269 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002270 break; /* stay in release state */
2271 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002272 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002273 return;
2274// release = 1;
2275// l4_cause = 14;
2276// break;
2277 case 0x306:
2278 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002279 mo_cause = trans->cc.msg.cause.value;
2280 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002281 break;
2282 case 0x323:
2283 disconnect = 1;
2284 break;
2285 default:
2286 release = 1;
2287 }
2288
2289 if (release && trans->callref) {
2290 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002291 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002292 l4_location, l4_cause);
2293 trans->callref = 0;
2294 }
2295
2296 if (disconnect && trans->callref) {
2297 /* process disconnect towards layer 4 */
2298 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002299 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002300 }
2301
2302 /* process disconnect towards mobile station */
2303 if (disconnect || release) {
2304 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002305 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2306 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2307 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002308 mo_rel.cause.diag_len = 3;
2309
2310 if (disconnect)
2311 gsm48_cc_tx_disconnect(trans, &mo_rel);
2312 if (release)
2313 gsm48_cc_tx_release(trans, &mo_rel);
2314 }
2315
2316}
2317
2318static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2319 int sec, int micro)
2320{
2321 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002322 trans->cc.timer.cb = gsm48_cc_timeout;
2323 trans->cc.timer.data = trans;
2324 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2325 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002326}
2327
2328static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2329{
2330 struct gsm48_hdr *gh = msgb_l3(msg);
2331 u_int8_t msg_type = gh->msg_type & 0xbf;
2332 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2333 struct tlv_parsed tp;
2334 struct gsm_mncc setup;
2335
2336 memset(&setup, 0, sizeof(struct gsm_mncc));
2337 setup.callref = trans->callref;
2338 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2339 /* emergency setup is identified by msg_type */
2340 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2341 setup.emergency = 1;
2342
2343 /* use subscriber as calling party number */
2344 if (trans->subscr) {
2345 setup.fields |= MNCC_F_CALLING;
2346 strncpy(setup.calling.number, trans->subscr->extension,
2347 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002348 strncpy(setup.imsi, trans->subscr->imsi,
2349 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002350 }
2351 /* bearer capability */
2352 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2353 setup.fields |= MNCC_F_BEARER_CAP;
2354 decode_bearer_cap(&setup.bearer_cap,
2355 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2356 }
2357 /* facility */
2358 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2359 setup.fields |= MNCC_F_FACILITY;
2360 decode_facility(&setup.facility,
2361 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2362 }
2363 /* called party bcd number */
2364 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2365 setup.fields |= MNCC_F_CALLED;
2366 decode_called(&setup.called,
2367 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2368 }
2369 /* user-user */
2370 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2371 setup.fields |= MNCC_F_USERUSER;
2372 decode_useruser(&setup.useruser,
2373 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2374 }
2375 /* ss-version */
2376 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2377 setup.fields |= MNCC_F_SSVERSION;
2378 decode_ssversion(&setup.ssversion,
2379 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2380 }
2381 /* CLIR suppression */
2382 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2383 setup.clir.sup = 1;
2384 /* CLIR invocation */
2385 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2386 setup.clir.inv = 1;
2387 /* cc cap */
2388 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2389 setup.fields |= MNCC_F_CCCAP;
2390 decode_cccap(&setup.cccap,
2391 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2392 }
2393
Harald Welte4bfdfe72009-06-10 23:11:52 +08002394 new_cc_state(trans, GSM_CSTATE_INITIATED);
2395
2396 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002397 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002398
Harald Welte13cac662009-07-29 12:10:35 +02002399 /* MNCC code will modify the channel asynchronously, we should
2400 * ipaccess-bind only after the modification has been made to the
2401 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002402 return 0;
2403}
2404
2405static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002406{
2407 struct msgb *msg = gsm48_msgb_alloc();
2408 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002409 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002410 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002411
Harald Welte7ccf7782009-02-17 01:43:01 +00002412 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002413
Harald Welte4bfdfe72009-06-10 23:11:52 +08002414 /* transaction id must not be assigned */
2415 if (trans->transaction_id != 0xff) { /* unasssigned */
2416 DEBUGP(DCC, "TX Setup with assigned transaction. "
2417 "This is not allowed!\n");
2418 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002419 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002420 GSM48_CAUSE_LOC_PRN_S_LU,
2421 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002422 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002423 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002424 return rc;
2425 }
2426
2427 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002428 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2429 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002430 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002431 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002432 GSM48_CAUSE_LOC_PRN_S_LU,
2433 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002434 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002435 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002436 return rc;
2437 }
Harald Welte78283ef2009-07-23 21:36:44 +02002438 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002439
Harald Welte65e74cc2008-12-29 01:55:35 +00002440 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002441
Harald Welte4bfdfe72009-06-10 23:11:52 +08002442 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002443
Harald Welte4bfdfe72009-06-10 23:11:52 +08002444 /* bearer capability */
2445 if (setup->fields & MNCC_F_BEARER_CAP)
2446 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2447 /* facility */
2448 if (setup->fields & MNCC_F_FACILITY)
2449 encode_facility(msg, 0, &setup->facility);
2450 /* progress */
2451 if (setup->fields & MNCC_F_PROGRESS)
2452 encode_progress(msg, 0, &setup->progress);
2453 /* calling party BCD number */
2454 if (setup->fields & MNCC_F_CALLING)
2455 encode_calling(msg, &setup->calling);
2456 /* called party BCD number */
2457 if (setup->fields & MNCC_F_CALLED)
2458 encode_called(msg, &setup->called);
2459 /* user-user */
2460 if (setup->fields & MNCC_F_USERUSER)
2461 encode_useruser(msg, 0, &setup->useruser);
2462 /* redirecting party BCD number */
2463 if (setup->fields & MNCC_F_REDIRECTING)
2464 encode_redirecting(msg, &setup->redirecting);
2465 /* signal */
2466 if (setup->fields & MNCC_F_SIGNAL)
2467 encode_signal(msg, setup->signal);
2468
2469 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002470
Harald Welte39e2ead2009-07-23 21:13:03 +02002471 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002472}
2473
Harald Welte4bfdfe72009-06-10 23:11:52 +08002474static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2475{
2476 struct gsm48_hdr *gh = msgb_l3(msg);
2477 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2478 struct tlv_parsed tp;
2479 struct gsm_mncc call_conf;
2480
2481 gsm48_stop_cc_timer(trans);
2482 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2483
2484 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2485 call_conf.callref = trans->callref;
2486 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2487#if 0
2488 /* repeat */
2489 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2490 call_conf.repeat = 1;
2491 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2492 call_conf.repeat = 2;
2493#endif
2494 /* bearer capability */
2495 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2496 call_conf.fields |= MNCC_F_BEARER_CAP;
2497 decode_bearer_cap(&call_conf.bearer_cap,
2498 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2499 }
2500 /* cause */
2501 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2502 call_conf.fields |= MNCC_F_CAUSE;
2503 decode_cause(&call_conf.cause,
2504 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2505 }
2506 /* cc cap */
2507 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2508 call_conf.fields |= MNCC_F_CCCAP;
2509 decode_cccap(&call_conf.cccap,
2510 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2511 }
2512
2513 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2514
Harald Welte596fed42009-07-23 19:06:52 +02002515 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2516 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002517}
2518
2519static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2520{
2521 struct gsm_mncc *proceeding = arg;
2522 struct msgb *msg = gsm48_msgb_alloc();
2523 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2524
Harald Welte4bfdfe72009-06-10 23:11:52 +08002525 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2526
2527 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2528
2529 /* bearer capability */
2530 if (proceeding->fields & MNCC_F_BEARER_CAP)
2531 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2532 /* facility */
2533 if (proceeding->fields & MNCC_F_FACILITY)
2534 encode_facility(msg, 0, &proceeding->facility);
2535 /* progress */
2536 if (proceeding->fields & MNCC_F_PROGRESS)
2537 encode_progress(msg, 0, &proceeding->progress);
2538
Harald Welte39e2ead2009-07-23 21:13:03 +02002539 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002540}
2541
2542static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2543{
2544 struct gsm48_hdr *gh = msgb_l3(msg);
2545 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2546 struct tlv_parsed tp;
2547 struct gsm_mncc alerting;
2548
2549 gsm48_stop_cc_timer(trans);
2550 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2551
2552 memset(&alerting, 0, sizeof(struct gsm_mncc));
2553 alerting.callref = trans->callref;
2554 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2555 /* facility */
2556 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2557 alerting.fields |= MNCC_F_FACILITY;
2558 decode_facility(&alerting.facility,
2559 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2560 }
2561
2562 /* progress */
2563 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2564 alerting.fields |= MNCC_F_PROGRESS;
2565 decode_progress(&alerting.progress,
2566 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2567 }
2568 /* ss-version */
2569 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2570 alerting.fields |= MNCC_F_SSVERSION;
2571 decode_ssversion(&alerting.ssversion,
2572 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2573 }
2574
2575 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2576
Harald Welte596fed42009-07-23 19:06:52 +02002577 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2578 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002579}
2580
2581static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2582{
2583 struct gsm_mncc *alerting = arg;
2584 struct msgb *msg = gsm48_msgb_alloc();
2585 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2586
Harald Welte4bfdfe72009-06-10 23:11:52 +08002587 gh->msg_type = GSM48_MT_CC_ALERTING;
2588
2589 /* facility */
2590 if (alerting->fields & MNCC_F_FACILITY)
2591 encode_facility(msg, 0, &alerting->facility);
2592 /* progress */
2593 if (alerting->fields & MNCC_F_PROGRESS)
2594 encode_progress(msg, 0, &alerting->progress);
2595 /* user-user */
2596 if (alerting->fields & MNCC_F_USERUSER)
2597 encode_useruser(msg, 0, &alerting->useruser);
2598
2599 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2600
Harald Welte39e2ead2009-07-23 21:13:03 +02002601 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002602}
2603
2604static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2605{
2606 struct gsm_mncc *progress = arg;
2607 struct msgb *msg = gsm48_msgb_alloc();
2608 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2609
Harald Welte4bfdfe72009-06-10 23:11:52 +08002610 gh->msg_type = GSM48_MT_CC_PROGRESS;
2611
2612 /* progress */
2613 encode_progress(msg, 1, &progress->progress);
2614 /* user-user */
2615 if (progress->fields & MNCC_F_USERUSER)
2616 encode_useruser(msg, 0, &progress->useruser);
2617
Harald Welte39e2ead2009-07-23 21:13:03 +02002618 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002619}
2620
2621static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2622{
2623 struct gsm_mncc *connect = arg;
2624 struct msgb *msg = gsm48_msgb_alloc();
2625 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2626
Harald Welte4bfdfe72009-06-10 23:11:52 +08002627 gh->msg_type = GSM48_MT_CC_CONNECT;
2628
2629 gsm48_stop_cc_timer(trans);
2630 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2631
2632 /* facility */
2633 if (connect->fields & MNCC_F_FACILITY)
2634 encode_facility(msg, 0, &connect->facility);
2635 /* progress */
2636 if (connect->fields & MNCC_F_PROGRESS)
2637 encode_progress(msg, 0, &connect->progress);
2638 /* connected number */
2639 if (connect->fields & MNCC_F_CONNECTED)
2640 encode_connected(msg, &connect->connected);
2641 /* user-user */
2642 if (connect->fields & MNCC_F_USERUSER)
2643 encode_useruser(msg, 0, &connect->useruser);
2644
2645 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2646
Harald Welte39e2ead2009-07-23 21:13:03 +02002647 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002648}
2649
2650static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2651{
2652 struct gsm48_hdr *gh = msgb_l3(msg);
2653 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2654 struct tlv_parsed tp;
2655 struct gsm_mncc connect;
2656
2657 gsm48_stop_cc_timer(trans);
2658
2659 memset(&connect, 0, sizeof(struct gsm_mncc));
2660 connect.callref = trans->callref;
2661 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2662 /* use subscriber as connected party number */
2663 if (trans->subscr) {
2664 connect.fields |= MNCC_F_CONNECTED;
2665 strncpy(connect.connected.number, trans->subscr->extension,
2666 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002667 strncpy(connect.imsi, trans->subscr->imsi,
2668 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002669 }
2670 /* facility */
2671 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2672 connect.fields |= MNCC_F_FACILITY;
2673 decode_facility(&connect.facility,
2674 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2675 }
2676 /* user-user */
2677 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2678 connect.fields |= MNCC_F_USERUSER;
2679 decode_useruser(&connect.useruser,
2680 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2681 }
2682 /* ss-version */
2683 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2684 connect.fields |= MNCC_F_SSVERSION;
2685 decode_ssversion(&connect.ssversion,
2686 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2687 }
2688
2689 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2690
Harald Welte596fed42009-07-23 19:06:52 +02002691 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002692}
2693
2694
2695static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2696{
2697 struct gsm_mncc connect_ack;
2698
2699 gsm48_stop_cc_timer(trans);
2700
2701 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2702
2703 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2704 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002705 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002706 &connect_ack);
2707}
2708
2709static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2710{
2711 struct msgb *msg = gsm48_msgb_alloc();
2712 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2713
Harald Welte4bfdfe72009-06-10 23:11:52 +08002714 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2715
2716 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2717
Harald Welte39e2ead2009-07-23 21:13:03 +02002718 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002719}
2720
2721static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2722{
2723 struct gsm48_hdr *gh = msgb_l3(msg);
2724 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2725 struct tlv_parsed tp;
2726 struct gsm_mncc disc;
2727
2728 gsm48_stop_cc_timer(trans);
2729
2730 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2731
2732 memset(&disc, 0, sizeof(struct gsm_mncc));
2733 disc.callref = trans->callref;
2734 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2735 /* cause */
2736 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2737 disc.fields |= MNCC_F_CAUSE;
2738 decode_cause(&disc.cause,
2739 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2740 }
2741 /* facility */
2742 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2743 disc.fields |= MNCC_F_FACILITY;
2744 decode_facility(&disc.facility,
2745 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2746 }
2747 /* user-user */
2748 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2749 disc.fields |= MNCC_F_USERUSER;
2750 decode_useruser(&disc.useruser,
2751 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2752 }
2753 /* ss-version */
2754 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2755 disc.fields |= MNCC_F_SSVERSION;
2756 decode_ssversion(&disc.ssversion,
2757 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2758 }
2759
Harald Welte596fed42009-07-23 19:06:52 +02002760 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002761
2762}
2763
Harald Weltec66b71c2009-06-11 14:23:20 +08002764static struct gsm_mncc_cause default_cause = {
2765 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2766 .coding = 0,
2767 .rec = 0,
2768 .rec_val = 0,
2769 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2770 .diag_len = 0,
2771 .diag = { 0 },
2772};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002773
2774static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2775{
2776 struct gsm_mncc *disc = arg;
2777 struct msgb *msg = gsm48_msgb_alloc();
2778 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2779
Harald Welte4bfdfe72009-06-10 23:11:52 +08002780 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2781
2782 gsm48_stop_cc_timer(trans);
2783 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2784
2785 /* cause */
2786 if (disc->fields & MNCC_F_CAUSE)
2787 encode_cause(msg, 1, &disc->cause);
2788 else
2789 encode_cause(msg, 1, &default_cause);
2790
2791 /* facility */
2792 if (disc->fields & MNCC_F_FACILITY)
2793 encode_facility(msg, 0, &disc->facility);
2794 /* progress */
2795 if (disc->fields & MNCC_F_PROGRESS)
2796 encode_progress(msg, 0, &disc->progress);
2797 /* user-user */
2798 if (disc->fields & MNCC_F_USERUSER)
2799 encode_useruser(msg, 0, &disc->useruser);
2800
2801 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002802 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002803
2804 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2805
Harald Welte39e2ead2009-07-23 21:13:03 +02002806 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002807}
2808
2809static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2810{
2811 struct gsm48_hdr *gh = msgb_l3(msg);
2812 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2813 struct tlv_parsed tp;
2814 struct gsm_mncc rel;
2815 int rc;
2816
2817 gsm48_stop_cc_timer(trans);
2818
2819 memset(&rel, 0, sizeof(struct gsm_mncc));
2820 rel.callref = trans->callref;
2821 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2822 /* cause */
2823 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2824 rel.fields |= MNCC_F_CAUSE;
2825 decode_cause(&rel.cause,
2826 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2827 }
2828 /* facility */
2829 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2830 rel.fields |= MNCC_F_FACILITY;
2831 decode_facility(&rel.facility,
2832 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2833 }
2834 /* user-user */
2835 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2836 rel.fields |= MNCC_F_USERUSER;
2837 decode_useruser(&rel.useruser,
2838 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2839 }
2840 /* ss-version */
2841 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2842 rel.fields |= MNCC_F_SSVERSION;
2843 decode_ssversion(&rel.ssversion,
2844 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2845 }
2846
Harald Weltedcaf5652009-07-23 18:56:43 +02002847 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002848 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002849 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002850 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002851 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002852 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002853 GSM48_MT_CC_RELEASE_COMPL);
2854 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002855 }
2856
2857 new_cc_state(trans, GSM_CSTATE_NULL);
2858
2859 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002860 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002861
2862 return rc;
2863}
2864
2865static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2866{
2867 struct gsm_mncc *rel = arg;
2868 struct msgb *msg = gsm48_msgb_alloc();
2869 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2870
Harald Welte4bfdfe72009-06-10 23:11:52 +08002871 gh->msg_type = GSM48_MT_CC_RELEASE;
2872
2873 trans->callref = 0;
2874
2875 gsm48_stop_cc_timer(trans);
2876 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2877
2878 /* cause */
2879 if (rel->fields & MNCC_F_CAUSE)
2880 encode_cause(msg, 0, &rel->cause);
2881 /* facility */
2882 if (rel->fields & MNCC_F_FACILITY)
2883 encode_facility(msg, 0, &rel->facility);
2884 /* user-user */
2885 if (rel->fields & MNCC_F_USERUSER)
2886 encode_useruser(msg, 0, &rel->useruser);
2887
Harald Weltedcaf5652009-07-23 18:56:43 +02002888 trans->cc.T308_second = 0;
2889 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002890
Harald Weltedcaf5652009-07-23 18:56:43 +02002891 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002892 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2893
Harald Welte39e2ead2009-07-23 21:13:03 +02002894 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002895}
2896
2897static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2898{
2899 struct gsm48_hdr *gh = msgb_l3(msg);
2900 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2901 struct tlv_parsed tp;
2902 struct gsm_mncc rel;
2903 int rc = 0;
2904
2905 gsm48_stop_cc_timer(trans);
2906
2907 memset(&rel, 0, sizeof(struct gsm_mncc));
2908 rel.callref = trans->callref;
2909 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2910 /* cause */
2911 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2912 rel.fields |= MNCC_F_CAUSE;
2913 decode_cause(&rel.cause,
2914 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2915 }
2916 /* facility */
2917 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2918 rel.fields |= MNCC_F_FACILITY;
2919 decode_facility(&rel.facility,
2920 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2921 }
2922 /* user-user */
2923 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2924 rel.fields |= MNCC_F_USERUSER;
2925 decode_useruser(&rel.useruser,
2926 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2927 }
2928 /* ss-version */
2929 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2930 rel.fields |= MNCC_F_SSVERSION;
2931 decode_ssversion(&rel.ssversion,
2932 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2933 }
2934
2935 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002936 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002937 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002938 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002939 MNCC_REJ_IND, &rel);
2940 break;
2941 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002942 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002943 MNCC_REL_CNF, &rel);
2944 break;
2945 default:
Harald Welte596fed42009-07-23 19:06:52 +02002946 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002947 MNCC_REL_IND, &rel);
2948 }
2949 }
2950
2951 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002952 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002953
2954 return rc;
2955}
2956
2957static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2958{
2959 struct gsm_mncc *rel = arg;
2960 struct msgb *msg = gsm48_msgb_alloc();
2961 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2962
Harald Welte4bfdfe72009-06-10 23:11:52 +08002963 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2964
2965 trans->callref = 0;
2966
2967 gsm48_stop_cc_timer(trans);
2968
2969 /* cause */
2970 if (rel->fields & MNCC_F_CAUSE)
2971 encode_cause(msg, 0, &rel->cause);
2972 /* facility */
2973 if (rel->fields & MNCC_F_FACILITY)
2974 encode_facility(msg, 0, &rel->facility);
2975 /* user-user */
2976 if (rel->fields & MNCC_F_USERUSER)
2977 encode_useruser(msg, 0, &rel->useruser);
2978
Harald Weltedcaf5652009-07-23 18:56:43 +02002979 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002980
Harald Welte39e2ead2009-07-23 21:13:03 +02002981 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002982}
2983
2984static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2985{
2986 struct gsm48_hdr *gh = msgb_l3(msg);
2987 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2988 struct tlv_parsed tp;
2989 struct gsm_mncc fac;
2990
2991 memset(&fac, 0, sizeof(struct gsm_mncc));
2992 fac.callref = trans->callref;
2993 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2994 /* facility */
2995 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2996 fac.fields |= MNCC_F_FACILITY;
2997 decode_facility(&fac.facility,
2998 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2999 }
3000 /* ss-version */
3001 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
3002 fac.fields |= MNCC_F_SSVERSION;
3003 decode_ssversion(&fac.ssversion,
3004 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
3005 }
3006
Harald Welte596fed42009-07-23 19:06:52 +02003007 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003008}
3009
3010static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
3011{
3012 struct gsm_mncc *fac = arg;
3013 struct msgb *msg = gsm48_msgb_alloc();
3014 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3015
Harald Welte4bfdfe72009-06-10 23:11:52 +08003016 gh->msg_type = GSM48_MT_CC_FACILITY;
3017
3018 /* facility */
3019 encode_facility(msg, 1, &fac->facility);
3020
Harald Welte39e2ead2009-07-23 21:13:03 +02003021 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003022}
3023
3024static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
3025{
3026 struct gsm_mncc hold;
3027
3028 memset(&hold, 0, sizeof(struct gsm_mncc));
3029 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003030 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003031}
3032
3033static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
3034{
3035 struct msgb *msg = gsm48_msgb_alloc();
3036 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3037
Harald Welte4bfdfe72009-06-10 23:11:52 +08003038 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
3039
Harald Welte39e2ead2009-07-23 21:13:03 +02003040 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003041}
3042
3043static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
3044{
3045 struct gsm_mncc *hold_rej = arg;
3046 struct msgb *msg = gsm48_msgb_alloc();
3047 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3048
Harald Welte4bfdfe72009-06-10 23:11:52 +08003049 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
3050
3051 /* cause */
3052 if (hold_rej->fields & MNCC_F_CAUSE)
3053 encode_cause(msg, 1, &hold_rej->cause);
3054 else
3055 encode_cause(msg, 1, &default_cause);
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_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
3061{
3062 struct gsm_mncc retrieve;
3063
3064 memset(&retrieve, 0, sizeof(struct gsm_mncc));
3065 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003066 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
3067 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003068}
3069
3070static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
3071{
3072 struct msgb *msg = gsm48_msgb_alloc();
3073 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3074
Harald Welte4bfdfe72009-06-10 23:11:52 +08003075 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3076
Harald Welte39e2ead2009-07-23 21:13:03 +02003077 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003078}
3079
3080static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3081{
3082 struct gsm_mncc *retrieve_rej = arg;
3083 struct msgb *msg = gsm48_msgb_alloc();
3084 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3085
Harald Welte4bfdfe72009-06-10 23:11:52 +08003086 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3087
3088 /* cause */
3089 if (retrieve_rej->fields & MNCC_F_CAUSE)
3090 encode_cause(msg, 1, &retrieve_rej->cause);
3091 else
3092 encode_cause(msg, 1, &default_cause);
3093
Harald Welte39e2ead2009-07-23 21:13:03 +02003094 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003095}
3096
3097static int gsm48_cc_rx_start_dtmf(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 dtmf;
3103
3104 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3105 dtmf.callref = trans->callref;
3106 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3107 /* keypad facility */
3108 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3109 dtmf.fields |= MNCC_F_KEYPAD;
3110 decode_keypad(&dtmf.keypad,
3111 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3112 }
3113
Harald Welte596fed42009-07-23 19:06:52 +02003114 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003115}
3116
3117static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3118{
3119 struct gsm_mncc *dtmf = arg;
3120 struct msgb *msg = gsm48_msgb_alloc();
3121 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3122
Harald Welte4bfdfe72009-06-10 23:11:52 +08003123 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3124
3125 /* keypad */
3126 if (dtmf->fields & MNCC_F_KEYPAD)
3127 encode_keypad(msg, dtmf->keypad);
3128
Harald Welte39e2ead2009-07-23 21:13:03 +02003129 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003130}
3131
3132static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3133{
3134 struct gsm_mncc *dtmf = arg;
3135 struct msgb *msg = gsm48_msgb_alloc();
3136 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3137
Harald Welte4bfdfe72009-06-10 23:11:52 +08003138 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3139
3140 /* cause */
3141 if (dtmf->fields & MNCC_F_CAUSE)
3142 encode_cause(msg, 1, &dtmf->cause);
3143 else
3144 encode_cause(msg, 1, &default_cause);
3145
Harald Welte39e2ead2009-07-23 21:13:03 +02003146 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003147}
3148
3149static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3150{
3151 struct msgb *msg = gsm48_msgb_alloc();
3152 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3153
Harald Welte4bfdfe72009-06-10 23:11:52 +08003154 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3155
Harald Welte39e2ead2009-07-23 21:13:03 +02003156 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003157}
3158
3159static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3160{
3161 struct gsm_mncc dtmf;
3162
3163 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3164 dtmf.callref = trans->callref;
3165
Harald Welte596fed42009-07-23 19:06:52 +02003166 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003167}
3168
3169static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3170{
3171 struct gsm48_hdr *gh = msgb_l3(msg);
3172 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3173 struct tlv_parsed tp;
3174 struct gsm_mncc modify;
3175
3176 memset(&modify, 0, sizeof(struct gsm_mncc));
3177 modify.callref = trans->callref;
3178 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3179 /* bearer capability */
3180 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3181 modify.fields |= MNCC_F_BEARER_CAP;
3182 decode_bearer_cap(&modify.bearer_cap,
3183 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3184 }
3185
3186 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3187
Harald Welte596fed42009-07-23 19:06:52 +02003188 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003189}
3190
3191static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3192{
3193 struct gsm_mncc *modify = arg;
3194 struct msgb *msg = gsm48_msgb_alloc();
3195 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3196
Harald Welte4bfdfe72009-06-10 23:11:52 +08003197 gh->msg_type = GSM48_MT_CC_MODIFY;
3198
3199 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3200
3201 /* bearer capability */
3202 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3203
3204 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3205
Harald Welte39e2ead2009-07-23 21:13:03 +02003206 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003207}
3208
3209static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3210{
3211 struct gsm48_hdr *gh = msgb_l3(msg);
3212 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3213 struct tlv_parsed tp;
3214 struct gsm_mncc modify;
3215
3216 gsm48_stop_cc_timer(trans);
3217
3218 memset(&modify, 0, sizeof(struct gsm_mncc));
3219 modify.callref = trans->callref;
3220 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3221 /* bearer capability */
3222 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3223 modify.fields |= MNCC_F_BEARER_CAP;
3224 decode_bearer_cap(&modify.bearer_cap,
3225 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3226 }
3227
3228 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3229
Harald Welte596fed42009-07-23 19:06:52 +02003230 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003231}
3232
3233static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3234{
3235 struct gsm_mncc *modify = arg;
3236 struct msgb *msg = gsm48_msgb_alloc();
3237 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3238
Harald Welte4bfdfe72009-06-10 23:11:52 +08003239 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3240
3241 /* bearer capability */
3242 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3243
3244 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3245
Harald Welte39e2ead2009-07-23 21:13:03 +02003246 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003247}
3248
3249static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3250{
3251 struct gsm48_hdr *gh = msgb_l3(msg);
3252 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3253 struct tlv_parsed tp;
3254 struct gsm_mncc modify;
3255
3256 gsm48_stop_cc_timer(trans);
3257
3258 memset(&modify, 0, sizeof(struct gsm_mncc));
3259 modify.callref = trans->callref;
3260 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3261 /* bearer capability */
3262 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3263 modify.fields |= GSM48_IE_BEARER_CAP;
3264 decode_bearer_cap(&modify.bearer_cap,
3265 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3266 }
3267 /* cause */
3268 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3269 modify.fields |= MNCC_F_CAUSE;
3270 decode_cause(&modify.cause,
3271 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3272 }
3273
3274 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3275
Harald Welte596fed42009-07-23 19:06:52 +02003276 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003277}
3278
3279static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3280{
3281 struct gsm_mncc *modify = arg;
3282 struct msgb *msg = gsm48_msgb_alloc();
3283 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3284
Harald Welte4bfdfe72009-06-10 23:11:52 +08003285 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3286
3287 /* bearer capability */
3288 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3289 /* cause */
3290 encode_cause(msg, 1, &modify->cause);
3291
3292 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3293
Harald Welte39e2ead2009-07-23 21:13:03 +02003294 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003295}
3296
3297static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3298{
3299 struct gsm_mncc *notify = arg;
3300 struct msgb *msg = gsm48_msgb_alloc();
3301 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3302
Harald Welte4bfdfe72009-06-10 23:11:52 +08003303 gh->msg_type = GSM48_MT_CC_NOTIFY;
3304
3305 /* notify */
3306 encode_notify(msg, notify->notify);
3307
Harald Welte39e2ead2009-07-23 21:13:03 +02003308 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003309}
3310
3311static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3312{
3313 struct gsm48_hdr *gh = msgb_l3(msg);
3314 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3315// struct tlv_parsed tp;
3316 struct gsm_mncc notify;
3317
3318 memset(&notify, 0, sizeof(struct gsm_mncc));
3319 notify.callref = trans->callref;
3320// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3321 if (payload_len >= 1)
3322 decode_notify(&notify.notify, gh->data);
3323
Harald Welte596fed42009-07-23 19:06:52 +02003324 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003325}
3326
3327static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3328{
3329 struct gsm_mncc *user = arg;
3330 struct msgb *msg = gsm48_msgb_alloc();
3331 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3332
Harald Welte4bfdfe72009-06-10 23:11:52 +08003333 gh->msg_type = GSM48_MT_CC_USER_INFO;
3334
3335 /* user-user */
3336 if (user->fields & MNCC_F_USERUSER)
3337 encode_useruser(msg, 1, &user->useruser);
3338 /* more data */
3339 if (user->more)
3340 encode_more(msg);
3341
Harald Welte39e2ead2009-07-23 21:13:03 +02003342 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003343}
3344
3345static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3346{
3347 struct gsm48_hdr *gh = msgb_l3(msg);
3348 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3349 struct tlv_parsed tp;
3350 struct gsm_mncc user;
3351
3352 memset(&user, 0, sizeof(struct gsm_mncc));
3353 user.callref = trans->callref;
3354 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3355 /* user-user */
3356 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3357 user.fields |= MNCC_F_USERUSER;
3358 decode_useruser(&user.useruser,
3359 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3360 }
3361 /* more data */
3362 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3363 user.more = 1;
3364
Harald Welte596fed42009-07-23 19:06:52 +02003365 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003366}
3367
3368static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3369{
3370 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003371 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003372
Harald Welte13cac662009-07-29 12:10:35 +02003373 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3374 if (rc < 0)
3375 return rc;
3376
3377 /* FIXME: we not only need to do this after mode modify, but
3378 * also after channel activation */
3379 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3380 mode->lchan_mode != GSM48_CMODE_SIGN)
3381 rc = rsl_ipacc_bind(trans->lchan);
3382
3383 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003384}
3385
3386static struct downstate {
3387 u_int32_t states;
3388 int type;
3389 int (*rout) (struct gsm_trans *trans, void *arg);
3390} downstatelist[] = {
3391 /* mobile originating call establishment */
3392 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3393 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3394 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3395 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3396 {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 */
3397 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3398 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3399 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3400 /* mobile terminating call establishment */
3401 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3402 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3403 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3404 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3405 /* signalling during call */
3406 {SBIT(GSM_CSTATE_ACTIVE),
3407 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3408 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3409 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3410 {ALL_STATES,
3411 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3412 {ALL_STATES,
3413 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3414 {ALL_STATES,
3415 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3416 {SBIT(GSM_CSTATE_ACTIVE),
3417 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3418 {SBIT(GSM_CSTATE_ACTIVE),
3419 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3420 {SBIT(GSM_CSTATE_ACTIVE),
3421 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3422 {SBIT(GSM_CSTATE_ACTIVE),
3423 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3424 {SBIT(GSM_CSTATE_ACTIVE),
3425 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3426 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3427 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3428 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3429 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3430 {SBIT(GSM_CSTATE_ACTIVE),
3431 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3432 /* clearing */
3433 {SBIT(GSM_CSTATE_INITIATED),
3434 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3435 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3436 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3437 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3438 MNCC_REL_REQ, gsm48_cc_tx_release},
3439 /* special */
3440 {ALL_STATES,
3441 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3442};
3443
3444#define DOWNSLLEN \
3445 (sizeof(downstatelist) / sizeof(struct downstate))
3446
3447
3448int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3449{
Harald Welte1a6f7982009-08-09 18:52:33 +02003450 int i, rc = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003451 struct gsm_trans *trans = NULL, *transt;
3452 struct gsm_subscriber *subscr;
Harald Welte1a6f7982009-08-09 18:52:33 +02003453 struct gsm_lchan *lchan = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003454 struct gsm_bts *bts = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003455 struct gsm_mncc *data = arg, rel;
3456
3457 /* handle special messages */
3458 switch(msg_type) {
3459 case MNCC_BRIDGE:
3460 return tch_bridge(net, arg);
3461 case MNCC_FRAME_DROP:
3462 return tch_recv(net, arg, 0);
3463 case MNCC_FRAME_RECV:
3464 return tch_recv(net, arg, 1);
3465 case GSM_TRAU_FRAME:
3466 return tch_frame(net, arg);
3467 }
3468
3469 memset(&rel, 0, sizeof(struct gsm_mncc));
3470 rel.callref = data->callref;
3471
3472 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003473 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003474
3475 /* Callref unknown */
3476 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003477 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003478 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3479 "Received '%s' from MNCC with "
3480 "unknown callref %d\n", data->called.number,
3481 get_mncc_name(msg_type), data->callref);
3482 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003483 return mncc_release_ind(net, NULL, data->callref,
3484 GSM48_CAUSE_LOC_PRN_S_LU,
3485 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003486 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003487 if (!data->called.number[0] && !data->imsi[0]) {
3488 DEBUGP(DCC, "(bts - trx - ts - ti) "
3489 "Received '%s' from MNCC with "
3490 "no number or IMSI\n", get_mncc_name(msg_type));
3491 /* Invalid number */
3492 return mncc_release_ind(net, NULL, data->callref,
3493 GSM48_CAUSE_LOC_PRN_S_LU,
3494 GSM48_CC_CAUSE_INV_NR_FORMAT);
3495 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003496 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003497 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003498 subscr = subscr_get_by_extension(net,
3499 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003500 else
Harald Welte9176bd42009-07-23 18:46:00 +02003501 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003502 /* If subscriber is not found */
3503 if (!subscr) {
3504 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3505 "Received '%s' from MNCC with "
3506 "unknown subscriber %s\n", data->called.number,
3507 get_mncc_name(msg_type), data->called.number);
3508 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003509 return mncc_release_ind(net, NULL, data->callref,
3510 GSM48_CAUSE_LOC_PRN_S_LU,
3511 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003512 }
3513 /* If subscriber is not "attached" */
3514 if (!subscr->lac) {
3515 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3516 "Received '%s' from MNCC with "
3517 "detached subscriber %s\n", data->called.number,
3518 get_mncc_name(msg_type), data->called.number);
3519 subscr_put(subscr);
3520 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003521 return mncc_release_ind(net, NULL, data->callref,
3522 GSM48_CAUSE_LOC_PRN_S_LU,
3523 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003524 }
3525 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003526 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3527 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003528 DEBUGP(DCC, "No memory for trans.\n");
3529 subscr_put(subscr);
3530 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003531 mncc_release_ind(net, NULL, data->callref,
3532 GSM48_CAUSE_LOC_PRN_S_LU,
3533 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003534 return -ENOMEM;
3535 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003536 /* Find lchan */
Harald Welte1a6f7982009-08-09 18:52:33 +02003537 lchan = lchan_for_subscr(subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003538 /* If subscriber has no lchan */
3539 if (!lchan) {
3540 /* find transaction with this subscriber already paging */
3541 llist_for_each_entry(transt, &net->trans_list, entry) {
3542 /* Transaction of our lchan? */
3543 if (transt == trans ||
3544 transt->subscr != subscr)
3545 continue;
3546 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3547 "Received '%s' from MNCC with "
3548 "unallocated channel, paging already "
3549 "started.\n", bts->nr,
3550 data->called.number,
3551 get_mncc_name(msg_type));
3552 return 0;
3553 }
3554 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003555 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003556 /* Trigger paging */
3557 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3558 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003559 return 0;
3560 }
3561 /* Assign lchan */
3562 trans->lchan = lchan;
3563 use_lchan(lchan);
3564 }
3565 lchan = trans->lchan;
3566
3567 /* if paging did not respond yet */
3568 if (!lchan) {
3569 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3570 "Received '%s' from MNCC in paging state\n",
3571 (trans->subscr)?(trans->subscr->extension):"-",
3572 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003573 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3574 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003575 if (msg_type == MNCC_REL_REQ)
3576 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3577 else
3578 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3579 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003580 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003581 return rc;
3582 }
3583
3584 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3585 "Received '%s' from MNCC in state %d (%s)\n",
3586 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3587 trans->transaction_id,
3588 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003589 get_mncc_name(msg_type), trans->cc.state,
3590 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003591
3592 /* Find function for current state and message */
3593 for (i = 0; i < DOWNSLLEN; i++)
3594 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003595 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003596 break;
3597 if (i == DOWNSLLEN) {
3598 DEBUGP(DCC, "Message unhandled at this state.\n");
3599 return 0;
3600 }
3601
3602 rc = downstatelist[i].rout(trans, arg);
3603
3604 return rc;
3605}
3606
3607
3608static struct datastate {
3609 u_int32_t states;
3610 int type;
3611 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3612} datastatelist[] = {
3613 /* mobile originating call establishment */
3614 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3615 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3616 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3617 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3618 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3619 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3620 /* mobile terminating call establishment */
3621 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3622 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3623 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3624 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3625 {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 */
3626 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3627 /* signalling during call */
3628 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3629 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3630 {SBIT(GSM_CSTATE_ACTIVE),
3631 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3632 {ALL_STATES,
3633 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3634 {ALL_STATES,
3635 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3636 {ALL_STATES,
3637 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3638 {SBIT(GSM_CSTATE_ACTIVE),
3639 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3640 {SBIT(GSM_CSTATE_ACTIVE),
3641 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3642 {SBIT(GSM_CSTATE_ACTIVE),
3643 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3644 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3645 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3646 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3647 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3648 {SBIT(GSM_CSTATE_ACTIVE),
3649 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3650 /* clearing */
3651 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3652 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3653 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3654 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3655 {ALL_STATES, /* 5.4.3.4 */
3656 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3657};
3658
3659#define DATASLLEN \
3660 (sizeof(datastatelist) / sizeof(struct datastate))
3661
Harald Welte4bc90a12008-12-27 16:32:52 +00003662static int gsm0408_rcv_cc(struct msgb *msg)
3663{
3664 struct gsm48_hdr *gh = msgb_l3(msg);
3665 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003666 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003667 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003668 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003669 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003670
Harald Welte4bfdfe72009-06-10 23:11:52 +08003671 if (msg_type & 0x80) {
3672 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3673 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003674 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003675
3676 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003677 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003678
Harald Welte6f5aee02009-07-23 21:21:14 +02003679 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003680 "Received '%s' from MS in state %d (%s)\n",
3681 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3682 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003683 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3684 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003685
3686 /* Create transaction */
3687 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003688 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003689 "creating new trans.\n", transaction_id);
3690 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003691 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3692 transaction_id, new_callref++);
3693 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003694 DEBUGP(DCC, "No memory for trans.\n");
3695 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003696 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003697 GSM48_MT_CC_RELEASE_COMPL);
3698 return -ENOMEM;
3699 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003700 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003701 trans->lchan = lchan;
3702 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003703 }
3704
3705 /* find function for current state and message */
3706 for (i = 0; i < DATASLLEN; i++)
3707 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003708 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003709 break;
3710 if (i == DATASLLEN) {
3711 DEBUGP(DCC, "Message unhandled at this state.\n");
3712 return 0;
3713 }
3714
3715 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003716
3717 return rc;
3718}
3719
Harald Welte52b1f982008-12-23 20:25:15 +00003720/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3721int gsm0408_rcvmsg(struct msgb *msg)
3722{
3723 struct gsm48_hdr *gh = msgb_l3(msg);
3724 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003725 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003726
3727 switch (pdisc) {
3728 case GSM48_PDISC_CC:
3729 rc = gsm0408_rcv_cc(msg);
3730 break;
3731 case GSM48_PDISC_MM:
3732 rc = gsm0408_rcv_mm(msg);
3733 break;
3734 case GSM48_PDISC_RR:
3735 rc = gsm0408_rcv_rr(msg);
3736 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003737 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003738 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003739 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003740 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003741 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003742 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3743 pdisc);
3744 break;
3745 default:
3746 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3747 pdisc);
3748 break;
3749 }
3750
3751 return rc;
3752}
Harald Welte8470bf22008-12-25 23:28:35 +00003753
Harald Welte8470bf22008-12-25 23:28:35 +00003754/* Section 9.1.8 / Table 9.9 */
3755struct chreq {
3756 u_int8_t val;
3757 u_int8_t mask;
3758 enum chreq_type type;
3759};
3760
3761/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3762static const struct chreq chreq_type_neci1[] = {
3763 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3764 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3765 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3766 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3767 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3768 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3769 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3770 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3771 { 0x10, 0xf0, CHREQ_T_SDCCH },
3772 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3773 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3774 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3775};
3776
3777/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3778static const struct chreq chreq_type_neci0[] = {
3779 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3780 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3781 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3782 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3783 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3784 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3785 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3786 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3787};
3788
3789static const enum gsm_chan_t ctype_by_chreq[] = {
3790 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3791 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3792 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3793 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3794 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3795 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3796 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3797 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3798 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3799 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3800 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3801 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3802};
3803
Harald Weltee14a57c2008-12-29 04:08:28 +00003804static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3805 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3806 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3807 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3808 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3809 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3810 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3811 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3812 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3813 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3814 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3815 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3816 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3817};
3818
Harald Welte8470bf22008-12-25 23:28:35 +00003819enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3820{
3821 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003822 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Welte8470bf22008-12-25 23:28:35 +00003823
Harald Weltee58ca7c2009-08-10 02:14:46 +02003824 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3825 const struct chreq *chr = &chreq_type_neci0[i];
Harald Welte8470bf22008-12-25 23:28:35 +00003826 if ((ra & chr->mask) == chr->val)
3827 return ctype_by_chreq[chr->type];
3828 }
3829 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3830 return GSM_LCHAN_SDCCH;
3831}
Harald Weltee14a57c2008-12-29 04:08:28 +00003832
3833enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3834{
3835 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003836 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Weltee14a57c2008-12-29 04:08:28 +00003837
Harald Weltee58ca7c2009-08-10 02:14:46 +02003838 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3839 const struct chreq *chr = &chreq_type_neci0[i];
Harald Weltee14a57c2008-12-29 04:08:28 +00003840 if ((ra & chr->mask) == chr->val)
3841 return reason_by_chreq[chr->type];
3842 }
3843 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3844 return GSM_CHREQ_REASON_OTHER;
3845}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003846
3847/* dequeue messages to layer 4 */
3848int bsc_upqueue(struct gsm_network *net)
3849{
3850 struct gsm_mncc *mncc;
3851 struct msgb *msg;
3852 int work = 0;
3853
3854 if (net)
3855 while ((msg = msgb_dequeue(&net->upqueue))) {
3856 mncc = (struct gsm_mncc *)msg->data;
3857 if (net->mncc_recv)
3858 net->mncc_recv(net, mncc->msg_type, mncc);
3859 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003860 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003861 }
3862
3863 return work;
3864}
Harald Weltedcaf5652009-07-23 18:56:43 +02003865
Harald Welte805f6442009-07-28 18:25:29 +02003866/*
3867 * This will be ran by the linker when loading the DSO. We use it to
3868 * do system initialization, e.g. registration of signal handlers.
3869 */
3870static __attribute__((constructor)) void on_dso_load_0408(void)
3871{
3872 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3873 "loc_updating_oper");
3874 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3875 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3876}