blob: 03fe01058a7e9363db4500cf6fed852087ca1144 [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>
Daniel Willmanneea93372009-08-13 03:42:07 +020038#include <openbsc/gsm_utils.h>
Harald Welte8470bf22008-12-25 23:28:35 +000039#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000040#include <openbsc/gsm_04_11.h>
Harald Welte8470bf22008-12-25 23:28:35 +000041#include <openbsc/gsm_04_08.h>
42#include <openbsc/abis_rsl.h>
Holger Freytherca362a62009-01-04 21:05:01 +000043#include <openbsc/chan_alloc.h>
Harald Welte0b4c34e2009-02-09 17:54:43 +000044#include <openbsc/paging.h>
Holger Freyther053e09d2009-02-14 22:51:06 +000045#include <openbsc/signal.h>
Harald Welte45b407a2009-05-23 15:51:12 +000046#include <openbsc/trau_frame.h>
Harald Welte11fa29c2009-02-19 17:24:39 +000047#include <openbsc/trau_mux.h>
Harald Welte805f6442009-07-28 18:25:29 +020048#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020049#include <openbsc/talloc.h>
Harald Weltedcaf5652009-07-23 18:56:43 +020050#include <openbsc/transaction.h>
Harald Welte52b1f982008-12-23 20:25:15 +000051
Harald Welte8470bf22008-12-25 23:28:35 +000052#define GSM48_ALLOC_SIZE 1024
53#define GSM48_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000054
Harald Welte0c389302009-06-10 12:08:54 +080055#define GSM_MAX_FACILITY 128
56#define GSM_MAX_SSVERSION 128
57#define GSM_MAX_USERUSER 128
58
Harald Welte2cf161b2009-06-20 22:36:41 +020059static void *tall_locop_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020060
Harald Welte805f6442009-07-28 18:25:29 +020061/* should ip.access BTS use direct RTP streams between each other (1),
62 * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
63int ipacc_rtp_direct = 1;
64
Harald Welte09e38af2009-02-16 22:52:23 +000065static const struct tlv_definition rsl_att_tlvdef = {
66 .def = {
67 [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
68 [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
69 [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
70 [GSM48_IE_UTC] = { TLV_TYPE_TV },
71 [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
72 [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
73
74 [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
75 [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
76 [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
77 [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
78 [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
79 [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
80 [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
Harald Welte0c389302009-06-10 12:08:54 +080081 [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
Harald Welte09e38af2009-02-16 22:52:23 +000082 [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
83 [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
Harald Welte0c389302009-06-10 12:08:54 +080084 [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
85 [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
Harald Welte09e38af2009-02-16 22:52:23 +000086 [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
87 [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
88 [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
89 [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
90 [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
91 [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
92 [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
93 [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
94 [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
95 [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
96 [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
97 [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
98 [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
99 [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
Harald Welte0c389302009-06-10 12:08:54 +0800100 [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
101 [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
Harald Welte09e38af2009-02-16 22:52:23 +0000102 /* FIXME: more elements */
103 },
104};
Harald Weltecf5b3592009-05-01 18:28:42 +0000105
106static const char *rr_cause_names[] = {
107 [GSM48_RR_CAUSE_NORMAL] = "Normal event",
108 [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
109 [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
110 [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
111 [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
112 [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
113 [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
114 [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
115 [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
116 [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
117 [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
118 [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
119 [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
120 [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
121 [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
122 [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
123 [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
124};
125
Harald Welte4bfdfe72009-06-10 23:11:52 +0800126static const char *cc_state_names[] = {
127 "NULL",
128 "INITIATED",
129 "illegal state 2",
130 "MO_CALL_PROC",
131 "CALL_DELIVERED",
132 "illegal state 5",
133 "CALL_PRESENT",
134 "CALL_RECEIVED",
135 "CONNECT_REQUEST",
136 "MO_TERM_CALL_CONF",
137 "ACTIVE",
138 "DISCONNECT_REQ",
139 "DISCONNECT_IND",
140 "illegal state 13",
141 "illegal state 14",
142 "illegal state 15",
143 "illegal state 16",
144 "illegal state 17",
145 "illegal state 18",
146 "RELEASE_REQ",
147 "illegal state 20",
148 "illegal state 21",
149 "illegal state 22",
150 "illegal state 23",
151 "illegal state 24",
152 "illegal state 25",
153 "MO_ORIG_MODIFY",
154 "MO_TERM_MODIFY",
155 "CONNECT_IND",
156 "illegal state 29",
157 "illegal state 30",
158 "illegal state 31",
159};
160
161static const char *cc_msg_names[] = {
162 "unknown 0x00",
163 "ALERTING",
164 "CALL_PROC",
165 "PROGRESS",
166 "ESTAB",
167 "SETUP",
168 "ESTAB_CONF",
169 "CONNECT",
170 "CALL_CONF",
171 "START_CC",
172 "unknown 0x0a",
173 "RECALL",
174 "unknown 0x0c",
175 "unknown 0x0d",
176 "EMERG_SETUP",
177 "CONNECT_ACK",
178 "USER_INFO",
179 "unknown 0x11",
180 "unknown 0x12",
181 "MODIFY_REJECT",
182 "unknown 0x14",
183 "unknown 0x15",
184 "unknown 0x16",
185 "MODIFY",
186 "HOLD",
187 "HOLD_ACK",
188 "HOLD_REJ",
189 "unknown 0x1b",
190 "RETR",
191 "RETR_ACK",
192 "RETR_REJ",
193 "MODIFY_COMPL",
194 "unknown 0x20",
195 "unknown 0x21",
196 "unknown 0x22",
197 "unknown 0x23",
198 "unknown 0x24",
199 "DISCONNECT",
200 "unknown 0x26",
201 "unknown 0x27",
202 "unknown 0x28",
203 "unknown 0x29",
204 "RELEASE_COMPL",
205 "unknown 0x2b",
206 "unknown 0x2c",
207 "RELEASE",
208 "unknown 0x2e",
209 "unknown 0x2f",
210 "unknown 0x30",
211 "STOP_DTMF",
212 "STOP_DTMF_ACK",
213 "unknown 0x33",
214 "STATUS_ENQ",
215 "START_DTMF",
216 "START_DTMF_ACK",
217 "START_DTMF_REJ",
218 "unknown 0x38",
219 "CONG_CTRL",
220 "FACILITY",
221 "unknown 0x3b",
222 "STATUS",
223 "unknown 0x3c",
224 "NOTIFY",
225 "unknown 0x3f",
226};
227
Harald Weltecf5b3592009-05-01 18:28:42 +0000228static char strbuf[64];
229
230static const char *rr_cause_name(u_int8_t cause)
231{
232 if (cause < ARRAY_SIZE(rr_cause_names) &&
233 rr_cause_names[cause])
234 return rr_cause_names[cause];
235
236 snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
237 return strbuf;
238}
239
Harald Weltef7c43522009-06-09 20:24:21 +0000240static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
241 int len)
242{
243 memset(rep, 0, sizeof(*rep));
244
245 if (data[0] & 0x80)
246 rep->flags |= MEAS_REP_F_BA1;
247 if (data[0] & 0x40)
248 rep->flags |= MEAS_REP_F_DTX;
Harald Welte5a691b52009-07-05 04:05:44 +0200249 if ((data[1] & 0x40) == 0x00)
Harald Weltef7c43522009-06-09 20:24:21 +0000250 rep->flags |= MEAS_REP_F_VALID;
251
252 rep->rxlev_full = data[0] & 0x3f;
253 rep->rxlev_sub = data[1] & 0x3f;
254 rep->rxqual_full = (data[3] >> 4) & 0x7;
255 rep->rxqual_sub = (data[3] >> 1) & 0x7;
256 rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2);
257 if (rep->num_cell < 1)
258 return;
259
260 /* an encoding nightmare in perfection */
261
262 rep->cell[0].rxlev = data[4] & 0x3f;
263 rep->cell[0].bcch_freq = data[5] >> 2;
264 rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5);
265 if (rep->num_cell < 2)
266 return;
267
268 rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7);
269 rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f;
270 rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4);
271 if (rep->num_cell < 3)
272 return;
273
274 rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6);
275 rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f;
276 rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3);
277 if (rep->num_cell < 4)
278 return;
279
280 rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5);
281 rep->cell[3].bcch_freq = data[11] & 0x1f;
282 rep->cell[3].bsic = data[12] >> 2;
283 if (rep->num_cell < 5)
284 return;
285
286 rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4);
287 rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7);
288 rep->cell[4].bsic = (data[14] >> 1) & 0x3f;
289 if (rep->num_cell < 6)
290 return;
291
292 rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3);
293 rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6);
294 rep->cell[5].bsic = data[16] & 0x3f;
295}
296
Holger Freytherd51524f2009-06-09 08:27:07 +0000297int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
Harald Welte65e74cc2008-12-29 01:55:35 +0000298static int gsm48_tx_simple(struct gsm_lchan *lchan,
299 u_int8_t pdisc, u_int8_t msg_type);
Holger Freytherb7193e42008-12-29 17:44:08 +0000300static void schedule_reject(struct gsm_lchan *lchan);
Harald Welte65e74cc2008-12-29 01:55:35 +0000301
Harald Welte52b1f982008-12-23 20:25:15 +0000302struct gsm_lai {
303 u_int16_t mcc;
304 u_int16_t mnc;
305 u_int16_t lac;
306};
307
Holger Freythere97f7fb2008-12-31 18:52:11 +0000308static int reject_cause = 0;
309void gsm0408_set_reject_cause(int cause)
310{
311 reject_cause = cause;
312}
313
Harald Welte4bfdfe72009-06-10 23:11:52 +0800314static u_int32_t new_callref = 0x80000001;
315
Holger Freyther73487a22008-12-31 18:53:57 +0000316static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
317 struct gsm_subscriber *subscriber)
Holger Freyther89824fc2008-12-30 16:18:18 +0000318{
319 if (!subscriber)
320 return 0;
321
Holger Freyther73487a22008-12-31 18:53:57 +0000322 /*
323 * Do not send accept yet as more information should arrive. Some
324 * phones will not send us the information and we will have to check
325 * what we want to do with that.
326 */
327 if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
328 return 0;
329
Jan Luebbe06513f22009-08-12 12:48:00 +0200330 switch (subscriber->net->auth_policy) {
331 case GSM_AUTH_POLICY_CLOSED:
332 return subscriber->authorized;
Harald Welte (local)aa9dc192009-08-13 13:49:51 +0200333 case GSM_AUTH_POLICY_TOKEN:
334 return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
Jan Luebbe06513f22009-08-12 12:48:00 +0200335 case GSM_AUTH_POLICY_ACCEPT_ALL:
Holger Freyther89824fc2008-12-30 16:18:18 +0000336 return 1;
Jan Luebbe06513f22009-08-12 12:48:00 +0200337 default:
338 return 0;
339 }
Holger Freyther89824fc2008-12-30 16:18:18 +0000340}
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);
Harald Welte (local)aa9dc192009-08-13 13:49:51 +02001157 if (!lchan->subscr)
1158 lchan->subscr = db_create_subscriber(net, mi_string);
Jan Luebbeb0dfc312009-08-12 10:12:52 +02001159 }
Holger Freyther73487a22008-12-31 18:53:57 +00001160 if (lchan->loc_operation)
1161 lchan->loc_operation->waiting_for_imsi = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001162 break;
1163 case GSM_MI_TYPE_IMEI:
Harald Welte255539c2008-12-28 02:26:27 +00001164 case GSM_MI_TYPE_IMEISV:
Harald Welte75a983f2008-12-27 21:34:06 +00001165 /* update subscribe <-> IMEI mapping */
1166 if (lchan->subscr)
1167 db_subscriber_assoc_imei(lchan->subscr, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001168 if (lchan->loc_operation)
1169 lchan->loc_operation->waiting_for_imei = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001170 break;
1171 }
Holger Freyther73487a22008-12-31 18:53:57 +00001172
1173 /* Check if we can let the mobile station enter */
Holger Freytherd51524f2009-06-09 08:27:07 +00001174 return gsm0408_authorize(lchan, msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001175}
1176
Harald Welte255539c2008-12-28 02:26:27 +00001177
1178static void loc_upd_rej_cb(void *data)
1179{
1180 struct gsm_lchan *lchan = data;
1181
Holger Freyther73487a22008-12-31 18:53:57 +00001182 release_loc_updating_req(lchan);
Holger Freythere97f7fb2008-12-31 18:52:11 +00001183 gsm0408_loc_upd_rej(lchan, reject_cause);
Holger Freyther67b4b9a2009-01-01 03:46:11 +00001184 lchan_auto_release(lchan);
Harald Welte255539c2008-12-28 02:26:27 +00001185}
1186
Holger Freytherb7193e42008-12-29 17:44:08 +00001187static void schedule_reject(struct gsm_lchan *lchan)
1188{
Holger Freyther73487a22008-12-31 18:53:57 +00001189 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1190 lchan->loc_operation->updating_timer.data = lchan;
Harald Welteff117a82009-05-23 05:22:08 +00001191 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
Holger Freytherb7193e42008-12-29 17:44:08 +00001192}
1193
Harald Welte2a139372009-02-22 21:14:55 +00001194static const char *lupd_name(u_int8_t type)
1195{
1196 switch (type) {
1197 case GSM48_LUPD_NORMAL:
1198 return "NORMAL";
1199 case GSM48_LUPD_PERIODIC:
1200 return "PEROIDOC";
1201 case GSM48_LUPD_IMSI_ATT:
1202 return "IMSI ATTACH";
1203 default:
1204 return "UNKNOWN";
1205 }
1206}
1207
Harald Welte231ad4f2008-12-27 11:15:38 +00001208#define MI_SIZE 32
Harald Weltebf5e8df2009-02-03 12:59:45 +00001209/* Chapter 9.2.15: Receive Location Updating Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001210static int mm_rx_loc_upd_req(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001211{
Harald Welte8470bf22008-12-25 23:28:35 +00001212 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001213 struct gsm48_loc_upd_req *lu;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001214 struct gsm_subscriber *subscr = NULL;
Harald Welte255539c2008-12-28 02:26:27 +00001215 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001216 struct gsm_bts *bts = lchan->ts->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +00001217 u_int8_t mi_type;
Harald Welte231ad4f2008-12-27 11:15:38 +00001218 char mi_string[MI_SIZE];
1219 int rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001220
Harald Welte8470bf22008-12-25 23:28:35 +00001221 lu = (struct gsm48_loc_upd_req *) gh->data;
1222
1223 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
Harald Welte52b1f982008-12-23 20:25:15 +00001224
Harald Weltefc977a82008-12-27 10:19:37 +00001225 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1226
Harald Weltea0368542009-06-27 02:58:43 +02001227 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte2a139372009-02-22 21:14:55 +00001228 lupd_name(lu->type));
Holger Freyther73487a22008-12-31 18:53:57 +00001229
Holger Freythereaf04692009-06-06 13:54:44 +00001230 /*
1231 * Pseudo Spoof detection: Just drop a second/concurrent
1232 * location updating request.
1233 */
1234 if (lchan->loc_operation) {
Harald Weltea0368542009-06-27 02:58:43 +02001235 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Holger Freythereaf04692009-06-06 13:54:44 +00001236 lchan->loc_operation);
1237 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1238 return 0;
1239 }
1240
Holger Freyther73487a22008-12-31 18:53:57 +00001241 allocate_loc_updating_req(lchan);
1242
Harald Welte52b1f982008-12-23 20:25:15 +00001243 switch (mi_type) {
1244 case GSM_MI_TYPE_IMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001245 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001246 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001247 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001248 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001249
Jan Luebbe370b41d2009-08-12 10:19:34 +02001250 /* look up subscriber based on IMSI, create if not found */
1251 subscr = subscr_get_by_imsi(bts->network, mi_string);
1252 if (!subscr) {
1253 subscr = db_create_subscriber(bts->network, mi_string);
1254 }
Harald Welte4b634542008-12-27 01:55:51 +00001255 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001256 case GSM_MI_TYPE_TMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001257 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001258 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001259 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001260 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001261
Harald Welte52b1f982008-12-23 20:25:15 +00001262 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welte9176bd42009-07-23 18:46:00 +02001263 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte52b1f982008-12-23 20:25:15 +00001264 if (!subscr) {
Harald Welte231ad4f2008-12-27 11:15:38 +00001265 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte255539c2008-12-28 02:26:27 +00001266 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
Holger Freyther73487a22008-12-31 18:53:57 +00001267 lchan->loc_operation->waiting_for_imsi = 1;
Harald Welte52b1f982008-12-23 20:25:15 +00001268 }
1269 break;
1270 case GSM_MI_TYPE_IMEI:
1271 case GSM_MI_TYPE_IMEISV:
1272 /* no sim card... FIXME: what to do ? */
Harald Weltea0368542009-06-27 02:58:43 +02001273 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001274 break;
1275 default:
Harald Weltea0368542009-06-27 02:58:43 +02001276 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001277 break;
1278 }
1279
Harald Welte24516ea2009-07-04 10:18:00 +02001280 /* schedule the reject timer */
1281 schedule_reject(lchan);
1282
Harald Welte4bfdfe72009-06-10 23:11:52 +08001283 if (!subscr) {
Harald Weltea0368542009-06-27 02:58:43 +02001284 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001285 /* FIXME: request id? close channel? */
1286 return -EINVAL;
1287 }
1288
Harald Welte255539c2008-12-28 02:26:27 +00001289 lchan->subscr = subscr;
1290
Harald Welte24516ea2009-07-04 10:18:00 +02001291 /* check if we can let the subscriber into our network immediately
1292 * or if we need to wait for identity responses. */
Holger Freytherd51524f2009-06-09 08:27:07 +00001293 return gsm0408_authorize(lchan, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001294}
1295
Harald Welte13cac662009-07-29 12:10:35 +02001296/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Harald Welte7584aea2009-02-11 11:44:12 +00001297int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1298{
1299 struct msgb *msg = gsm48_msgb_alloc();
1300 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1301 struct gsm48_chan_mode_modify *cmm =
1302 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
Harald Welte4a543e82009-02-28 13:17:55 +00001303 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
Harald Welte7584aea2009-02-11 11:44:12 +00001304
Harald Welte4a543e82009-02-28 13:17:55 +00001305 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
Harald Welte7ccf7782009-02-17 01:43:01 +00001306
Harald Welte45b407a2009-05-23 15:51:12 +00001307 lchan->tch_mode = mode;
Harald Welte7584aea2009-02-11 11:44:12 +00001308 msg->lchan = lchan;
1309 gh->proto_discr = GSM48_PDISC_RR;
1310 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1311
1312 /* fill the channel information element, this code
1313 * should probably be shared with rsl_rx_chan_rqd() */
1314 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte02b0e092009-02-28 13:11:07 +00001315 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
Harald Welte7584aea2009-02-11 11:44:12 +00001316 cmm->chan_desc.h0.h = 0;
1317 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1318 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1319 cmm->mode = mode;
1320
Harald Welte39e2ead2009-07-23 21:13:03 +02001321 return gsm48_sendmsg(msg, NULL);
Harald Welte7584aea2009-02-11 11:44:12 +00001322}
1323
Harald Welte4bfdfe72009-06-10 23:11:52 +08001324#if 0
1325static u_int8_t to_bcd8(u_int8_t val)
1326{
1327 return ((val / 10) << 4) | (val % 10);
1328}
1329#endif
1330
Harald Weltedb253af2008-12-30 17:56:55 +00001331/* Section 9.2.15a */
1332int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1333{
1334 struct msgb *msg = gsm48_msgb_alloc();
1335 struct gsm48_hdr *gh;
1336 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Weltedb253af2008-12-30 17:56:55 +00001337 u_int8_t *ptr8;
1338 u_int16_t *ptr16;
Daniel Willmanneea93372009-08-13 03:42:07 +02001339 int name_len, name_pad;
Harald Weltedb253af2008-12-30 17:56:55 +00001340 int i;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001341#if 0
1342 time_t cur_t;
1343 struct tm* cur_time;
1344 int tz15min;
1345#endif
Harald Weltedb253af2008-12-30 17:56:55 +00001346
1347 msg->lchan = lchan;
1348
1349 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1350 gh->proto_discr = GSM48_PDISC_MM;
1351 gh->msg_type = GSM48_MT_MM_INFO;
1352
1353 if (net->name_long) {
Daniel Willmanneea93372009-08-13 03:42:07 +02001354#if 0
Harald Weltedb253af2008-12-30 17:56:55 +00001355 name_len = strlen(net->name_long);
1356 /* 10.5.3.5a */
1357 ptr8 = msgb_put(msg, 3);
1358 ptr8[0] = GSM48_IE_NAME_LONG;
1359 ptr8[1] = name_len*2 +1;
1360 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1361
1362 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1363 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001364 ptr16[i] = htons(net->name_long[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001365
1366 /* FIXME: Use Cell Broadcast, not UCS-2, since
1367 * UCS-2 is only supported by later revisions of the spec */
Daniel Willmanneea93372009-08-13 03:42:07 +02001368#endif
1369 name_len = (strlen(net->name_long)*7)/8;
1370 name_pad = (8 - strlen(net->name_long)*7)%8;
1371 if (name_pad > 0)
1372 name_len++;
1373 /* 10.5.3.5a */
1374 ptr8 = msgb_put(msg, 3);
1375 ptr8[0] = GSM48_IE_NAME_LONG;
1376 ptr8[1] = name_len +1;
1377 ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */
1378
1379 ptr8 = msgb_put(msg, name_len);
1380 gsm_7bit_encode(ptr8, net->name_long);
1381
Harald Weltedb253af2008-12-30 17:56:55 +00001382 }
1383
1384 if (net->name_short) {
Daniel Willmanneea93372009-08-13 03:42:07 +02001385#if 0
Harald Weltedb253af2008-12-30 17:56:55 +00001386 name_len = strlen(net->name_short);
1387 /* 10.5.3.5a */
1388 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Welte7543eb72009-07-19 17:51:36 +02001389 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Weltedb253af2008-12-30 17:56:55 +00001390 ptr8[1] = name_len*2 + 1;
1391 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1392
Harald Weltee872cb12009-01-01 00:33:37 +00001393 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
Harald Weltedb253af2008-12-30 17:56:55 +00001394 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001395 ptr16[i] = htons(net->name_short[i]);
Daniel Willmanneea93372009-08-13 03:42:07 +02001396#endif
1397 name_len = (strlen(net->name_short)*7)/8;
1398 name_pad = (8 - strlen(net->name_short)*7)%8;
1399 if (name_pad > 0)
1400 name_len++;
1401 /* 10.5.3.5a */
1402 ptr8 = (u_int8_t *) msgb_put(msg, 3);
1403 ptr8[0] = GSM48_IE_NAME_SHORT;
1404 ptr8[1] = name_len +1;
1405 ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */
1406
1407 ptr8 = msgb_put(msg, name_len);
1408 gsm_7bit_encode(ptr8, net->name_short);
1409
Harald Weltedb253af2008-12-30 17:56:55 +00001410 }
1411
1412#if 0
1413 /* Section 10.5.3.9 */
1414 cur_t = time(NULL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001415 cur_time = gmtime(&cur_t);
Harald Weltedb253af2008-12-30 17:56:55 +00001416 ptr8 = msgb_put(msg, 8);
1417 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1418 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1419 ptr8[2] = to_bcd8(cur_time->tm_mon);
1420 ptr8[3] = to_bcd8(cur_time->tm_mday);
1421 ptr8[4] = to_bcd8(cur_time->tm_hour);
1422 ptr8[5] = to_bcd8(cur_time->tm_min);
1423 ptr8[6] = to_bcd8(cur_time->tm_sec);
1424 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1425 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001426 ptr8[7] = to_bcd8(tz15min);
Harald Weltedb253af2008-12-30 17:56:55 +00001427 if (tz15min < 0)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001428 ptr8[7] |= 0x80;
Harald Weltedb253af2008-12-30 17:56:55 +00001429#endif
1430
Daniel Willmanneea93372009-08-13 03:42:07 +02001431 DEBUGP(DMM, "-> MM INFO\n");
1432
Harald Welte39e2ead2009-07-23 21:13:03 +02001433 return gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001434}
1435
Harald Welte7984d5c2009-08-12 22:56:50 +02001436/* Section 9.2.2 */
1437int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand)
1438{
1439 struct msgb *msg = gsm48_msgb_alloc();
1440 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1441 u_int8_t *r;
1442
1443 DEBUGP(DMM, "-> AUTH REQ\n");
1444
1445 msg->lchan = lchan;
1446 gh->proto_discr = GSM48_PDISC_MM;
1447 gh->msg_type = GSM48_MT_MM_AUTH_REQ;
1448
1449 /* 16 bytes RAND parameters */
1450 r = msgb_put(msg, 16);
1451 if (rand)
1452 memcpy(r, rand, 16);
1453
1454 return gsm48_sendmsg(msg, NULL);
1455}
1456
1457/* Section 9.2.1 */
1458int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan)
1459{
1460 DEBUGP(DMM, "-> AUTH REJECT\n");
1461 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ);
1462}
1463
Harald Welte4b634542008-12-27 01:55:51 +00001464static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1465{
Harald Welte4b634542008-12-27 01:55:51 +00001466 DEBUGP(DMM, "-> CM SERVICE ACK\n");
Harald Welte65e74cc2008-12-29 01:55:35 +00001467 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
Harald Welte4b634542008-12-27 01:55:51 +00001468}
Harald Welteba4cf162009-01-10 01:49:35 +00001469
1470/* 9.2.6 CM service reject */
1471static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1472 enum gsm48_reject_value value)
1473{
1474 struct msgb *msg = gsm48_msgb_alloc();
1475 struct gsm48_hdr *gh;
1476
1477 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1478
1479 msg->lchan = lchan;
1480 use_lchan(lchan);
1481
1482 gh->proto_discr = GSM48_PDISC_MM;
1483 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1484 gh->data[0] = value;
1485 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1486
Harald Welte39e2ead2009-07-23 21:13:03 +02001487 return gsm48_sendmsg(msg, NULL);
Harald Welteba4cf162009-01-10 01:49:35 +00001488}
1489
Harald Welte3ac7f102009-08-10 10:12:45 +02001490static int send_siemens_mrpci(struct gsm_lchan *lchan,
1491 u_int8_t *classmark2_lv)
1492{
1493 struct rsl_mrpci mrpci;
1494
1495 if (classmark2_lv[0] < 2)
1496 return -EINVAL;
1497
1498 mrpci.power_class = classmark2_lv[1] & 0x7;
1499 mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
1500 mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
1501 mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
1502
1503 return rsl_siemens_mrpci(lchan, &mrpci);
1504}
Harald Welte4ed0e922009-01-10 03:17:30 +00001505
1506/*
1507 * Handle CM Service Requests
1508 * a) Verify that the packet is long enough to contain the information
1509 * we require otherwsie reject with INCORRECT_MESSAGE
1510 * b) Try to parse the TMSI. If we do not have one reject
1511 * c) Check that we know the subscriber with the TMSI otherwise reject
1512 * with a HLR cause
1513 * d) Set the subscriber on the gsm_lchan and accept
1514 */
Harald Welte4b634542008-12-27 01:55:51 +00001515static int gsm48_rx_mm_serv_req(struct msgb *msg)
1516{
Harald Welteba4cf162009-01-10 01:49:35 +00001517 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001518 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001519
Harald Welte9176bd42009-07-23 18:46:00 +02001520 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welteba4cf162009-01-10 01:49:35 +00001521 struct gsm_subscriber *subscr;
1522 struct gsm48_hdr *gh = msgb_l3(msg);
1523 struct gsm48_service_request *req =
1524 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001525 /* unfortunately in Phase1 the classmar2 length is variable */
1526 u_int8_t classmark2_len = gh->data[1];
1527 u_int8_t *classmark2 = gh->data+2;
1528 u_int8_t mi_len = *(classmark2 + classmark2_len);
1529 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001530
Harald Weltec9e02182009-05-01 19:07:53 +00001531 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001532 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001533 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001534 return gsm48_tx_mm_serv_rej(msg->lchan,
1535 GSM48_REJECT_INCORRECT_MESSAGE);
1536 }
1537
1538 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001539 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001540 return gsm48_tx_mm_serv_rej(msg->lchan,
1541 GSM48_REJECT_INCORRECT_MESSAGE);
1542 }
1543
Harald Weltec9e02182009-05-01 19:07:53 +00001544 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001545 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001546 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001547 return gsm48_tx_mm_serv_rej(msg->lchan,
1548 GSM48_REJECT_INCORRECT_MESSAGE);
1549 }
1550
Harald Weltec9e02182009-05-01 19:07:53 +00001551 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001552 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001553 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001554
Harald Welte3ac7f102009-08-10 10:12:45 +02001555 if (is_siemens_bts(bts))
1556 send_siemens_mrpci(msg->lchan, classmark2-1);
1557
Harald Welte9176bd42009-07-23 18:46:00 +02001558 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Holger Freythereb443982009-06-04 13:58:42 +00001559
Harald Welte2a139372009-02-22 21:14:55 +00001560 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001561 if (!subscr)
1562 return gsm48_tx_mm_serv_rej(msg->lchan,
1563 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1564
1565 if (!msg->lchan->subscr)
1566 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001567 else if (msg->lchan->subscr != subscr) {
1568 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1569 subscr_put(subscr);
1570 }
1571
Harald Weltec2e302d2009-07-05 14:08:13 +02001572 subscr->equipment.classmark2_len = classmark2_len;
1573 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1574 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001575
Harald Welte4b634542008-12-27 01:55:51 +00001576 return gsm48_tx_mm_serv_ack(msg->lchan);
1577}
1578
Harald Welte2a139372009-02-22 21:14:55 +00001579static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1580{
Harald Welte9176bd42009-07-23 18:46:00 +02001581 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2a139372009-02-22 21:14:55 +00001582 struct gsm48_hdr *gh = msgb_l3(msg);
1583 struct gsm48_imsi_detach_ind *idi =
1584 (struct gsm48_imsi_detach_ind *) gh->data;
1585 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1586 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001587 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001588
1589 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1590 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1591 mi_type, mi_string);
1592
1593 switch (mi_type) {
1594 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001595 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001596 break;
1597 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001598 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001599 break;
1600 case GSM_MI_TYPE_IMEI:
1601 case GSM_MI_TYPE_IMEISV:
1602 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001603 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001604 break;
1605 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001606 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001607 break;
1608 }
1609
Holger Freyther4a49e772009-04-12 05:37:29 +00001610 if (subscr) {
1611 subscr_update(subscr, msg->trx->bts,
1612 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001613 DEBUGP(DMM, "Subscriber: %s\n",
1614 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001615 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001616 } else
Harald Welte2a139372009-02-22 21:14:55 +00001617 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1618
Harald Welte2a139372009-02-22 21:14:55 +00001619 return 0;
1620}
1621
Harald Welted2a7f5a2009-06-05 20:08:20 +00001622static int gsm48_rx_mm_status(struct msgb *msg)
1623{
1624 struct gsm48_hdr *gh = msgb_l3(msg);
1625
1626 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1627
1628 return 0;
1629}
1630
Harald Weltebf5e8df2009-02-03 12:59:45 +00001631/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001632static int gsm0408_rcv_mm(struct msgb *msg)
1633{
1634 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001635 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001636
1637 switch (gh->msg_type & 0xbf) {
1638 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001639 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001640 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001641 break;
1642 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001643 rc = mm_rx_id_resp(msg);
1644 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001645 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001646 rc = gsm48_rx_mm_serv_req(msg);
1647 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001648 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001649 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001650 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001651 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001652 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1653 msg->lchan->subscr ?
1654 msg->lchan->subscr->imsi :
1655 "unknown subscriber");
1656 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001657 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001658 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1659 break;
1660 case GSM48_MT_MM_CM_REEST_REQ:
1661 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1662 break;
1663 case GSM48_MT_MM_AUTH_RESP:
1664 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001665 break;
1666 default:
1667 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1668 gh->msg_type);
1669 break;
1670 }
1671
1672 return rc;
1673}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001674
Harald Welte2d35ae62009-02-06 12:02:13 +00001675/* Receive a PAGING RESPONSE message from the MS */
1676static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1677{
Harald Welte9176bd42009-07-23 18:46:00 +02001678 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2d35ae62009-02-06 12:02:13 +00001679 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001680 u_int8_t *classmark2_lv = gh->data + 1;
1681 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1682 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001683 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001684 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001685 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001686 int rc = 0;
1687
Harald Welte61548982009-02-22 21:26:29 +00001688 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001689 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1690 mi_type, mi_string);
Harald Welte3ac7f102009-08-10 10:12:45 +02001691
1692 if (is_siemens_bts(bts))
1693 send_siemens_mrpci(msg->lchan, classmark2_lv);
1694
Harald Weltefe18d8f2009-02-22 21:14:24 +00001695 switch (mi_type) {
1696 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001697 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001698 break;
1699 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001700 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001701 break;
1702 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001703
1704 if (!subscr) {
1705 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001706 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001707 return -EINVAL;
1708 }
1709 DEBUGP(DRR, "<- Channel was requested by %s\n",
Harald Welte76042182009-08-08 16:03:15 +02001710 subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001711
Harald Weltec2e302d2009-07-05 14:08:13 +02001712 subscr->equipment.classmark2_len = *classmark2_lv;
1713 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1714 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001715
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001716 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001717 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001718 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001719 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1720 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001721 return -EINVAL;
1722 } else {
1723 DEBUGP(DRR, "<- Channel already owned by us\n");
1724 subscr_put(subscr);
1725 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001726 }
1727
Harald Welte595ad7b2009-02-16 22:05:44 +00001728 sig_data.subscr = subscr;
1729 sig_data.bts = msg->lchan->ts->trx->bts;
1730 sig_data.lchan = msg->lchan;
1731
1732 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001733
1734 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001735 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001736
Harald Welte7584aea2009-02-11 11:44:12 +00001737 /* FIXME: somehow signal the completion of the PAGING to
1738 * the entity that requested the paging */
1739
Harald Welte2d35ae62009-02-06 12:02:13 +00001740 return rc;
1741}
1742
Harald Weltef7c43522009-06-09 20:24:21 +00001743static int gsm48_rx_rr_classmark(struct msgb *msg)
1744{
1745 struct gsm48_hdr *gh = msgb_l3(msg);
1746 struct gsm_subscriber *subscr = msg->lchan->subscr;
1747 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1748 u_int8_t cm2_len, cm3_len = 0;
1749 u_int8_t *cm2, *cm3 = NULL;
1750
1751 DEBUGP(DRR, "CLASSMARK CHANGE ");
1752
1753 /* classmark 2 */
1754 cm2_len = gh->data[0];
1755 cm2 = &gh->data[1];
1756 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1757
1758 if (payload_len > cm2_len + 1) {
1759 /* we must have a classmark3 */
1760 if (gh->data[cm2_len+1] != 0x20) {
1761 DEBUGPC(DRR, "ERR CM3 TAG\n");
1762 return -EINVAL;
1763 }
1764 if (cm2_len > 3) {
1765 DEBUGPC(DRR, "CM2 too long!\n");
1766 return -EINVAL;
1767 }
1768
1769 cm3_len = gh->data[cm2_len+2];
1770 cm3 = &gh->data[cm2_len+3];
1771 if (cm3_len > 14) {
1772 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1773 return -EINVAL;
1774 }
1775 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1776 }
1777 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001778 subscr->equipment.classmark2_len = cm2_len;
1779 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001780 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001781 subscr->equipment.classmark3_len = cm3_len;
1782 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001783 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001784 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001785 }
1786
Harald Weltef7c43522009-06-09 20:24:21 +00001787 return 0;
1788}
1789
Harald Weltecf5b3592009-05-01 18:28:42 +00001790static int gsm48_rx_rr_status(struct msgb *msg)
1791{
1792 struct gsm48_hdr *gh = msgb_l3(msg);
1793
1794 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1795 rr_cause_name(gh->data[0]));
1796
1797 return 0;
1798}
1799
Harald Weltef7c43522009-06-09 20:24:21 +00001800static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1801{
1802 struct gsm48_hdr *gh = msgb_l3(msg);
1803 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1804 static struct gsm_meas_rep meas_rep;
1805
Harald Welte10d0e672009-06-27 02:53:10 +02001806 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001807 parse_meas_rep(&meas_rep, gh->data, payload_len);
1808 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001809 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001810 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001811 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001812 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001813 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001814 else
Harald Welte10d0e672009-06-27 02:53:10 +02001815 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001816 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1817 meas_rep.rxqual_sub);
1818
Harald Welte10d0e672009-06-27 02:53:10 +02001819 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001820
1821 /* FIXME: put the results somwhere */
1822
1823 return 0;
1824}
1825
Harald Weltebf5e8df2009-02-03 12:59:45 +00001826/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001827static int gsm0408_rcv_rr(struct msgb *msg)
1828{
1829 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001830 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001831
1832 switch (gh->msg_type) {
1833 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001834 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001835 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001836 case GSM48_MT_RR_GPRS_SUSP_REQ:
1837 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1838 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001839 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001840 rc = gsm48_rr_rx_pag_resp(msg);
1841 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001842 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1843 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte13cac662009-07-29 12:10:35 +02001844 /* We've successfully modified the MS side of the channel,
1845 * now go on to modify the BTS side of the channel */
Harald Welte9943c5b2009-07-29 15:41:29 +02001846 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
Harald Welte2c38aa82009-02-18 03:44:24 +00001847 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001848 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001849 case GSM48_MT_RR_STATUS:
1850 rc = gsm48_rx_rr_status(msg);
1851 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001852 case GSM48_MT_RR_MEAS_REP:
1853 rc = gsm48_rx_rr_meas_rep(msg);
1854 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001855 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001856 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001857 gh->msg_type);
1858 break;
1859 }
1860
Harald Welte2d35ae62009-02-06 12:02:13 +00001861 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001862}
1863
Harald Welte115d1032009-08-10 11:43:22 +02001864/* 7.1.7 and 9.1.7: RR CHANnel RELease */
Holger Freythere64a7a32009-02-06 21:55:37 +00001865int gsm48_send_rr_release(struct gsm_lchan *lchan)
1866{
1867 struct msgb *msg = gsm48_msgb_alloc();
1868 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1869 u_int8_t *cause;
1870
1871 msg->lchan = lchan;
1872 gh->proto_discr = GSM48_PDISC_RR;
1873 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1874
1875 cause = msgb_put(msg, 1);
1876 cause[0] = GSM48_RR_CAUSE_NORMAL;
1877
1878 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1879 lchan->nr, lchan->type);
1880
Harald Welteae0f2362009-07-19 18:36:49 +02001881 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001882 gsm48_sendmsg(msg, NULL);
Harald Welte76042182009-08-08 16:03:15 +02001883 /* FIXME: Start Timer T3109 */
Harald Welteae0f2362009-07-19 18:36:49 +02001884
1885 /* Deactivate the SACCH on the BTS side */
1886 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001887}
1888
Harald Welte4bc90a12008-12-27 16:32:52 +00001889/* Call Control */
1890
Harald Welte7584aea2009-02-11 11:44:12 +00001891/* The entire call control code is written in accordance with Figure 7.10c
1892 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1893 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1894 * it for voice */
1895
Harald Welte4bfdfe72009-06-10 23:11:52 +08001896static void new_cc_state(struct gsm_trans *trans, int state)
1897{
1898 if (state > 31 || state < 0)
1899 return;
1900
1901 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001902 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001903
Harald Weltedcaf5652009-07-23 18:56:43 +02001904 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001905}
1906
1907static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001908{
1909 struct msgb *msg = gsm48_msgb_alloc();
1910 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1911 u_int8_t *cause, *call_state;
1912
Harald Welte4bc90a12008-12-27 16:32:52 +00001913 gh->msg_type = GSM48_MT_CC_STATUS;
1914
1915 cause = msgb_put(msg, 3);
1916 cause[0] = 2;
1917 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1918 cause[2] = 0x80 | 30; /* response to status inquiry */
1919
1920 call_state = msgb_put(msg, 1);
1921 call_state[0] = 0xc0 | 0x00;
1922
Harald Welte39e2ead2009-07-23 21:13:03 +02001923 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001924}
1925
Harald Welte6f4b7532008-12-29 00:39:37 +00001926static int gsm48_tx_simple(struct gsm_lchan *lchan,
1927 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001928{
1929 struct msgb *msg = gsm48_msgb_alloc();
1930 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1931
1932 msg->lchan = lchan;
1933
Harald Welte6f4b7532008-12-29 00:39:37 +00001934 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001935 gh->msg_type = msg_type;
1936
Harald Welte39e2ead2009-07-23 21:13:03 +02001937 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001938}
1939
Harald Welte4bfdfe72009-06-10 23:11:52 +08001940static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1941{
Harald Weltedcaf5652009-07-23 18:56:43 +02001942 if (bsc_timer_pending(&trans->cc.timer)) {
1943 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1944 bsc_del_timer(&trans->cc.timer);
1945 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001946 }
1947}
1948
1949static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1950 int msg_type, struct gsm_mncc *mncc)
1951{
1952 struct msgb *msg;
1953
1954 if (trans)
1955 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001956 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001957 "Sending '%s' to MNCC.\n",
1958 trans->lchan->ts->trx->bts->nr,
1959 trans->lchan->ts->trx->nr,
1960 trans->lchan->ts->nr, trans->transaction_id,
1961 (trans->subscr)?(trans->subscr->extension):"-",
1962 get_mncc_name(msg_type));
1963 else
1964 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1965 "Sending '%s' to MNCC.\n",
1966 (trans->subscr)?(trans->subscr->extension):"-",
1967 get_mncc_name(msg_type));
1968 else
1969 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1970 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1971
1972 mncc->msg_type = msg_type;
1973
Harald Welte966636f2009-06-26 19:39:35 +02001974 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001975 if (!msg)
1976 return -ENOMEM;
1977 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1978 msgb_enqueue(&net->upqueue, msg);
1979
1980 return 0;
1981}
1982
1983int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1984 u_int32_t callref, int location, int value)
1985{
1986 struct gsm_mncc rel;
1987
Harald Welte92f70c52009-06-12 01:54:08 +08001988 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001989 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001990 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001991 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1992}
1993
Harald Weltedcaf5652009-07-23 18:56:43 +02001994/* Call Control Specific transaction release.
1995 * gets called by trans_free, DO NOT CALL YOURSELF! */
1996void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001997{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001998 gsm48_stop_cc_timer(trans);
1999
2000 /* send release to L4, if callref still exists */
2001 if (trans->callref) {
2002 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02002003 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002004 GSM48_CAUSE_LOC_PRN_S_LU,
2005 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002006 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002007 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002008 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02002009 if (trans->lchan)
2010 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002011}
2012
2013static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
2014
Harald Welte09e38af2009-02-16 22:52:23 +00002015/* call-back from paging the B-end of the connection */
2016static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00002017 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00002018{
Harald Welte7ccf7782009-02-17 01:43:01 +00002019 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002020 struct gsm_subscriber *subscr = param;
2021 struct gsm_trans *transt, *tmp;
2022 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02002023
Harald Welte09e38af2009-02-16 22:52:23 +00002024 if (hooknum != GSM_HOOK_RR_PAGING)
2025 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002026
2027 if (!subscr)
2028 return -EINVAL;
2029 net = subscr->net;
2030 if (!net) {
2031 DEBUGP(DCC, "Error Network not set!\n");
2032 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00002033 }
Harald Welte7584aea2009-02-11 11:44:12 +00002034
Harald Welte4bfdfe72009-06-10 23:11:52 +08002035 /* check all tranactions (without lchan) for subscriber */
2036 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
2037 if (transt->subscr != subscr || transt->lchan)
2038 continue;
2039 switch (event) {
2040 case GSM_PAGING_SUCCEEDED:
2041 if (!lchan) // paranoid
2042 break;
2043 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
2044 subscr->extension);
2045 /* Assign lchan */
2046 if (!transt->lchan) {
2047 transt->lchan = lchan;
2048 use_lchan(lchan);
2049 }
2050 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02002051 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002052 break;
2053 case GSM_PAGING_EXPIRED:
2054 DEBUGP(DCC, "Paging subscr %s expired!\n",
2055 subscr->extension);
2056 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002057 mncc_release_ind(transt->subscr->net, transt,
2058 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002059 GSM48_CAUSE_LOC_PRN_S_LU,
2060 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002061 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002062 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002063 break;
2064 }
2065 }
Harald Welte09e38af2009-02-16 22:52:23 +00002066 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00002067}
Harald Welte7584aea2009-02-11 11:44:12 +00002068
Harald Welte805f6442009-07-28 18:25:29 +02002069/* some other part of the code sends us a signal */
2070static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
2071 void *handler_data, void *signal_data)
2072{
2073 struct gsm_lchan *lchan = signal_data;
2074 struct gsm_bts_trx_ts *ts;
2075 int rc;
2076
2077 if (subsys != SS_ABISIP)
2078 return 0;
2079
2080 /* in case we use direct BTS-to-BTS RTP */
2081 if (ipacc_rtp_direct)
2082 return 0;
2083
2084 ts = lchan->ts;
2085
2086 switch (signal) {
2087 case S_ABISIP_BIND_ACK:
2088 /* the BTS has successfully bound a TCH to a local ip/port,
2089 * which means we can connect our UDP socket to it */
2090 if (ts->abis_ip.rtp_socket) {
2091 rtp_socket_free(ts->abis_ip.rtp_socket);
2092 ts->abis_ip.rtp_socket = NULL;
2093 }
2094
2095 ts->abis_ip.rtp_socket = rtp_socket_create();
2096 if (!ts->abis_ip.rtp_socket)
2097 goto out_err;
2098
2099 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2100 ts->abis_ip.bound_ip,
2101 ts->abis_ip.bound_port);
2102 if (rc < 0)
2103 goto out_err;
2104 break;
2105 case S_ABISIP_DISC_IND:
2106 /* the BTS tells us a RTP stream has been disconnected */
2107 if (ts->abis_ip.rtp_socket) {
2108 rtp_socket_free(ts->abis_ip.rtp_socket);
2109 ts->abis_ip.rtp_socket = NULL;
2110 }
2111 break;
2112 }
2113
2114 return 0;
2115out_err:
2116 /* FIXME: do something */
2117 return 0;
2118}
2119
2120/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2121static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2122{
2123 struct gsm_bts_trx_ts *ts = lchan->ts;
2124 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2125 int rc;
2126
2127 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2128 ntohs(rs->rtp.sin_local.sin_port),
2129 ts->abis_ip.conn_id,
2130 /* FIXME: use RTP payload of bound socket, not BTS*/
2131 ts->abis_ip.rtp_payload2);
2132
2133 return rc;
2134}
2135
Harald Welte49f48b82009-02-17 15:29:33 +00002136/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002137static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002138{
Harald Welte11fa29c2009-02-19 17:24:39 +00002139 struct gsm_bts *bts = lchan->ts->trx->bts;
2140 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002141 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002142 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002143
Harald Welte11fa29c2009-02-19 17:24:39 +00002144 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2145 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2146 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2147
2148 if (bts->type != remote_bts->type) {
2149 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2150 return -EINVAL;
2151 }
Harald Welte49f48b82009-02-17 15:29:33 +00002152
Harald Welte11fa29c2009-02-19 17:24:39 +00002153 switch (bts->type) {
2154 case GSM_BTS_TYPE_NANOBTS_900:
2155 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002156 if (!ipacc_rtp_direct) {
2157 /* connect the TCH's to our RTP proxy */
2158 rc = ipacc_connect_proxy_bind(lchan);
2159 if (rc < 0)
2160 return rc;
2161 rc = ipacc_connect_proxy_bind(remote_lchan);
2162
2163 /* connect them with each other */
2164 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2165 remote_lchan->ts->abis_ip.rtp_socket);
2166 } else {
2167 /* directly connect TCH RTP streams to each other */
2168 ts = remote_lchan->ts;
2169 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2170 ts->abis_ip.bound_port,
2171 lchan->ts->abis_ip.conn_id,
2172 ts->abis_ip.rtp_payload2);
2173 if (rc < 0)
2174 return rc;
2175 ts = lchan->ts;
2176 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2177 ts->abis_ip.bound_port,
2178 remote_lchan->ts->abis_ip.conn_id,
2179 ts->abis_ip.rtp_payload2);
2180 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002181 break;
2182 case GSM_BTS_TYPE_BS11:
2183 trau_mux_map_lchan(lchan, remote_lchan);
2184 break;
2185 default:
2186 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002187 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002188 break;
2189 }
Harald Welte49f48b82009-02-17 15:29:33 +00002190
2191 return 0;
2192}
2193
Harald Welte4bfdfe72009-06-10 23:11:52 +08002194/* bridge channels of two transactions */
2195static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002196{
Harald Weltedcaf5652009-07-23 18:56:43 +02002197 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2198 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002199
Harald Welte4bfdfe72009-06-10 23:11:52 +08002200 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002201 return -EIO;
2202
Harald Welte4bfdfe72009-06-10 23:11:52 +08002203 if (!trans1->lchan || !trans2->lchan)
2204 return -EIO;
2205
2206 /* through-connect channel */
2207 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002208}
2209
Harald Welte4bfdfe72009-06-10 23:11:52 +08002210/* enable receive of channels to upqueue */
2211static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2212{
2213 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002214
Harald Welte4bfdfe72009-06-10 23:11:52 +08002215 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002216 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002217 if (!trans)
2218 return -EIO;
2219 if (!trans->lchan)
2220 return 0;
2221
2222 // todo IPACCESS
2223 if (enable)
2224 return trau_recv_lchan(trans->lchan, data->callref);
2225 return trau_mux_unmap(NULL, data->callref);
2226}
2227
2228/* send a frame to channel */
2229static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2230{
2231 struct gsm_trans *trans;
2232
2233 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002234 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002235 if (!trans)
2236 return -EIO;
2237 if (!trans->lchan)
2238 return 0;
2239 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2240 trans->lchan->type != GSM_LCHAN_TCH_H)
2241 return 0;
2242
2243 // todo IPACCESS
2244 return trau_send_lchan(trans->lchan,
2245 (struct decoded_trau_frame *)frame->data);
2246}
2247
2248
2249static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2250{
2251 DEBUGP(DCC, "-> STATUS ENQ\n");
2252 return gsm48_cc_tx_status(trans, msg);
2253}
2254
2255static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2256static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2257
2258static void gsm48_cc_timeout(void *arg)
2259{
2260 struct gsm_trans *trans = arg;
2261 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002262 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2263 int mo_location = GSM48_CAUSE_LOC_USER;
2264 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2265 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002266 struct gsm_mncc mo_rel, l4_rel;
2267
2268 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2269 mo_rel.callref = trans->callref;
2270 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2271 l4_rel.callref = trans->callref;
2272
Harald Weltedcaf5652009-07-23 18:56:43 +02002273 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002274 case 0x303:
2275 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002276 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002277 break;
2278 case 0x310:
2279 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002280 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002281 break;
2282 case 0x313:
2283 disconnect = 1;
2284 /* unknown, did not find it in the specs */
2285 break;
2286 case 0x301:
2287 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002288 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002289 break;
2290 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002291 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002292 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002293 gsm48_cc_tx_release(trans, &trans->cc.msg);
2294 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002295 break; /* stay in release state */
2296 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002297 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002298 return;
2299// release = 1;
2300// l4_cause = 14;
2301// break;
2302 case 0x306:
2303 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002304 mo_cause = trans->cc.msg.cause.value;
2305 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002306 break;
2307 case 0x323:
2308 disconnect = 1;
2309 break;
2310 default:
2311 release = 1;
2312 }
2313
2314 if (release && trans->callref) {
2315 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002316 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002317 l4_location, l4_cause);
2318 trans->callref = 0;
2319 }
2320
2321 if (disconnect && trans->callref) {
2322 /* process disconnect towards layer 4 */
2323 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002324 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002325 }
2326
2327 /* process disconnect towards mobile station */
2328 if (disconnect || release) {
2329 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002330 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2331 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2332 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002333 mo_rel.cause.diag_len = 3;
2334
2335 if (disconnect)
2336 gsm48_cc_tx_disconnect(trans, &mo_rel);
2337 if (release)
2338 gsm48_cc_tx_release(trans, &mo_rel);
2339 }
2340
2341}
2342
2343static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2344 int sec, int micro)
2345{
2346 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002347 trans->cc.timer.cb = gsm48_cc_timeout;
2348 trans->cc.timer.data = trans;
2349 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2350 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002351}
2352
2353static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2354{
2355 struct gsm48_hdr *gh = msgb_l3(msg);
2356 u_int8_t msg_type = gh->msg_type & 0xbf;
2357 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2358 struct tlv_parsed tp;
2359 struct gsm_mncc setup;
2360
2361 memset(&setup, 0, sizeof(struct gsm_mncc));
2362 setup.callref = trans->callref;
2363 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2364 /* emergency setup is identified by msg_type */
2365 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2366 setup.emergency = 1;
2367
2368 /* use subscriber as calling party number */
2369 if (trans->subscr) {
2370 setup.fields |= MNCC_F_CALLING;
2371 strncpy(setup.calling.number, trans->subscr->extension,
2372 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002373 strncpy(setup.imsi, trans->subscr->imsi,
2374 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002375 }
2376 /* bearer capability */
2377 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2378 setup.fields |= MNCC_F_BEARER_CAP;
2379 decode_bearer_cap(&setup.bearer_cap,
2380 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2381 }
2382 /* facility */
2383 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2384 setup.fields |= MNCC_F_FACILITY;
2385 decode_facility(&setup.facility,
2386 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2387 }
2388 /* called party bcd number */
2389 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2390 setup.fields |= MNCC_F_CALLED;
2391 decode_called(&setup.called,
2392 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2393 }
2394 /* user-user */
2395 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2396 setup.fields |= MNCC_F_USERUSER;
2397 decode_useruser(&setup.useruser,
2398 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2399 }
2400 /* ss-version */
2401 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2402 setup.fields |= MNCC_F_SSVERSION;
2403 decode_ssversion(&setup.ssversion,
2404 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2405 }
2406 /* CLIR suppression */
2407 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2408 setup.clir.sup = 1;
2409 /* CLIR invocation */
2410 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2411 setup.clir.inv = 1;
2412 /* cc cap */
2413 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2414 setup.fields |= MNCC_F_CCCAP;
2415 decode_cccap(&setup.cccap,
2416 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2417 }
2418
Harald Welte4bfdfe72009-06-10 23:11:52 +08002419 new_cc_state(trans, GSM_CSTATE_INITIATED);
2420
2421 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002422 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002423
Harald Welte13cac662009-07-29 12:10:35 +02002424 /* MNCC code will modify the channel asynchronously, we should
2425 * ipaccess-bind only after the modification has been made to the
2426 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002427 return 0;
2428}
2429
2430static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002431{
2432 struct msgb *msg = gsm48_msgb_alloc();
2433 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002434 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002435 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002436
Harald Welte7ccf7782009-02-17 01:43:01 +00002437 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002438
Harald Welte4bfdfe72009-06-10 23:11:52 +08002439 /* transaction id must not be assigned */
2440 if (trans->transaction_id != 0xff) { /* unasssigned */
2441 DEBUGP(DCC, "TX Setup with assigned transaction. "
2442 "This is not allowed!\n");
2443 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002444 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002445 GSM48_CAUSE_LOC_PRN_S_LU,
2446 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002447 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002448 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002449 return rc;
2450 }
2451
2452 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002453 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2454 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002455 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002456 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002457 GSM48_CAUSE_LOC_PRN_S_LU,
2458 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002459 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002460 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002461 return rc;
2462 }
Harald Welte78283ef2009-07-23 21:36:44 +02002463 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002464
Harald Welte65e74cc2008-12-29 01:55:35 +00002465 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002466
Harald Welte4bfdfe72009-06-10 23:11:52 +08002467 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002468
Harald Welte4bfdfe72009-06-10 23:11:52 +08002469 /* bearer capability */
2470 if (setup->fields & MNCC_F_BEARER_CAP)
2471 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2472 /* facility */
2473 if (setup->fields & MNCC_F_FACILITY)
2474 encode_facility(msg, 0, &setup->facility);
2475 /* progress */
2476 if (setup->fields & MNCC_F_PROGRESS)
2477 encode_progress(msg, 0, &setup->progress);
2478 /* calling party BCD number */
2479 if (setup->fields & MNCC_F_CALLING)
2480 encode_calling(msg, &setup->calling);
2481 /* called party BCD number */
2482 if (setup->fields & MNCC_F_CALLED)
2483 encode_called(msg, &setup->called);
2484 /* user-user */
2485 if (setup->fields & MNCC_F_USERUSER)
2486 encode_useruser(msg, 0, &setup->useruser);
2487 /* redirecting party BCD number */
2488 if (setup->fields & MNCC_F_REDIRECTING)
2489 encode_redirecting(msg, &setup->redirecting);
2490 /* signal */
2491 if (setup->fields & MNCC_F_SIGNAL)
2492 encode_signal(msg, setup->signal);
2493
2494 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002495
Harald Welte39e2ead2009-07-23 21:13:03 +02002496 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002497}
2498
Harald Welte4bfdfe72009-06-10 23:11:52 +08002499static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2500{
2501 struct gsm48_hdr *gh = msgb_l3(msg);
2502 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2503 struct tlv_parsed tp;
2504 struct gsm_mncc call_conf;
2505
2506 gsm48_stop_cc_timer(trans);
2507 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2508
2509 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2510 call_conf.callref = trans->callref;
2511 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2512#if 0
2513 /* repeat */
2514 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2515 call_conf.repeat = 1;
2516 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2517 call_conf.repeat = 2;
2518#endif
2519 /* bearer capability */
2520 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2521 call_conf.fields |= MNCC_F_BEARER_CAP;
2522 decode_bearer_cap(&call_conf.bearer_cap,
2523 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2524 }
2525 /* cause */
2526 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2527 call_conf.fields |= MNCC_F_CAUSE;
2528 decode_cause(&call_conf.cause,
2529 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2530 }
2531 /* cc cap */
2532 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2533 call_conf.fields |= MNCC_F_CCCAP;
2534 decode_cccap(&call_conf.cccap,
2535 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2536 }
2537
2538 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2539
Harald Welte596fed42009-07-23 19:06:52 +02002540 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2541 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002542}
2543
2544static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2545{
2546 struct gsm_mncc *proceeding = arg;
2547 struct msgb *msg = gsm48_msgb_alloc();
2548 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2549
Harald Welte4bfdfe72009-06-10 23:11:52 +08002550 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2551
2552 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2553
2554 /* bearer capability */
2555 if (proceeding->fields & MNCC_F_BEARER_CAP)
2556 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2557 /* facility */
2558 if (proceeding->fields & MNCC_F_FACILITY)
2559 encode_facility(msg, 0, &proceeding->facility);
2560 /* progress */
2561 if (proceeding->fields & MNCC_F_PROGRESS)
2562 encode_progress(msg, 0, &proceeding->progress);
2563
Harald Welte39e2ead2009-07-23 21:13:03 +02002564 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002565}
2566
2567static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2568{
2569 struct gsm48_hdr *gh = msgb_l3(msg);
2570 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2571 struct tlv_parsed tp;
2572 struct gsm_mncc alerting;
2573
2574 gsm48_stop_cc_timer(trans);
2575 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2576
2577 memset(&alerting, 0, sizeof(struct gsm_mncc));
2578 alerting.callref = trans->callref;
2579 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2580 /* facility */
2581 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2582 alerting.fields |= MNCC_F_FACILITY;
2583 decode_facility(&alerting.facility,
2584 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2585 }
2586
2587 /* progress */
2588 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2589 alerting.fields |= MNCC_F_PROGRESS;
2590 decode_progress(&alerting.progress,
2591 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2592 }
2593 /* ss-version */
2594 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2595 alerting.fields |= MNCC_F_SSVERSION;
2596 decode_ssversion(&alerting.ssversion,
2597 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2598 }
2599
2600 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2601
Harald Welte596fed42009-07-23 19:06:52 +02002602 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2603 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002604}
2605
2606static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2607{
2608 struct gsm_mncc *alerting = arg;
2609 struct msgb *msg = gsm48_msgb_alloc();
2610 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2611
Harald Welte4bfdfe72009-06-10 23:11:52 +08002612 gh->msg_type = GSM48_MT_CC_ALERTING;
2613
2614 /* facility */
2615 if (alerting->fields & MNCC_F_FACILITY)
2616 encode_facility(msg, 0, &alerting->facility);
2617 /* progress */
2618 if (alerting->fields & MNCC_F_PROGRESS)
2619 encode_progress(msg, 0, &alerting->progress);
2620 /* user-user */
2621 if (alerting->fields & MNCC_F_USERUSER)
2622 encode_useruser(msg, 0, &alerting->useruser);
2623
2624 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2625
Harald Welte39e2ead2009-07-23 21:13:03 +02002626 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002627}
2628
2629static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2630{
2631 struct gsm_mncc *progress = arg;
2632 struct msgb *msg = gsm48_msgb_alloc();
2633 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2634
Harald Welte4bfdfe72009-06-10 23:11:52 +08002635 gh->msg_type = GSM48_MT_CC_PROGRESS;
2636
2637 /* progress */
2638 encode_progress(msg, 1, &progress->progress);
2639 /* user-user */
2640 if (progress->fields & MNCC_F_USERUSER)
2641 encode_useruser(msg, 0, &progress->useruser);
2642
Harald Welte39e2ead2009-07-23 21:13:03 +02002643 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002644}
2645
2646static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2647{
2648 struct gsm_mncc *connect = arg;
2649 struct msgb *msg = gsm48_msgb_alloc();
2650 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2651
Harald Welte4bfdfe72009-06-10 23:11:52 +08002652 gh->msg_type = GSM48_MT_CC_CONNECT;
2653
2654 gsm48_stop_cc_timer(trans);
2655 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2656
2657 /* facility */
2658 if (connect->fields & MNCC_F_FACILITY)
2659 encode_facility(msg, 0, &connect->facility);
2660 /* progress */
2661 if (connect->fields & MNCC_F_PROGRESS)
2662 encode_progress(msg, 0, &connect->progress);
2663 /* connected number */
2664 if (connect->fields & MNCC_F_CONNECTED)
2665 encode_connected(msg, &connect->connected);
2666 /* user-user */
2667 if (connect->fields & MNCC_F_USERUSER)
2668 encode_useruser(msg, 0, &connect->useruser);
2669
2670 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2671
Harald Welte39e2ead2009-07-23 21:13:03 +02002672 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002673}
2674
2675static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2676{
2677 struct gsm48_hdr *gh = msgb_l3(msg);
2678 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2679 struct tlv_parsed tp;
2680 struct gsm_mncc connect;
2681
2682 gsm48_stop_cc_timer(trans);
2683
2684 memset(&connect, 0, sizeof(struct gsm_mncc));
2685 connect.callref = trans->callref;
2686 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2687 /* use subscriber as connected party number */
2688 if (trans->subscr) {
2689 connect.fields |= MNCC_F_CONNECTED;
2690 strncpy(connect.connected.number, trans->subscr->extension,
2691 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002692 strncpy(connect.imsi, trans->subscr->imsi,
2693 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002694 }
2695 /* facility */
2696 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2697 connect.fields |= MNCC_F_FACILITY;
2698 decode_facility(&connect.facility,
2699 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2700 }
2701 /* user-user */
2702 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2703 connect.fields |= MNCC_F_USERUSER;
2704 decode_useruser(&connect.useruser,
2705 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2706 }
2707 /* ss-version */
2708 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2709 connect.fields |= MNCC_F_SSVERSION;
2710 decode_ssversion(&connect.ssversion,
2711 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2712 }
2713
2714 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2715
Harald Welte596fed42009-07-23 19:06:52 +02002716 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002717}
2718
2719
2720static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2721{
2722 struct gsm_mncc connect_ack;
2723
2724 gsm48_stop_cc_timer(trans);
2725
2726 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2727
2728 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2729 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002730 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002731 &connect_ack);
2732}
2733
2734static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2735{
2736 struct msgb *msg = gsm48_msgb_alloc();
2737 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2738
Harald Welte4bfdfe72009-06-10 23:11:52 +08002739 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2740
2741 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2742
Harald Welte39e2ead2009-07-23 21:13:03 +02002743 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002744}
2745
2746static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2747{
2748 struct gsm48_hdr *gh = msgb_l3(msg);
2749 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2750 struct tlv_parsed tp;
2751 struct gsm_mncc disc;
2752
2753 gsm48_stop_cc_timer(trans);
2754
2755 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2756
2757 memset(&disc, 0, sizeof(struct gsm_mncc));
2758 disc.callref = trans->callref;
2759 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2760 /* cause */
2761 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2762 disc.fields |= MNCC_F_CAUSE;
2763 decode_cause(&disc.cause,
2764 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2765 }
2766 /* facility */
2767 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2768 disc.fields |= MNCC_F_FACILITY;
2769 decode_facility(&disc.facility,
2770 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2771 }
2772 /* user-user */
2773 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2774 disc.fields |= MNCC_F_USERUSER;
2775 decode_useruser(&disc.useruser,
2776 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2777 }
2778 /* ss-version */
2779 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2780 disc.fields |= MNCC_F_SSVERSION;
2781 decode_ssversion(&disc.ssversion,
2782 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2783 }
2784
Harald Welte596fed42009-07-23 19:06:52 +02002785 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002786
2787}
2788
Harald Weltec66b71c2009-06-11 14:23:20 +08002789static struct gsm_mncc_cause default_cause = {
2790 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2791 .coding = 0,
2792 .rec = 0,
2793 .rec_val = 0,
2794 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2795 .diag_len = 0,
2796 .diag = { 0 },
2797};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002798
2799static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2800{
2801 struct gsm_mncc *disc = arg;
2802 struct msgb *msg = gsm48_msgb_alloc();
2803 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2804
Harald Welte4bfdfe72009-06-10 23:11:52 +08002805 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2806
2807 gsm48_stop_cc_timer(trans);
2808 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2809
2810 /* cause */
2811 if (disc->fields & MNCC_F_CAUSE)
2812 encode_cause(msg, 1, &disc->cause);
2813 else
2814 encode_cause(msg, 1, &default_cause);
2815
2816 /* facility */
2817 if (disc->fields & MNCC_F_FACILITY)
2818 encode_facility(msg, 0, &disc->facility);
2819 /* progress */
2820 if (disc->fields & MNCC_F_PROGRESS)
2821 encode_progress(msg, 0, &disc->progress);
2822 /* user-user */
2823 if (disc->fields & MNCC_F_USERUSER)
2824 encode_useruser(msg, 0, &disc->useruser);
2825
2826 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002827 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002828
2829 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2830
Harald Welte39e2ead2009-07-23 21:13:03 +02002831 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002832}
2833
2834static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2835{
2836 struct gsm48_hdr *gh = msgb_l3(msg);
2837 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2838 struct tlv_parsed tp;
2839 struct gsm_mncc rel;
2840 int rc;
2841
2842 gsm48_stop_cc_timer(trans);
2843
2844 memset(&rel, 0, sizeof(struct gsm_mncc));
2845 rel.callref = trans->callref;
2846 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2847 /* cause */
2848 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2849 rel.fields |= MNCC_F_CAUSE;
2850 decode_cause(&rel.cause,
2851 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2852 }
2853 /* facility */
2854 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2855 rel.fields |= MNCC_F_FACILITY;
2856 decode_facility(&rel.facility,
2857 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2858 }
2859 /* user-user */
2860 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2861 rel.fields |= MNCC_F_USERUSER;
2862 decode_useruser(&rel.useruser,
2863 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2864 }
2865 /* ss-version */
2866 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2867 rel.fields |= MNCC_F_SSVERSION;
2868 decode_ssversion(&rel.ssversion,
2869 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2870 }
2871
Harald Weltedcaf5652009-07-23 18:56:43 +02002872 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002873 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002874 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002875 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002876 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002877 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002878 GSM48_MT_CC_RELEASE_COMPL);
2879 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002880 }
2881
2882 new_cc_state(trans, GSM_CSTATE_NULL);
2883
2884 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002885 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002886
2887 return rc;
2888}
2889
2890static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2891{
2892 struct gsm_mncc *rel = arg;
2893 struct msgb *msg = gsm48_msgb_alloc();
2894 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2895
Harald Welte4bfdfe72009-06-10 23:11:52 +08002896 gh->msg_type = GSM48_MT_CC_RELEASE;
2897
2898 trans->callref = 0;
2899
2900 gsm48_stop_cc_timer(trans);
2901 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2902
2903 /* cause */
2904 if (rel->fields & MNCC_F_CAUSE)
2905 encode_cause(msg, 0, &rel->cause);
2906 /* facility */
2907 if (rel->fields & MNCC_F_FACILITY)
2908 encode_facility(msg, 0, &rel->facility);
2909 /* user-user */
2910 if (rel->fields & MNCC_F_USERUSER)
2911 encode_useruser(msg, 0, &rel->useruser);
2912
Harald Weltedcaf5652009-07-23 18:56:43 +02002913 trans->cc.T308_second = 0;
2914 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002915
Harald Weltedcaf5652009-07-23 18:56:43 +02002916 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002917 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2918
Harald Welte39e2ead2009-07-23 21:13:03 +02002919 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002920}
2921
2922static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2923{
2924 struct gsm48_hdr *gh = msgb_l3(msg);
2925 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2926 struct tlv_parsed tp;
2927 struct gsm_mncc rel;
2928 int rc = 0;
2929
2930 gsm48_stop_cc_timer(trans);
2931
2932 memset(&rel, 0, sizeof(struct gsm_mncc));
2933 rel.callref = trans->callref;
2934 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2935 /* cause */
2936 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2937 rel.fields |= MNCC_F_CAUSE;
2938 decode_cause(&rel.cause,
2939 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2940 }
2941 /* facility */
2942 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2943 rel.fields |= MNCC_F_FACILITY;
2944 decode_facility(&rel.facility,
2945 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2946 }
2947 /* user-user */
2948 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2949 rel.fields |= MNCC_F_USERUSER;
2950 decode_useruser(&rel.useruser,
2951 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2952 }
2953 /* ss-version */
2954 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2955 rel.fields |= MNCC_F_SSVERSION;
2956 decode_ssversion(&rel.ssversion,
2957 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2958 }
2959
2960 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002961 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002962 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002963 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002964 MNCC_REJ_IND, &rel);
2965 break;
2966 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002967 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002968 MNCC_REL_CNF, &rel);
2969 break;
2970 default:
Harald Welte596fed42009-07-23 19:06:52 +02002971 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002972 MNCC_REL_IND, &rel);
2973 }
2974 }
2975
2976 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002977 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002978
2979 return rc;
2980}
2981
2982static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2983{
2984 struct gsm_mncc *rel = arg;
2985 struct msgb *msg = gsm48_msgb_alloc();
2986 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2987
Harald Welte4bfdfe72009-06-10 23:11:52 +08002988 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2989
2990 trans->callref = 0;
2991
2992 gsm48_stop_cc_timer(trans);
2993
2994 /* cause */
2995 if (rel->fields & MNCC_F_CAUSE)
2996 encode_cause(msg, 0, &rel->cause);
2997 /* facility */
2998 if (rel->fields & MNCC_F_FACILITY)
2999 encode_facility(msg, 0, &rel->facility);
3000 /* user-user */
3001 if (rel->fields & MNCC_F_USERUSER)
3002 encode_useruser(msg, 0, &rel->useruser);
3003
Harald Weltedcaf5652009-07-23 18:56:43 +02003004 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003005
Harald Welte39e2ead2009-07-23 21:13:03 +02003006 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003007}
3008
3009static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
3010{
3011 struct gsm48_hdr *gh = msgb_l3(msg);
3012 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3013 struct tlv_parsed tp;
3014 struct gsm_mncc fac;
3015
3016 memset(&fac, 0, sizeof(struct gsm_mncc));
3017 fac.callref = trans->callref;
3018 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
3019 /* facility */
3020 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
3021 fac.fields |= MNCC_F_FACILITY;
3022 decode_facility(&fac.facility,
3023 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
3024 }
3025 /* ss-version */
3026 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
3027 fac.fields |= MNCC_F_SSVERSION;
3028 decode_ssversion(&fac.ssversion,
3029 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
3030 }
3031
Harald Welte596fed42009-07-23 19:06:52 +02003032 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003033}
3034
3035static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
3036{
3037 struct gsm_mncc *fac = arg;
3038 struct msgb *msg = gsm48_msgb_alloc();
3039 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3040
Harald Welte4bfdfe72009-06-10 23:11:52 +08003041 gh->msg_type = GSM48_MT_CC_FACILITY;
3042
3043 /* facility */
3044 encode_facility(msg, 1, &fac->facility);
3045
Harald Welte39e2ead2009-07-23 21:13:03 +02003046 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003047}
3048
3049static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
3050{
3051 struct gsm_mncc hold;
3052
3053 memset(&hold, 0, sizeof(struct gsm_mncc));
3054 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003055 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003056}
3057
3058static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
3059{
3060 struct msgb *msg = gsm48_msgb_alloc();
3061 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3062
Harald Welte4bfdfe72009-06-10 23:11:52 +08003063 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
3064
Harald Welte39e2ead2009-07-23 21:13:03 +02003065 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003066}
3067
3068static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
3069{
3070 struct gsm_mncc *hold_rej = arg;
3071 struct msgb *msg = gsm48_msgb_alloc();
3072 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3073
Harald Welte4bfdfe72009-06-10 23:11:52 +08003074 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
3075
3076 /* cause */
3077 if (hold_rej->fields & MNCC_F_CAUSE)
3078 encode_cause(msg, 1, &hold_rej->cause);
3079 else
3080 encode_cause(msg, 1, &default_cause);
3081
Harald Welte39e2ead2009-07-23 21:13:03 +02003082 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003083}
3084
3085static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
3086{
3087 struct gsm_mncc retrieve;
3088
3089 memset(&retrieve, 0, sizeof(struct gsm_mncc));
3090 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003091 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
3092 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003093}
3094
3095static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
3096{
3097 struct msgb *msg = gsm48_msgb_alloc();
3098 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3099
Harald Welte4bfdfe72009-06-10 23:11:52 +08003100 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3101
Harald Welte39e2ead2009-07-23 21:13:03 +02003102 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003103}
3104
3105static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3106{
3107 struct gsm_mncc *retrieve_rej = arg;
3108 struct msgb *msg = gsm48_msgb_alloc();
3109 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3110
Harald Welte4bfdfe72009-06-10 23:11:52 +08003111 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3112
3113 /* cause */
3114 if (retrieve_rej->fields & MNCC_F_CAUSE)
3115 encode_cause(msg, 1, &retrieve_rej->cause);
3116 else
3117 encode_cause(msg, 1, &default_cause);
3118
Harald Welte39e2ead2009-07-23 21:13:03 +02003119 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003120}
3121
3122static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3123{
3124 struct gsm48_hdr *gh = msgb_l3(msg);
3125 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3126 struct tlv_parsed tp;
3127 struct gsm_mncc dtmf;
3128
3129 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3130 dtmf.callref = trans->callref;
3131 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3132 /* keypad facility */
3133 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3134 dtmf.fields |= MNCC_F_KEYPAD;
3135 decode_keypad(&dtmf.keypad,
3136 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3137 }
3138
Harald Welte596fed42009-07-23 19:06:52 +02003139 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003140}
3141
3142static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3143{
3144 struct gsm_mncc *dtmf = arg;
3145 struct msgb *msg = gsm48_msgb_alloc();
3146 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3147
Harald Welte4bfdfe72009-06-10 23:11:52 +08003148 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3149
3150 /* keypad */
3151 if (dtmf->fields & MNCC_F_KEYPAD)
3152 encode_keypad(msg, dtmf->keypad);
3153
Harald Welte39e2ead2009-07-23 21:13:03 +02003154 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003155}
3156
3157static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3158{
3159 struct gsm_mncc *dtmf = arg;
3160 struct msgb *msg = gsm48_msgb_alloc();
3161 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3162
Harald Welte4bfdfe72009-06-10 23:11:52 +08003163 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3164
3165 /* cause */
3166 if (dtmf->fields & MNCC_F_CAUSE)
3167 encode_cause(msg, 1, &dtmf->cause);
3168 else
3169 encode_cause(msg, 1, &default_cause);
3170
Harald Welte39e2ead2009-07-23 21:13:03 +02003171 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003172}
3173
3174static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3175{
3176 struct msgb *msg = gsm48_msgb_alloc();
3177 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3178
Harald Welte4bfdfe72009-06-10 23:11:52 +08003179 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3180
Harald Welte39e2ead2009-07-23 21:13:03 +02003181 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003182}
3183
3184static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3185{
3186 struct gsm_mncc dtmf;
3187
3188 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3189 dtmf.callref = trans->callref;
3190
Harald Welte596fed42009-07-23 19:06:52 +02003191 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003192}
3193
3194static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3195{
3196 struct gsm48_hdr *gh = msgb_l3(msg);
3197 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3198 struct tlv_parsed tp;
3199 struct gsm_mncc modify;
3200
3201 memset(&modify, 0, sizeof(struct gsm_mncc));
3202 modify.callref = trans->callref;
3203 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3204 /* bearer capability */
3205 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3206 modify.fields |= MNCC_F_BEARER_CAP;
3207 decode_bearer_cap(&modify.bearer_cap,
3208 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3209 }
3210
3211 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3212
Harald Welte596fed42009-07-23 19:06:52 +02003213 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003214}
3215
3216static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3217{
3218 struct gsm_mncc *modify = arg;
3219 struct msgb *msg = gsm48_msgb_alloc();
3220 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3221
Harald Welte4bfdfe72009-06-10 23:11:52 +08003222 gh->msg_type = GSM48_MT_CC_MODIFY;
3223
3224 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3225
3226 /* bearer capability */
3227 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3228
3229 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3230
Harald Welte39e2ead2009-07-23 21:13:03 +02003231 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003232}
3233
3234static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3235{
3236 struct gsm48_hdr *gh = msgb_l3(msg);
3237 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3238 struct tlv_parsed tp;
3239 struct gsm_mncc modify;
3240
3241 gsm48_stop_cc_timer(trans);
3242
3243 memset(&modify, 0, sizeof(struct gsm_mncc));
3244 modify.callref = trans->callref;
3245 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3246 /* bearer capability */
3247 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3248 modify.fields |= MNCC_F_BEARER_CAP;
3249 decode_bearer_cap(&modify.bearer_cap,
3250 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3251 }
3252
3253 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3254
Harald Welte596fed42009-07-23 19:06:52 +02003255 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003256}
3257
3258static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3259{
3260 struct gsm_mncc *modify = arg;
3261 struct msgb *msg = gsm48_msgb_alloc();
3262 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3263
Harald Welte4bfdfe72009-06-10 23:11:52 +08003264 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3265
3266 /* bearer capability */
3267 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3268
3269 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3270
Harald Welte39e2ead2009-07-23 21:13:03 +02003271 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003272}
3273
3274static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3275{
3276 struct gsm48_hdr *gh = msgb_l3(msg);
3277 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3278 struct tlv_parsed tp;
3279 struct gsm_mncc modify;
3280
3281 gsm48_stop_cc_timer(trans);
3282
3283 memset(&modify, 0, sizeof(struct gsm_mncc));
3284 modify.callref = trans->callref;
3285 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3286 /* bearer capability */
3287 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3288 modify.fields |= GSM48_IE_BEARER_CAP;
3289 decode_bearer_cap(&modify.bearer_cap,
3290 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3291 }
3292 /* cause */
3293 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3294 modify.fields |= MNCC_F_CAUSE;
3295 decode_cause(&modify.cause,
3296 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3297 }
3298
3299 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3300
Harald Welte596fed42009-07-23 19:06:52 +02003301 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003302}
3303
3304static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3305{
3306 struct gsm_mncc *modify = arg;
3307 struct msgb *msg = gsm48_msgb_alloc();
3308 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3309
Harald Welte4bfdfe72009-06-10 23:11:52 +08003310 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3311
3312 /* bearer capability */
3313 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3314 /* cause */
3315 encode_cause(msg, 1, &modify->cause);
3316
3317 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3318
Harald Welte39e2ead2009-07-23 21:13:03 +02003319 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003320}
3321
3322static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3323{
3324 struct gsm_mncc *notify = arg;
3325 struct msgb *msg = gsm48_msgb_alloc();
3326 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3327
Harald Welte4bfdfe72009-06-10 23:11:52 +08003328 gh->msg_type = GSM48_MT_CC_NOTIFY;
3329
3330 /* notify */
3331 encode_notify(msg, notify->notify);
3332
Harald Welte39e2ead2009-07-23 21:13:03 +02003333 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003334}
3335
3336static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3337{
3338 struct gsm48_hdr *gh = msgb_l3(msg);
3339 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3340// struct tlv_parsed tp;
3341 struct gsm_mncc notify;
3342
3343 memset(&notify, 0, sizeof(struct gsm_mncc));
3344 notify.callref = trans->callref;
3345// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3346 if (payload_len >= 1)
3347 decode_notify(&notify.notify, gh->data);
3348
Harald Welte596fed42009-07-23 19:06:52 +02003349 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003350}
3351
3352static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3353{
3354 struct gsm_mncc *user = arg;
3355 struct msgb *msg = gsm48_msgb_alloc();
3356 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3357
Harald Welte4bfdfe72009-06-10 23:11:52 +08003358 gh->msg_type = GSM48_MT_CC_USER_INFO;
3359
3360 /* user-user */
3361 if (user->fields & MNCC_F_USERUSER)
3362 encode_useruser(msg, 1, &user->useruser);
3363 /* more data */
3364 if (user->more)
3365 encode_more(msg);
3366
Harald Welte39e2ead2009-07-23 21:13:03 +02003367 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003368}
3369
3370static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3371{
3372 struct gsm48_hdr *gh = msgb_l3(msg);
3373 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3374 struct tlv_parsed tp;
3375 struct gsm_mncc user;
3376
3377 memset(&user, 0, sizeof(struct gsm_mncc));
3378 user.callref = trans->callref;
3379 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3380 /* user-user */
3381 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3382 user.fields |= MNCC_F_USERUSER;
3383 decode_useruser(&user.useruser,
3384 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3385 }
3386 /* more data */
3387 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3388 user.more = 1;
3389
Harald Welte596fed42009-07-23 19:06:52 +02003390 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003391}
3392
3393static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3394{
3395 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003396 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003397
Harald Welte13cac662009-07-29 12:10:35 +02003398 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3399 if (rc < 0)
3400 return rc;
3401
3402 /* FIXME: we not only need to do this after mode modify, but
3403 * also after channel activation */
3404 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3405 mode->lchan_mode != GSM48_CMODE_SIGN)
3406 rc = rsl_ipacc_bind(trans->lchan);
3407
3408 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003409}
3410
3411static struct downstate {
3412 u_int32_t states;
3413 int type;
3414 int (*rout) (struct gsm_trans *trans, void *arg);
3415} downstatelist[] = {
3416 /* mobile originating call establishment */
3417 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3418 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3419 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3420 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3421 {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 */
3422 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3423 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3424 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3425 /* mobile terminating call establishment */
3426 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3427 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3428 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3429 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3430 /* signalling during call */
3431 {SBIT(GSM_CSTATE_ACTIVE),
3432 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3433 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3434 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3435 {ALL_STATES,
3436 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3437 {ALL_STATES,
3438 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3439 {ALL_STATES,
3440 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3441 {SBIT(GSM_CSTATE_ACTIVE),
3442 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3443 {SBIT(GSM_CSTATE_ACTIVE),
3444 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3445 {SBIT(GSM_CSTATE_ACTIVE),
3446 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3447 {SBIT(GSM_CSTATE_ACTIVE),
3448 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3449 {SBIT(GSM_CSTATE_ACTIVE),
3450 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3451 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3452 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3453 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3454 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3455 {SBIT(GSM_CSTATE_ACTIVE),
3456 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3457 /* clearing */
3458 {SBIT(GSM_CSTATE_INITIATED),
3459 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3460 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3461 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3462 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3463 MNCC_REL_REQ, gsm48_cc_tx_release},
3464 /* special */
3465 {ALL_STATES,
3466 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3467};
3468
3469#define DOWNSLLEN \
3470 (sizeof(downstatelist) / sizeof(struct downstate))
3471
3472
3473int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3474{
Harald Welte1a6f7982009-08-09 18:52:33 +02003475 int i, rc = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003476 struct gsm_trans *trans = NULL, *transt;
3477 struct gsm_subscriber *subscr;
Harald Welte1a6f7982009-08-09 18:52:33 +02003478 struct gsm_lchan *lchan = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003479 struct gsm_bts *bts = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003480 struct gsm_mncc *data = arg, rel;
3481
3482 /* handle special messages */
3483 switch(msg_type) {
3484 case MNCC_BRIDGE:
3485 return tch_bridge(net, arg);
3486 case MNCC_FRAME_DROP:
3487 return tch_recv(net, arg, 0);
3488 case MNCC_FRAME_RECV:
3489 return tch_recv(net, arg, 1);
3490 case GSM_TRAU_FRAME:
3491 return tch_frame(net, arg);
3492 }
3493
3494 memset(&rel, 0, sizeof(struct gsm_mncc));
3495 rel.callref = data->callref;
3496
3497 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003498 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003499
3500 /* Callref unknown */
3501 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003502 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003503 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3504 "Received '%s' from MNCC with "
3505 "unknown callref %d\n", data->called.number,
3506 get_mncc_name(msg_type), data->callref);
3507 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003508 return mncc_release_ind(net, NULL, data->callref,
3509 GSM48_CAUSE_LOC_PRN_S_LU,
3510 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003511 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003512 if (!data->called.number[0] && !data->imsi[0]) {
3513 DEBUGP(DCC, "(bts - trx - ts - ti) "
3514 "Received '%s' from MNCC with "
3515 "no number or IMSI\n", get_mncc_name(msg_type));
3516 /* Invalid number */
3517 return mncc_release_ind(net, NULL, data->callref,
3518 GSM48_CAUSE_LOC_PRN_S_LU,
3519 GSM48_CC_CAUSE_INV_NR_FORMAT);
3520 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003521 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003522 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003523 subscr = subscr_get_by_extension(net,
3524 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003525 else
Harald Welte9176bd42009-07-23 18:46:00 +02003526 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003527 /* If subscriber is not found */
3528 if (!subscr) {
3529 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3530 "Received '%s' from MNCC with "
3531 "unknown subscriber %s\n", data->called.number,
3532 get_mncc_name(msg_type), data->called.number);
3533 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003534 return mncc_release_ind(net, NULL, data->callref,
3535 GSM48_CAUSE_LOC_PRN_S_LU,
3536 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003537 }
3538 /* If subscriber is not "attached" */
3539 if (!subscr->lac) {
3540 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3541 "Received '%s' from MNCC with "
3542 "detached subscriber %s\n", data->called.number,
3543 get_mncc_name(msg_type), data->called.number);
3544 subscr_put(subscr);
3545 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003546 return mncc_release_ind(net, NULL, data->callref,
3547 GSM48_CAUSE_LOC_PRN_S_LU,
3548 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003549 }
3550 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003551 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3552 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003553 DEBUGP(DCC, "No memory for trans.\n");
3554 subscr_put(subscr);
3555 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003556 mncc_release_ind(net, NULL, data->callref,
3557 GSM48_CAUSE_LOC_PRN_S_LU,
3558 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003559 return -ENOMEM;
3560 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003561 /* Find lchan */
Harald Welte1a6f7982009-08-09 18:52:33 +02003562 lchan = lchan_for_subscr(subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003563 /* If subscriber has no lchan */
3564 if (!lchan) {
3565 /* find transaction with this subscriber already paging */
3566 llist_for_each_entry(transt, &net->trans_list, entry) {
3567 /* Transaction of our lchan? */
3568 if (transt == trans ||
3569 transt->subscr != subscr)
3570 continue;
3571 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3572 "Received '%s' from MNCC with "
3573 "unallocated channel, paging already "
3574 "started.\n", bts->nr,
3575 data->called.number,
3576 get_mncc_name(msg_type));
3577 return 0;
3578 }
3579 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003580 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003581 /* Trigger paging */
3582 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3583 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003584 return 0;
3585 }
3586 /* Assign lchan */
3587 trans->lchan = lchan;
3588 use_lchan(lchan);
3589 }
3590 lchan = trans->lchan;
3591
3592 /* if paging did not respond yet */
3593 if (!lchan) {
3594 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3595 "Received '%s' from MNCC in paging state\n",
3596 (trans->subscr)?(trans->subscr->extension):"-",
3597 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003598 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3599 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003600 if (msg_type == MNCC_REL_REQ)
3601 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3602 else
3603 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3604 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003605 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003606 return rc;
3607 }
3608
3609 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3610 "Received '%s' from MNCC in state %d (%s)\n",
3611 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3612 trans->transaction_id,
3613 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003614 get_mncc_name(msg_type), trans->cc.state,
3615 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003616
3617 /* Find function for current state and message */
3618 for (i = 0; i < DOWNSLLEN; i++)
3619 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003620 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003621 break;
3622 if (i == DOWNSLLEN) {
3623 DEBUGP(DCC, "Message unhandled at this state.\n");
3624 return 0;
3625 }
3626
3627 rc = downstatelist[i].rout(trans, arg);
3628
3629 return rc;
3630}
3631
3632
3633static struct datastate {
3634 u_int32_t states;
3635 int type;
3636 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3637} datastatelist[] = {
3638 /* mobile originating call establishment */
3639 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3640 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3641 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3642 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3643 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3644 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3645 /* mobile terminating call establishment */
3646 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3647 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3648 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3649 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3650 {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 */
3651 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3652 /* signalling during call */
3653 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3654 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3655 {SBIT(GSM_CSTATE_ACTIVE),
3656 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3657 {ALL_STATES,
3658 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3659 {ALL_STATES,
3660 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3661 {ALL_STATES,
3662 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3663 {SBIT(GSM_CSTATE_ACTIVE),
3664 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3665 {SBIT(GSM_CSTATE_ACTIVE),
3666 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3667 {SBIT(GSM_CSTATE_ACTIVE),
3668 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3669 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3670 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3671 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3672 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3673 {SBIT(GSM_CSTATE_ACTIVE),
3674 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3675 /* clearing */
3676 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3677 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3678 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3679 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3680 {ALL_STATES, /* 5.4.3.4 */
3681 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3682};
3683
3684#define DATASLLEN \
3685 (sizeof(datastatelist) / sizeof(struct datastate))
3686
Harald Welte4bc90a12008-12-27 16:32:52 +00003687static int gsm0408_rcv_cc(struct msgb *msg)
3688{
3689 struct gsm48_hdr *gh = msgb_l3(msg);
3690 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003691 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003692 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003693 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003694 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003695
Harald Welte4bfdfe72009-06-10 23:11:52 +08003696 if (msg_type & 0x80) {
3697 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3698 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003699 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003700
3701 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003702 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003703
Harald Welte6f5aee02009-07-23 21:21:14 +02003704 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003705 "Received '%s' from MS in state %d (%s)\n",
3706 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3707 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003708 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3709 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003710
3711 /* Create transaction */
3712 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003713 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003714 "creating new trans.\n", transaction_id);
3715 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003716 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3717 transaction_id, new_callref++);
3718 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003719 DEBUGP(DCC, "No memory for trans.\n");
3720 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003721 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003722 GSM48_MT_CC_RELEASE_COMPL);
3723 return -ENOMEM;
3724 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003725 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003726 trans->lchan = lchan;
3727 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003728 }
3729
3730 /* find function for current state and message */
3731 for (i = 0; i < DATASLLEN; i++)
3732 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003733 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003734 break;
3735 if (i == DATASLLEN) {
3736 DEBUGP(DCC, "Message unhandled at this state.\n");
3737 return 0;
3738 }
3739
3740 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003741
3742 return rc;
3743}
3744
Harald Welte52b1f982008-12-23 20:25:15 +00003745/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3746int gsm0408_rcvmsg(struct msgb *msg)
3747{
3748 struct gsm48_hdr *gh = msgb_l3(msg);
3749 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003750 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003751
3752 switch (pdisc) {
3753 case GSM48_PDISC_CC:
3754 rc = gsm0408_rcv_cc(msg);
3755 break;
3756 case GSM48_PDISC_MM:
3757 rc = gsm0408_rcv_mm(msg);
3758 break;
3759 case GSM48_PDISC_RR:
3760 rc = gsm0408_rcv_rr(msg);
3761 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003762 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003763 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003764 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003765 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003766 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003767 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3768 pdisc);
3769 break;
3770 default:
3771 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3772 pdisc);
3773 break;
3774 }
3775
3776 return rc;
3777}
Harald Welte8470bf22008-12-25 23:28:35 +00003778
Harald Welte8470bf22008-12-25 23:28:35 +00003779/* Section 9.1.8 / Table 9.9 */
3780struct chreq {
3781 u_int8_t val;
3782 u_int8_t mask;
3783 enum chreq_type type;
3784};
3785
3786/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3787static const struct chreq chreq_type_neci1[] = {
3788 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3789 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3790 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3791 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3792 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3793 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3794 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3795 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3796 { 0x10, 0xf0, CHREQ_T_SDCCH },
3797 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3798 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3799 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3800};
3801
3802/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3803static const struct chreq chreq_type_neci0[] = {
3804 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3805 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3806 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3807 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3808 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3809 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3810 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3811 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3812};
3813
3814static const enum gsm_chan_t ctype_by_chreq[] = {
3815 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3816 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3817 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3818 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3819 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3820 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3821 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3822 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3823 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3824 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3825 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3826 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3827};
3828
Harald Weltee14a57c2008-12-29 04:08:28 +00003829static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3830 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3831 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3832 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3833 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3834 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3835 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3836 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3837 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3838 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3839 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3840 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3841 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3842};
3843
Harald Welte8470bf22008-12-25 23:28:35 +00003844enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3845{
3846 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003847 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Welte8470bf22008-12-25 23:28:35 +00003848
Harald Weltee58ca7c2009-08-10 02:14:46 +02003849 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3850 const struct chreq *chr = &chreq_type_neci0[i];
Harald Welte8470bf22008-12-25 23:28:35 +00003851 if ((ra & chr->mask) == chr->val)
3852 return ctype_by_chreq[chr->type];
3853 }
3854 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3855 return GSM_LCHAN_SDCCH;
3856}
Harald Weltee14a57c2008-12-29 04:08:28 +00003857
3858enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3859{
3860 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003861 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Weltee14a57c2008-12-29 04:08:28 +00003862
Harald Weltee58ca7c2009-08-10 02:14:46 +02003863 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3864 const struct chreq *chr = &chreq_type_neci0[i];
Harald Weltee14a57c2008-12-29 04:08:28 +00003865 if ((ra & chr->mask) == chr->val)
3866 return reason_by_chreq[chr->type];
3867 }
3868 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3869 return GSM_CHREQ_REASON_OTHER;
3870}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003871
3872/* dequeue messages to layer 4 */
3873int bsc_upqueue(struct gsm_network *net)
3874{
3875 struct gsm_mncc *mncc;
3876 struct msgb *msg;
3877 int work = 0;
3878
3879 if (net)
3880 while ((msg = msgb_dequeue(&net->upqueue))) {
3881 mncc = (struct gsm_mncc *)msg->data;
3882 if (net->mncc_recv)
3883 net->mncc_recv(net, mncc->msg_type, mncc);
3884 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003885 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003886 }
3887
3888 return work;
3889}
Harald Weltedcaf5652009-07-23 18:56:43 +02003890
Harald Welte805f6442009-07-28 18:25:29 +02003891/*
3892 * This will be ran by the linker when loading the DSO. We use it to
3893 * do system initialization, e.g. registration of signal handlers.
3894 */
3895static __attribute__((constructor)) void on_dso_load_0408(void)
3896{
3897 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3898 "loc_updating_oper");
3899 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3900 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3901}