blob: 98f2d56032c50e6ea126c06ae7a8e48ae51d2c3b [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
2 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
3
Harald Weltebf5e8df2009-02-03 12:59:45 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte498b0bb2009-01-09 21:27:43 +00005 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte8470bf22008-12-25 23:28:35 +00006 *
Harald Welte52b1f982008-12-23 20:25:15 +00007 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
Harald Weltedb253af2008-12-30 17:56:55 +000030#include <time.h>
Harald Welte4b634542008-12-27 01:55:51 +000031#include <netinet/in.h>
Harald Welte52b1f982008-12-23 20:25:15 +000032
Harald Welte75a983f2008-12-27 21:34:06 +000033#include <openbsc/db.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <openbsc/msgb.h>
Harald Welte7584aea2009-02-11 11:44:12 +000035#include <openbsc/tlv.h>
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <openbsc/debug.h>
37#include <openbsc/gsm_data.h>
38#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000039#include <openbsc/gsm_04_11.h>
Harald Welte8470bf22008-12-25 23:28:35 +000040#include <openbsc/gsm_04_08.h>
41#include <openbsc/abis_rsl.h>
Holger Freytherca362a62009-01-04 21:05:01 +000042#include <openbsc/chan_alloc.h>
Harald Welte0b4c34e2009-02-09 17:54:43 +000043#include <openbsc/paging.h>
Holger Freyther053e09d2009-02-14 22:51:06 +000044#include <openbsc/signal.h>
Harald Welte45b407a2009-05-23 15:51:12 +000045#include <openbsc/trau_frame.h>
Harald Welte11fa29c2009-02-19 17:24:39 +000046#include <openbsc/trau_mux.h>
Harald Welte805f6442009-07-28 18:25:29 +020047#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020048#include <openbsc/talloc.h>
Harald Weltedcaf5652009-07-23 18:56:43 +020049#include <openbsc/transaction.h>
Harald Welte52b1f982008-12-23 20:25:15 +000050
Harald Welte8470bf22008-12-25 23:28:35 +000051#define GSM48_ALLOC_SIZE 1024
52#define GSM48_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000053
Harald Welte0c389302009-06-10 12:08:54 +080054#define GSM_MAX_FACILITY 128
55#define GSM_MAX_SSVERSION 128
56#define GSM_MAX_USERUSER 128
57
Harald Welte2cf161b2009-06-20 22:36:41 +020058static void *tall_locop_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020059
Harald Welte805f6442009-07-28 18:25:29 +020060/* should ip.access BTS use direct RTP streams between each other (1),
61 * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
62int ipacc_rtp_direct = 1;
63
Harald Welte09e38af2009-02-16 22:52:23 +000064static const struct tlv_definition rsl_att_tlvdef = {
65 .def = {
66 [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
67 [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
68 [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
69 [GSM48_IE_UTC] = { TLV_TYPE_TV },
70 [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
71 [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
72
73 [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
74 [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
75 [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
76 [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
77 [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
78 [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
79 [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
Harald Welte0c389302009-06-10 12:08:54 +080080 [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
Harald Welte09e38af2009-02-16 22:52:23 +000081 [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
82 [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
Harald Welte0c389302009-06-10 12:08:54 +080083 [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
84 [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
Harald Welte09e38af2009-02-16 22:52:23 +000085 [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
86 [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
87 [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
88 [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
89 [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
90 [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
91 [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
92 [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
93 [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
94 [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
95 [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
96 [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
97 [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
98 [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
Harald Welte0c389302009-06-10 12:08:54 +080099 [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
100 [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
Harald Welte09e38af2009-02-16 22:52:23 +0000101 /* FIXME: more elements */
102 },
103};
Harald Weltecf5b3592009-05-01 18:28:42 +0000104
105static const char *rr_cause_names[] = {
106 [GSM48_RR_CAUSE_NORMAL] = "Normal event",
107 [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
108 [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
109 [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
110 [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
111 [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
112 [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
113 [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
114 [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
115 [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
116 [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
117 [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
118 [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
119 [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
120 [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
121 [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
122 [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
123};
124
Harald Welte4bfdfe72009-06-10 23:11:52 +0800125static const char *cc_state_names[] = {
126 "NULL",
127 "INITIATED",
128 "illegal state 2",
129 "MO_CALL_PROC",
130 "CALL_DELIVERED",
131 "illegal state 5",
132 "CALL_PRESENT",
133 "CALL_RECEIVED",
134 "CONNECT_REQUEST",
135 "MO_TERM_CALL_CONF",
136 "ACTIVE",
137 "DISCONNECT_REQ",
138 "DISCONNECT_IND",
139 "illegal state 13",
140 "illegal state 14",
141 "illegal state 15",
142 "illegal state 16",
143 "illegal state 17",
144 "illegal state 18",
145 "RELEASE_REQ",
146 "illegal state 20",
147 "illegal state 21",
148 "illegal state 22",
149 "illegal state 23",
150 "illegal state 24",
151 "illegal state 25",
152 "MO_ORIG_MODIFY",
153 "MO_TERM_MODIFY",
154 "CONNECT_IND",
155 "illegal state 29",
156 "illegal state 30",
157 "illegal state 31",
158};
159
160static const char *cc_msg_names[] = {
161 "unknown 0x00",
162 "ALERTING",
163 "CALL_PROC",
164 "PROGRESS",
165 "ESTAB",
166 "SETUP",
167 "ESTAB_CONF",
168 "CONNECT",
169 "CALL_CONF",
170 "START_CC",
171 "unknown 0x0a",
172 "RECALL",
173 "unknown 0x0c",
174 "unknown 0x0d",
175 "EMERG_SETUP",
176 "CONNECT_ACK",
177 "USER_INFO",
178 "unknown 0x11",
179 "unknown 0x12",
180 "MODIFY_REJECT",
181 "unknown 0x14",
182 "unknown 0x15",
183 "unknown 0x16",
184 "MODIFY",
185 "HOLD",
186 "HOLD_ACK",
187 "HOLD_REJ",
188 "unknown 0x1b",
189 "RETR",
190 "RETR_ACK",
191 "RETR_REJ",
192 "MODIFY_COMPL",
193 "unknown 0x20",
194 "unknown 0x21",
195 "unknown 0x22",
196 "unknown 0x23",
197 "unknown 0x24",
198 "DISCONNECT",
199 "unknown 0x26",
200 "unknown 0x27",
201 "unknown 0x28",
202 "unknown 0x29",
203 "RELEASE_COMPL",
204 "unknown 0x2b",
205 "unknown 0x2c",
206 "RELEASE",
207 "unknown 0x2e",
208 "unknown 0x2f",
209 "unknown 0x30",
210 "STOP_DTMF",
211 "STOP_DTMF_ACK",
212 "unknown 0x33",
213 "STATUS_ENQ",
214 "START_DTMF",
215 "START_DTMF_ACK",
216 "START_DTMF_REJ",
217 "unknown 0x38",
218 "CONG_CTRL",
219 "FACILITY",
220 "unknown 0x3b",
221 "STATUS",
222 "unknown 0x3c",
223 "NOTIFY",
224 "unknown 0x3f",
225};
226
Harald Weltecf5b3592009-05-01 18:28:42 +0000227static char strbuf[64];
228
229static const char *rr_cause_name(u_int8_t cause)
230{
231 if (cause < ARRAY_SIZE(rr_cause_names) &&
232 rr_cause_names[cause])
233 return rr_cause_names[cause];
234
235 snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
236 return strbuf;
237}
238
Harald Weltef7c43522009-06-09 20:24:21 +0000239static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
240 int len)
241{
242 memset(rep, 0, sizeof(*rep));
243
244 if (data[0] & 0x80)
245 rep->flags |= MEAS_REP_F_BA1;
246 if (data[0] & 0x40)
247 rep->flags |= MEAS_REP_F_DTX;
Harald Welte5a691b52009-07-05 04:05:44 +0200248 if ((data[1] & 0x40) == 0x00)
Harald Weltef7c43522009-06-09 20:24:21 +0000249 rep->flags |= MEAS_REP_F_VALID;
250
251 rep->rxlev_full = data[0] & 0x3f;
252 rep->rxlev_sub = data[1] & 0x3f;
253 rep->rxqual_full = (data[3] >> 4) & 0x7;
254 rep->rxqual_sub = (data[3] >> 1) & 0x7;
255 rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2);
256 if (rep->num_cell < 1)
257 return;
258
259 /* an encoding nightmare in perfection */
260
261 rep->cell[0].rxlev = data[4] & 0x3f;
262 rep->cell[0].bcch_freq = data[5] >> 2;
263 rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5);
264 if (rep->num_cell < 2)
265 return;
266
267 rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7);
268 rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f;
269 rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4);
270 if (rep->num_cell < 3)
271 return;
272
273 rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6);
274 rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f;
275 rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3);
276 if (rep->num_cell < 4)
277 return;
278
279 rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5);
280 rep->cell[3].bcch_freq = data[11] & 0x1f;
281 rep->cell[3].bsic = data[12] >> 2;
282 if (rep->num_cell < 5)
283 return;
284
285 rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4);
286 rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7);
287 rep->cell[4].bsic = (data[14] >> 1) & 0x3f;
288 if (rep->num_cell < 6)
289 return;
290
291 rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3);
292 rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6);
293 rep->cell[5].bsic = data[16] & 0x3f;
294}
295
Holger Freytherd51524f2009-06-09 08:27:07 +0000296int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
Harald Welte65e74cc2008-12-29 01:55:35 +0000297static int gsm48_tx_simple(struct gsm_lchan *lchan,
298 u_int8_t pdisc, u_int8_t msg_type);
Holger Freytherb7193e42008-12-29 17:44:08 +0000299static void schedule_reject(struct gsm_lchan *lchan);
Harald Welte65e74cc2008-12-29 01:55:35 +0000300
Harald Welte52b1f982008-12-23 20:25:15 +0000301struct gsm_lai {
302 u_int16_t mcc;
303 u_int16_t mnc;
304 u_int16_t lac;
305};
306
Holger Freythere97f7fb2008-12-31 18:52:11 +0000307static int reject_cause = 0;
308void gsm0408_set_reject_cause(int cause)
309{
310 reject_cause = cause;
311}
312
Harald Welte4bfdfe72009-06-10 23:11:52 +0800313static u_int32_t new_callref = 0x80000001;
314
Holger Freyther73487a22008-12-31 18:53:57 +0000315static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
316 struct gsm_subscriber *subscriber)
Holger Freyther89824fc2008-12-30 16:18:18 +0000317{
318 if (!subscriber)
319 return 0;
320
Holger Freyther73487a22008-12-31 18:53:57 +0000321 /*
322 * Do not send accept yet as more information should arrive. Some
323 * phones will not send us the information and we will have to check
324 * what we want to do with that.
325 */
326 if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
327 return 0;
328
Jan Luebbe06513f22009-08-12 12:48:00 +0200329 switch (subscriber->net->auth_policy) {
330 case GSM_AUTH_POLICY_CLOSED:
331 return subscriber->authorized;
Harald Welte (local)aa9dc192009-08-13 13:49:51 +0200332 case GSM_AUTH_POLICY_TOKEN:
333 return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
Jan Luebbe06513f22009-08-12 12:48:00 +0200334 case GSM_AUTH_POLICY_ACCEPT_ALL:
Holger Freyther89824fc2008-12-30 16:18:18 +0000335 return 1;
Jan Luebbe06513f22009-08-12 12:48:00 +0200336 default:
337 return 0;
338 }
Holger Freyther89824fc2008-12-30 16:18:18 +0000339}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000340
Holger Freyther73487a22008-12-31 18:53:57 +0000341static void release_loc_updating_req(struct gsm_lchan *lchan)
342{
Harald Welte179f0642008-12-31 23:59:18 +0000343 if (!lchan->loc_operation)
Holger Freyther73487a22008-12-31 18:53:57 +0000344 return;
345
Harald Welteff117a82009-05-23 05:22:08 +0000346 bsc_del_timer(&lchan->loc_operation->updating_timer);
Harald Welte2cf161b2009-06-20 22:36:41 +0200347 talloc_free(lchan->loc_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000348 lchan->loc_operation = 0;
Holger Freyther3eaa7922009-01-01 02:59:03 +0000349 put_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000350}
351
352static void allocate_loc_updating_req(struct gsm_lchan *lchan)
353{
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000354 use_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000355 release_loc_updating_req(lchan);
356
Harald Welte470ec292009-06-26 20:25:23 +0200357 lchan->loc_operation = talloc_zero(tall_locop_ctx,
358 struct gsm_loc_updating_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000359}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000360
Holger Freytherd51524f2009-06-09 08:27:07 +0000361static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
362{
363 u_int32_t tmsi;
364
365 if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
Harald Welteee5ad162009-08-09 19:07:00 +0200366 int rc;
367
Holger Freytherd51524f2009-06-09 08:27:07 +0000368 db_subscriber_alloc_tmsi(lchan->subscr);
Holger Freytherd51524f2009-06-09 08:27:07 +0000369 tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
370 release_loc_updating_req(lchan);
Harald Welteee5ad162009-08-09 19:07:00 +0200371 rc = gsm0408_loc_upd_acc(msg->lchan, tmsi);
372 /* call subscr_update after putting the loc_upd_acc
373 * in the transmit queue, since S_SUBSCR_ATTACHED might
374 * trigger further action like SMS delivery */
375 subscr_update(lchan->subscr, msg->trx->bts,
376 GSM_SUBSCRIBER_UPDATE_ATTACHED);
377 return rc;
Holger Freytherd51524f2009-06-09 08:27:07 +0000378 }
379
380 return 0;
381}
382
Holger Freyther7c19f742009-06-06 13:54:35 +0000383static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
384 void *handler_data, void *signal_data)
385{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800386 struct gsm_trans *trans, *temp;
387
Holger Freyther7c19f742009-06-06 13:54:35 +0000388 if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
389 return 0;
390
391 /*
392 * Cancel any outstanding location updating request
393 * operation taking place on the lchan.
394 */
Harald Welte1a5c6bd2009-07-04 09:35:21 +0200395 struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
Harald Weltec05677b2009-06-26 20:17:06 +0200396 if (!lchan)
397 return 0;
398
Holger Freyther7c19f742009-06-06 13:54:35 +0000399 release_loc_updating_req(lchan);
400
Harald Welte4bfdfe72009-06-10 23:11:52 +0800401 /* Free all transactions that are associated with the released lchan */
Harald Weltedcaf5652009-07-23 18:56:43 +0200402 /* FIXME: this is not neccessarily the right thing to do, we should
403 * only set trans->lchan to NULL and wait for another lchan to be
404 * established to the same MM entity (phone/subscriber) */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800405 llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
406 if (trans->lchan == lchan)
Harald Weltedcaf5652009-07-23 18:56:43 +0200407 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800408 }
409
Holger Freyther7c19f742009-06-06 13:54:35 +0000410 return 0;
411}
412
Harald Welte52b1f982008-12-23 20:25:15 +0000413static void to_bcd(u_int8_t *bcd, u_int16_t val)
414{
Harald Welte4b634542008-12-27 01:55:51 +0000415 bcd[2] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000416 val = val / 10;
417 bcd[1] = val % 10;
418 val = val / 10;
Harald Welte4b634542008-12-27 01:55:51 +0000419 bcd[0] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000420 val = val / 10;
421}
422
Holger Freyther17746612008-12-28 16:32:44 +0000423void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
Harald Welte52b1f982008-12-23 20:25:15 +0000424 u_int16_t mnc, u_int16_t lac)
425{
426 u_int8_t bcd[3];
427
428 to_bcd(bcd, mcc);
429 lai48->digits[0] = bcd[0] | (bcd[1] << 4);
430 lai48->digits[1] = bcd[2];
431
432 to_bcd(bcd, mnc);
Harald Welte4b634542008-12-27 01:55:51 +0000433 /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
434#if 0
Harald Welte8470bf22008-12-25 23:28:35 +0000435 lai48->digits[1] |= bcd[2] << 4;
436 lai48->digits[2] = bcd[0] | (bcd[1] << 4);
Harald Welte4b634542008-12-27 01:55:51 +0000437#else
438 lai48->digits[1] |= 0xf << 4;
439 lai48->digits[2] = bcd[1] | (bcd[2] << 4);
440#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000441
Harald Welte4b634542008-12-27 01:55:51 +0000442 lai48->lac = htons(lac);
Harald Welte52b1f982008-12-23 20:25:15 +0000443}
444
Harald Welte255539c2008-12-28 02:26:27 +0000445#define TMSI_LEN 5
Harald Welte52b1f982008-12-23 20:25:15 +0000446#define MID_TMSI_LEN (TMSI_LEN + 2)
447
Harald Welte255539c2008-12-28 02:26:27 +0000448int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +0000449{
Harald Welte65e74cc2008-12-29 01:55:35 +0000450 u_int32_t *tptr = (u_int32_t *) &buf[3];
Harald Welte255539c2008-12-28 02:26:27 +0000451
Harald Welte4b634542008-12-27 01:55:51 +0000452 buf[0] = GSM48_IE_MOBILE_ID;
Harald Welte1a412182008-12-27 22:13:43 +0000453 buf[1] = TMSI_LEN;
Harald Welte4b634542008-12-27 01:55:51 +0000454 buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
Harald Welte255539c2008-12-28 02:26:27 +0000455 *tptr = htonl(tmsi);
456
457 return 7;
Harald Welte52b1f982008-12-23 20:25:15 +0000458}
459
Harald Welte09e38af2009-02-16 22:52:23 +0000460static const char bcd_num_digits[] = {
461 '0', '1', '2', '3', '4', '5', '6', '7',
462 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
463};
464
Harald Welte0c389302009-06-10 12:08:54 +0800465/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
466int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
467 int h_len)
Harald Welte09e38af2009-02-16 22:52:23 +0000468{
469 u_int8_t in_len = bcd_lv[0];
470 int i;
471
Harald Welte0c389302009-06-10 12:08:54 +0800472 for (i = 1 + h_len; i <= in_len; i++) {
Harald Welte09e38af2009-02-16 22:52:23 +0000473 /* lower nibble */
474 output_len--;
475 if (output_len <= 1)
476 break;
477 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
478
479 /* higher nibble */
480 output_len--;
481 if (output_len <= 1)
482 break;
483 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
484 }
485 if (output_len >= 1)
486 *output++ = '\0';
487
Harald Welte0c389302009-06-10 12:08:54 +0800488 return 0;
Harald Welte09e38af2009-02-16 22:52:23 +0000489}
490
491/* convert a single ASCII character to call-control BCD */
492static int asc_to_bcd(const char asc)
493{
494 int i;
495
496 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
497 if (bcd_num_digits[i] == asc)
498 return i;
499 }
500 return -EINVAL;
501}
502
Harald Welte0c389302009-06-10 12:08:54 +0800503/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
Harald Welte09e38af2009-02-16 22:52:23 +0000504int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
Harald Welte0c389302009-06-10 12:08:54 +0800505 int h_len, const char *input)
Harald Welte09e38af2009-02-16 22:52:23 +0000506{
507 int in_len = strlen(input);
508 int i;
Harald Welte0c389302009-06-10 12:08:54 +0800509 u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000510
511 /* two digits per byte, plus type byte */
Harald Welte0c389302009-06-10 12:08:54 +0800512 bcd_lv[0] = in_len/2 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000513 if (in_len % 2)
514 bcd_lv[0]++;
515
Harald Welte0c389302009-06-10 12:08:54 +0800516 if (bcd_lv[0] > max_len)
517 return -EIO;
Harald Welte09e38af2009-02-16 22:52:23 +0000518
519 for (i = 0; i < in_len; i++) {
520 int rc = asc_to_bcd(input[i]);
521 if (rc < 0)
522 return rc;
523 if (i % 2 == 0)
524 *bcd_cur = rc;
525 else
526 *bcd_cur++ |= (rc << 4);
527 }
528 /* append padding nibble in case of odd length */
529 if (i % 2)
530 *bcd_cur++ |= 0xf0;
531
532 /* return how many bytes we used */
533 return (bcd_cur - bcd_lv);
534}
535
Harald Welte0c389302009-06-10 12:08:54 +0800536/* decode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800537static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
Harald Welte0c389302009-06-10 12:08:54 +0800538 const u_int8_t *lv)
539{
540 u_int8_t in_len = lv[0];
541 int i, s;
542
543 if (in_len < 1)
544 return -EINVAL;
545
Harald Welte4bfdfe72009-06-10 23:11:52 +0800546 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
Harald Welte0c389302009-06-10 12:08:54 +0800547
548 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800549 bcap->transfer = lv[1] & 0x07;
550 bcap->mode = (lv[1] & 0x08) >> 3;
551 bcap->coding = (lv[1] & 0x10) >> 4;
552 bcap->radio = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800553
554 i = 1;
555 s = 0;
556 while(!(lv[i] & 0x80)) {
557 i++; /* octet 3a etc */
558 if (in_len < i)
559 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800560 bcap->speech_ver[s++] = lv[i] & 0x0f;
561 bcap->speech_ver[s] = -1; /* end of list */
Harald Welte0c389302009-06-10 12:08:54 +0800562 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800563 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800564 if (s == 7) /* maximum speech versions + end of list */
565 return 0;
566 }
567
568 return 0;
569}
570
571/* encode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800572static int encode_bearer_cap(struct msgb *msg, int lv_only,
573 const struct gsm_mncc_bearer_cap *bcap)
Harald Welte0c389302009-06-10 12:08:54 +0800574{
575 u_int8_t lv[32 + 1];
576 int i, s;
577
Harald Welte4bfdfe72009-06-10 23:11:52 +0800578 lv[1] = bcap->transfer;
579 lv[1] |= bcap->mode << 3;
580 lv[1] |= bcap->coding << 4;
581 lv[1] |= bcap->radio << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800582
583 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800584 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
Harald Welte0c389302009-06-10 12:08:54 +0800585 i++; /* octet 3a etc */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800586 lv[i] = bcap->speech_ver[s];
Harald Welte0c389302009-06-10 12:08:54 +0800587 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800588 lv[i] |= bcap->speech_ctm << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800589 }
590 lv[i] |= 0x80; /* last IE of octet 3 etc */
591
592 lv[0] = i;
593 if (lv_only)
594 msgb_lv_put(msg, lv[0], lv+1);
595 else
596 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
597
598 return 0;
599}
600
601/* decode 'call control cap' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800602static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800603{
604 u_int8_t in_len = lv[0];
605
606 if (in_len < 1)
607 return -EINVAL;
608
609 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800610 ccap->dtmf = lv[1] & 0x01;
611 ccap->pcp = (lv[1] & 0x02) >> 1;
Harald Welte0c389302009-06-10 12:08:54 +0800612
613 return 0;
614}
615
616/* decode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800617static int decode_called(struct gsm_mncc_number *called,
618 const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800619{
620 u_int8_t in_len = lv[0];
621
622 if (in_len < 1)
623 return -EINVAL;
624
625 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800626 called->plan = lv[1] & 0x0f;
627 called->type = (lv[1] & 0x70) >> 4;
Harald Welte0c389302009-06-10 12:08:54 +0800628
629 /* octet 4..N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800630 decode_bcd_number(called->number, sizeof(called->number), lv, 1);
Harald Welte0c389302009-06-10 12:08:54 +0800631
632 return 0;
633}
634
635/* encode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800636static int encode_called(struct msgb *msg,
637 const struct gsm_mncc_number *called)
Harald Welte0c389302009-06-10 12:08:54 +0800638{
639 u_int8_t lv[18];
640 int ret;
641
642 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800643 lv[1] = called->plan;
644 lv[1] |= called->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800645
646 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800647 ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
Harald Welte0c389302009-06-10 12:08:54 +0800648 if (ret < 0)
649 return ret;
650
651 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
652
653 return 0;
654}
655
656/* encode callerid of various IEs */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800657static int encode_callerid(struct msgb *msg, int ie,
658 const struct gsm_mncc_number *callerid)
Harald Welte0c389302009-06-10 12:08:54 +0800659{
660 u_int8_t lv[13];
661 int h_len = 1;
662 int ret;
663
664 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800665 lv[1] = callerid->plan;
666 lv[1] |= callerid->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800667
Harald Welte4bfdfe72009-06-10 23:11:52 +0800668 if (callerid->present || callerid->screen) {
Harald Welte0c389302009-06-10 12:08:54 +0800669 /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800670 lv[2] = callerid->screen;
671 lv[2] |= callerid->present << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800672 lv[2] |= 0x80;
673 h_len++;
674 } else
675 lv[1] |= 0x80;
676
677 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800678 ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
Harald Welte0c389302009-06-10 12:08:54 +0800679 if (ret < 0)
680 return ret;
681
682 msgb_tlv_put(msg, ie, lv[0], lv+1);
683
684 return 0;
685}
686
687/* decode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800688static int decode_cause(struct gsm_mncc_cause *cause,
Harald Welte0c389302009-06-10 12:08:54 +0800689 const u_int8_t *lv)
690{
691 u_int8_t in_len = lv[0];
692 int i;
693
694 if (in_len < 2)
695 return -EINVAL;
696
Harald Welte4bfdfe72009-06-10 23:11:52 +0800697 cause->diag_len = 0;
Harald Welte0c389302009-06-10 12:08:54 +0800698
699 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800700 cause->location = lv[1] & 0x0f;
701 cause->coding = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800702
703 i = 1;
704 if (!(lv[i] & 0x80)) {
705 i++; /* octet 3a */
706 if (in_len < i+1)
707 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800708 cause->rec = 1;
709 cause->rec_val = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800710
711 }
712 i++;
713
714 /* octet 4 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800715 cause->value = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800716 i++;
717
718 if (in_len < i) /* no diag */
719 return 0;
720
721 if (in_len - (i-1) > 32) /* maximum 32 octets */
722 return 0;
723
724 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800725 memcpy(cause->diag, lv + i, in_len - (i-1));
726 cause->diag_len = in_len - (i-1);
Harald Welte0c389302009-06-10 12:08:54 +0800727
728 return 0;
729}
730
731/* encode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800732static int encode_cause(struct msgb *msg, int lv_only,
733 const struct gsm_mncc_cause *cause)
Harald Welte0c389302009-06-10 12:08:54 +0800734{
735 u_int8_t lv[32+4];
736 int i;
737
Harald Welte4bfdfe72009-06-10 23:11:52 +0800738 if (cause->diag_len > 32)
Harald Welte0c389302009-06-10 12:08:54 +0800739 return -EINVAL;
740
741 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800742 lv[1] = cause->location;
743 lv[1] |= cause->coding << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800744
745 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800746 if (cause->rec) {
Harald Welte0c389302009-06-10 12:08:54 +0800747 i++; /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800748 lv[i] = cause->rec_val;
Harald Welte0c389302009-06-10 12:08:54 +0800749 }
750 lv[i] |= 0x80; /* end of octet 3 */
751
752 /* octet 4 */
753 i++;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800754 lv[i] = 0x80 | cause->value;
Harald Welte0c389302009-06-10 12:08:54 +0800755
756 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800757 if (cause->diag_len) {
758 memcpy(lv + i, cause->diag, cause->diag_len);
759 i += cause->diag_len;
Harald Welte0c389302009-06-10 12:08:54 +0800760 }
761
762 lv[0] = i;
763 if (lv_only)
764 msgb_lv_put(msg, lv[0], lv+1);
765 else
766 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
767
768 return 0;
769}
770
771/* encode 'calling number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800772static int encode_calling(struct msgb *msg,
773 const struct gsm_mncc_number *calling)
Harald Welte0c389302009-06-10 12:08:54 +0800774{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800775 return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
Harald Welte0c389302009-06-10 12:08:54 +0800776}
777
778/* encode 'connected number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800779static int encode_connected(struct msgb *msg,
780 const struct gsm_mncc_number *connected)
Harald Welte0c389302009-06-10 12:08:54 +0800781{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800782 return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
Harald Welte0c389302009-06-10 12:08:54 +0800783}
784
785/* encode 'redirecting number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800786static int encode_redirecting(struct msgb *msg,
787 const struct gsm_mncc_number *redirecting)
Harald Welte0c389302009-06-10 12:08:54 +0800788{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800789 return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
Harald Welte0c389302009-06-10 12:08:54 +0800790}
791
792/* decode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800793static int decode_facility(struct gsm_mncc_facility *facility,
Harald Welte0c389302009-06-10 12:08:54 +0800794 const u_int8_t *lv)
795{
796 u_int8_t in_len = lv[0];
797
798 if (in_len < 1)
799 return -EINVAL;
800
Harald Welte4bfdfe72009-06-10 23:11:52 +0800801 if (in_len > sizeof(facility->info))
Harald Welte0c389302009-06-10 12:08:54 +0800802 return -EINVAL;
803
Harald Welte4bfdfe72009-06-10 23:11:52 +0800804 memcpy(facility->info, lv+1, in_len);
805 facility->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800806
807 return 0;
808}
809
810/* encode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800811static int encode_facility(struct msgb *msg, int lv_only,
812 const struct gsm_mncc_facility *facility)
Harald Welte0c389302009-06-10 12:08:54 +0800813{
814 u_int8_t lv[GSM_MAX_FACILITY + 1];
815
Harald Welte4bfdfe72009-06-10 23:11:52 +0800816 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
Harald Welte0c389302009-06-10 12:08:54 +0800817 return -EINVAL;
818
Harald Welte4bfdfe72009-06-10 23:11:52 +0800819 memcpy(lv+1, facility->info, facility->len);
820 lv[0] = facility->len;
Harald Welte0c389302009-06-10 12:08:54 +0800821 if (lv_only)
822 msgb_lv_put(msg, lv[0], lv+1);
823 else
824 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
825
826 return 0;
827}
828
829/* decode 'notify' */
830static int decode_notify(int *notify, const u_int8_t *v)
831{
832 *notify = v[0] & 0x7f;
833
834 return 0;
835}
836
837/* encode 'notify' */
838static int encode_notify(struct msgb *msg, int notify)
839{
840 msgb_v_put(msg, notify | 0x80);
841
842 return 0;
843}
844
845/* encode 'signal' */
846static int encode_signal(struct msgb *msg, int signal)
847{
848 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
849
850 return 0;
851}
852
853/* decode 'keypad' */
854static int decode_keypad(int *keypad, const u_int8_t *lv)
855{
856 u_int8_t in_len = lv[0];
857
858 if (in_len < 1)
859 return -EINVAL;
860
861 *keypad = lv[1] & 0x7f;
862
863 return 0;
864}
865
866/* encode 'keypad' */
867static int encode_keypad(struct msgb *msg, int keypad)
868{
869 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
870
871 return 0;
872}
873
874/* decode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800875static int decode_progress(struct gsm_mncc_progress *progress,
Harald Welte0c389302009-06-10 12:08:54 +0800876 const u_int8_t *lv)
877{
878 u_int8_t in_len = lv[0];
879
880 if (in_len < 2)
881 return -EINVAL;
882
Harald Welte4bfdfe72009-06-10 23:11:52 +0800883 progress->coding = (lv[1] & 0x60) >> 5;
884 progress->location = lv[1] & 0x0f;
885 progress->descr = lv[2] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800886
887 return 0;
888}
889
890/* encode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800891static int encode_progress(struct msgb *msg, int lv_only,
892 const struct gsm_mncc_progress *p)
Harald Welte0c389302009-06-10 12:08:54 +0800893{
894 u_int8_t lv[3];
895
896 lv[0] = 2;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800897 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
898 lv[2] = 0x80 | (p->descr & 0x7f);
Harald Welte0c389302009-06-10 12:08:54 +0800899 if (lv_only)
900 msgb_lv_put(msg, lv[0], lv+1);
901 else
902 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
903
904 return 0;
905}
906
907/* decode 'user-user' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800908static int decode_useruser(struct gsm_mncc_useruser *uu,
Harald Welte0c389302009-06-10 12:08:54 +0800909 const u_int8_t *lv)
910{
911 u_int8_t in_len = lv[0];
Harald Welte4bfdfe72009-06-10 23:11:52 +0800912 char *info = uu->info;
913 int info_len = sizeof(uu->info);
Harald Welte0c389302009-06-10 12:08:54 +0800914 int i;
915
916 if (in_len < 1)
917 return -EINVAL;
918
Harald Welte4bfdfe72009-06-10 23:11:52 +0800919 uu->proto = lv[1];
Harald Welte0c389302009-06-10 12:08:54 +0800920
921 for (i = 2; i <= in_len; i++) {
922 info_len--;
923 if (info_len <= 1)
924 break;
925 *info++ = lv[i];
926 }
927 if (info_len >= 1)
928 *info++ = '\0';
929
930 return 0;
931}
932
933/* encode 'useruser' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800934static int encode_useruser(struct msgb *msg, int lv_only,
935 const struct gsm_mncc_useruser *uu)
Harald Welte0c389302009-06-10 12:08:54 +0800936{
937 u_int8_t lv[GSM_MAX_USERUSER + 2];
938
Harald Welte4bfdfe72009-06-10 23:11:52 +0800939 if (strlen(uu->info) > GSM_MAX_USERUSER)
Harald Welte0c389302009-06-10 12:08:54 +0800940 return -EINVAL;
941
Harald Welte4bfdfe72009-06-10 23:11:52 +0800942 lv[0] = 1 + strlen(uu->info);
943 lv[1] = uu->proto;
944 memcpy(lv + 2, uu->info, strlen(uu->info));
Harald Welte0c389302009-06-10 12:08:54 +0800945 if (lv_only)
946 msgb_lv_put(msg, lv[0], lv+1);
947 else
948 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
949
950 return 0;
951}
952
953/* decode 'ss version' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800954static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
Harald Welte0c389302009-06-10 12:08:54 +0800955 const u_int8_t *lv)
956{
957 u_int8_t in_len = lv[0];
958
Harald Welte4bfdfe72009-06-10 23:11:52 +0800959 if (in_len < 1 || in_len < sizeof(ssv->info))
Harald Welte0c389302009-06-10 12:08:54 +0800960 return -EINVAL;
961
Harald Welte4bfdfe72009-06-10 23:11:52 +0800962 memcpy(ssv->info, lv + 1, in_len);
963 ssv->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800964
965 return 0;
966}
967
968/* encode 'more data' */
969static int encode_more(struct msgb *msg)
970{
971 u_int8_t *ie;
972
973 ie = msgb_put(msg, 1);
974 ie[0] = GSM48_IE_MORE_DATA;
975
976 return 0;
977}
978
Holger Freyther819dd202009-01-04 03:52:50 +0000979struct msgb *gsm48_msgb_alloc(void)
Harald Welte8470bf22008-12-25 23:28:35 +0000980{
Harald Welte966636f2009-06-26 19:39:35 +0200981 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
982 "GSM 04.08");
Harald Welte8470bf22008-12-25 23:28:35 +0000983}
984
Harald Welte39e2ead2009-07-23 21:13:03 +0200985int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
Harald Welte52b1f982008-12-23 20:25:15 +0000986{
Harald Welte39e2ead2009-07-23 21:13:03 +0200987 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
988
989 /* if we get passed a transaction reference, do some common
990 * work that the caller no longer has to do */
991 if (trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +0200992 gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
Harald Welte39e2ead2009-07-23 21:13:03 +0200993 msg->lchan = trans->lchan;
994 }
995
Harald Welte65e74cc2008-12-29 01:55:35 +0000996 if (msg->lchan) {
Harald Welte8470bf22008-12-25 23:28:35 +0000997 msg->trx = msg->lchan->ts->trx;
Harald Welte52b1f982008-12-23 20:25:15 +0000998
Harald Welte4bfdfe72009-06-10 23:11:52 +0800999 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
1000 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
1001 "Sending '%s' to MS.\n", msg->trx->bts->nr,
1002 msg->trx->nr, msg->lchan->ts->nr,
1003 gh->proto_discr & 0xf0,
1004 cc_msg_names[gh->msg_type & 0x3f]);
1005 else
1006 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
1007 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
1008 msg->trx->nr, msg->lchan->ts->nr,
1009 gh->proto_discr, gh->msg_type);
Harald Welte65e74cc2008-12-29 01:55:35 +00001010 }
1011
Harald Welte4b634542008-12-27 01:55:51 +00001012 msg->l3h = msg->data;
1013
Harald Welte8470bf22008-12-25 23:28:35 +00001014 return rsl_data_request(msg, 0);
Harald Welte52b1f982008-12-23 20:25:15 +00001015}
1016
Holger Freyther429e7762008-12-30 13:28:30 +00001017/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
Harald Welte8470bf22008-12-25 23:28:35 +00001018int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
Harald Welte52b1f982008-12-23 20:25:15 +00001019{
Harald Welte8470bf22008-12-25 23:28:35 +00001020 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001021 struct gsm48_hdr *gh;
1022
Harald Welte8470bf22008-12-25 23:28:35 +00001023 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001024
1025 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1026 gh->proto_discr = GSM48_PDISC_MM;
Harald Welte10b487b2008-12-27 19:53:37 +00001027 gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
Harald Welte52b1f982008-12-23 20:25:15 +00001028 gh->data[0] = cause;
1029
Harald Weltedb253af2008-12-30 17:56:55 +00001030 DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
1031
Harald Welte39e2ead2009-07-23 21:13:03 +02001032 return gsm48_sendmsg(msg, NULL);
Harald Welte52b1f982008-12-23 20:25:15 +00001033}
1034
1035/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
Harald Welte75a983f2008-12-27 21:34:06 +00001036int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +00001037{
Harald Welte8470bf22008-12-25 23:28:35 +00001038 struct gsm_bts *bts = lchan->ts->trx->bts;
1039 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001040 struct gsm48_hdr *gh;
1041 struct gsm48_loc_area_id *lai;
1042 u_int8_t *mid;
Holger Freyther07cc8d82008-12-29 06:23:46 +00001043 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001044
Harald Welte8470bf22008-12-25 23:28:35 +00001045 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001046
1047 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1048 gh->proto_discr = GSM48_PDISC_MM;
1049 gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
1050
1051 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
Holger Freyther17746612008-12-28 16:32:44 +00001052 gsm0408_generate_lai(lai, bts->network->country_code,
Harald Welte52b1f982008-12-23 20:25:15 +00001053 bts->network->network_code, bts->location_area_code);
1054
1055 mid = msgb_put(msg, MID_TMSI_LEN);
1056 generate_mid_from_tmsi(mid, tmsi);
1057
1058 DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
1059
Harald Welte39e2ead2009-07-23 21:13:03 +02001060 ret = gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001061
Harald Welteee5ad162009-08-09 19:07:00 +02001062 /* send MM INFO with network name */
Harald Weltedb253af2008-12-30 17:56:55 +00001063 ret = gsm48_tx_mm_info(lchan);
Harald Weltedb253af2008-12-30 17:56:55 +00001064
Holger Freyther07cc8d82008-12-29 06:23:46 +00001065 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001066}
1067
Harald Weltefc977a82008-12-27 10:19:37 +00001068static char bcd2char(u_int8_t bcd)
1069{
1070 if (bcd < 0xa)
1071 return '0' + bcd;
1072 else
1073 return 'A' + (bcd - 0xa);
1074}
1075
Harald Weltebf5e8df2009-02-03 12:59:45 +00001076/* Convert Mobile Identity (10.5.1.4) to string */
Harald Weltefc977a82008-12-27 10:19:37 +00001077static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
1078{
1079 int i;
1080 u_int8_t mi_type;
1081 char *str_cur = string;
Harald Welte4ed0e922009-01-10 03:17:30 +00001082 u_int32_t tmsi;
Harald Weltefc977a82008-12-27 10:19:37 +00001083
1084 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1085
1086 switch (mi_type) {
1087 case GSM_MI_TYPE_NONE:
1088 break;
1089 case GSM_MI_TYPE_TMSI:
Harald Welte4ed0e922009-01-10 03:17:30 +00001090 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
1091 if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
1092 memcpy(&tmsi, &mi[1], 4);
1093 tmsi = ntohl(tmsi);
1094 return snprintf(string, str_len, "%u", tmsi);
Harald Weltefc977a82008-12-27 10:19:37 +00001095 }
1096 break;
1097 case GSM_MI_TYPE_IMSI:
1098 case GSM_MI_TYPE_IMEI:
1099 case GSM_MI_TYPE_IMEISV:
Harald Weltedb253af2008-12-30 17:56:55 +00001100 *str_cur++ = bcd2char(mi[0] >> 4);
1101
1102 for (i = 1; i < mi_len; i++) {
Harald Weltefc977a82008-12-27 10:19:37 +00001103 if (str_cur + 2 >= string + str_len)
1104 return str_cur - string;
1105 *str_cur++ = bcd2char(mi[i] & 0xf);
Harald Weltedb253af2008-12-30 17:56:55 +00001106 /* skip last nibble in last input byte when GSM_EVEN */
1107 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
1108 *str_cur++ = bcd2char(mi[i] >> 4);
Harald Weltefc977a82008-12-27 10:19:37 +00001109 }
1110 break;
1111 default:
1112 break;
1113 }
Harald Weltefc977a82008-12-27 10:19:37 +00001114 *str_cur++ = '\0';
Harald Weltedb253af2008-12-30 17:56:55 +00001115
Harald Weltefc977a82008-12-27 10:19:37 +00001116 return str_cur - string;
1117}
1118
Harald Weltebf5e8df2009-02-03 12:59:45 +00001119/* Transmit Chapter 9.2.10 Identity Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001120static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
1121{
1122 struct msgb *msg = gsm48_msgb_alloc();
1123 struct gsm48_hdr *gh;
Harald Weltefc977a82008-12-27 10:19:37 +00001124
Harald Welte231ad4f2008-12-27 11:15:38 +00001125 msg->lchan = lchan;
1126
1127 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1128 gh->proto_discr = GSM48_PDISC_MM;
1129 gh->msg_type = GSM48_MT_MM_ID_REQ;
1130 gh->data[0] = id_type;
1131
Harald Welte39e2ead2009-07-23 21:13:03 +02001132 return gsm48_sendmsg(msg, NULL);
Harald Welte231ad4f2008-12-27 11:15:38 +00001133}
1134
1135#define MI_SIZE 32
1136
Harald Weltebf5e8df2009-02-03 12:59:45 +00001137/* Parse Chapter 9.2.11 Identity Response */
Harald Welte231ad4f2008-12-27 11:15:38 +00001138static int mm_rx_id_resp(struct msgb *msg)
1139{
1140 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte75a983f2008-12-27 21:34:06 +00001141 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001142 struct gsm_bts *bts = lchan->ts->trx->bts;
1143 struct gsm_network *net = bts->network;
Harald Welte231ad4f2008-12-27 11:15:38 +00001144 u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
1145 char mi_string[MI_SIZE];
1146
1147 mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
Harald Welte61253062008-12-27 11:25:50 +00001148 DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
Harald Welte231ad4f2008-12-27 11:15:38 +00001149 mi_type, mi_string);
1150
Harald Welte75a983f2008-12-27 21:34:06 +00001151 switch (mi_type) {
1152 case GSM_MI_TYPE_IMSI:
Jan Luebbe370b41d2009-08-12 10:19:34 +02001153 /* look up subscriber based on IMSI, create if not found */
1154 if (!lchan->subscr) {
1155 lchan->subscr = subscr_get_by_imsi(net, mi_string);
Harald Welte (local)aa9dc192009-08-13 13:49:51 +02001156 if (!lchan->subscr)
1157 lchan->subscr = db_create_subscriber(net, mi_string);
Jan Luebbeb0dfc312009-08-12 10:12:52 +02001158 }
Holger Freyther73487a22008-12-31 18:53:57 +00001159 if (lchan->loc_operation)
1160 lchan->loc_operation->waiting_for_imsi = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001161 break;
1162 case GSM_MI_TYPE_IMEI:
Harald Welte255539c2008-12-28 02:26:27 +00001163 case GSM_MI_TYPE_IMEISV:
Harald Welte75a983f2008-12-27 21:34:06 +00001164 /* update subscribe <-> IMEI mapping */
1165 if (lchan->subscr)
1166 db_subscriber_assoc_imei(lchan->subscr, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001167 if (lchan->loc_operation)
1168 lchan->loc_operation->waiting_for_imei = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001169 break;
1170 }
Holger Freyther73487a22008-12-31 18:53:57 +00001171
1172 /* Check if we can let the mobile station enter */
Holger Freytherd51524f2009-06-09 08:27:07 +00001173 return gsm0408_authorize(lchan, msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001174}
1175
Harald Welte255539c2008-12-28 02:26:27 +00001176
1177static void loc_upd_rej_cb(void *data)
1178{
1179 struct gsm_lchan *lchan = data;
1180
Holger Freyther73487a22008-12-31 18:53:57 +00001181 release_loc_updating_req(lchan);
Holger Freythere97f7fb2008-12-31 18:52:11 +00001182 gsm0408_loc_upd_rej(lchan, reject_cause);
Holger Freyther67b4b9a2009-01-01 03:46:11 +00001183 lchan_auto_release(lchan);
Harald Welte255539c2008-12-28 02:26:27 +00001184}
1185
Holger Freytherb7193e42008-12-29 17:44:08 +00001186static void schedule_reject(struct gsm_lchan *lchan)
1187{
Holger Freyther73487a22008-12-31 18:53:57 +00001188 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1189 lchan->loc_operation->updating_timer.data = lchan;
Harald Welteff117a82009-05-23 05:22:08 +00001190 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
Holger Freytherb7193e42008-12-29 17:44:08 +00001191}
1192
Harald Welte2a139372009-02-22 21:14:55 +00001193static const char *lupd_name(u_int8_t type)
1194{
1195 switch (type) {
1196 case GSM48_LUPD_NORMAL:
1197 return "NORMAL";
1198 case GSM48_LUPD_PERIODIC:
1199 return "PEROIDOC";
1200 case GSM48_LUPD_IMSI_ATT:
1201 return "IMSI ATTACH";
1202 default:
1203 return "UNKNOWN";
1204 }
1205}
1206
Harald Welte231ad4f2008-12-27 11:15:38 +00001207#define MI_SIZE 32
Harald Weltebf5e8df2009-02-03 12:59:45 +00001208/* Chapter 9.2.15: Receive Location Updating Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001209static int mm_rx_loc_upd_req(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001210{
Harald Welte8470bf22008-12-25 23:28:35 +00001211 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001212 struct gsm48_loc_upd_req *lu;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001213 struct gsm_subscriber *subscr = NULL;
Harald Welte255539c2008-12-28 02:26:27 +00001214 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001215 struct gsm_bts *bts = lchan->ts->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +00001216 u_int8_t mi_type;
Harald Welte231ad4f2008-12-27 11:15:38 +00001217 char mi_string[MI_SIZE];
1218 int rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001219
Harald Welte8470bf22008-12-25 23:28:35 +00001220 lu = (struct gsm48_loc_upd_req *) gh->data;
1221
1222 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
Harald Welte52b1f982008-12-23 20:25:15 +00001223
Harald Weltefc977a82008-12-27 10:19:37 +00001224 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1225
Harald Weltea0368542009-06-27 02:58:43 +02001226 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte2a139372009-02-22 21:14:55 +00001227 lupd_name(lu->type));
Holger Freyther73487a22008-12-31 18:53:57 +00001228
Holger Freythereaf04692009-06-06 13:54:44 +00001229 /*
1230 * Pseudo Spoof detection: Just drop a second/concurrent
1231 * location updating request.
1232 */
1233 if (lchan->loc_operation) {
Harald Weltea0368542009-06-27 02:58:43 +02001234 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Holger Freythereaf04692009-06-06 13:54:44 +00001235 lchan->loc_operation);
1236 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1237 return 0;
1238 }
1239
Holger Freyther73487a22008-12-31 18:53:57 +00001240 allocate_loc_updating_req(lchan);
1241
Harald Welte52b1f982008-12-23 20:25:15 +00001242 switch (mi_type) {
1243 case GSM_MI_TYPE_IMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001244 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001245 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001246 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001247 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001248
Jan Luebbe370b41d2009-08-12 10:19:34 +02001249 /* look up subscriber based on IMSI, create if not found */
1250 subscr = subscr_get_by_imsi(bts->network, mi_string);
1251 if (!subscr) {
1252 subscr = db_create_subscriber(bts->network, mi_string);
1253 }
Harald Welte4b634542008-12-27 01:55:51 +00001254 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001255 case GSM_MI_TYPE_TMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001256 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001257 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001258 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001259 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001260
Harald Welte52b1f982008-12-23 20:25:15 +00001261 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welte9176bd42009-07-23 18:46:00 +02001262 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte52b1f982008-12-23 20:25:15 +00001263 if (!subscr) {
Harald Welte231ad4f2008-12-27 11:15:38 +00001264 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte255539c2008-12-28 02:26:27 +00001265 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
Holger Freyther73487a22008-12-31 18:53:57 +00001266 lchan->loc_operation->waiting_for_imsi = 1;
Harald Welte52b1f982008-12-23 20:25:15 +00001267 }
1268 break;
1269 case GSM_MI_TYPE_IMEI:
1270 case GSM_MI_TYPE_IMEISV:
1271 /* no sim card... FIXME: what to do ? */
Harald Weltea0368542009-06-27 02:58:43 +02001272 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001273 break;
1274 default:
Harald Weltea0368542009-06-27 02:58:43 +02001275 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001276 break;
1277 }
1278
Harald Welte24516ea2009-07-04 10:18:00 +02001279 /* schedule the reject timer */
1280 schedule_reject(lchan);
1281
Harald Welte4bfdfe72009-06-10 23:11:52 +08001282 if (!subscr) {
Harald Weltea0368542009-06-27 02:58:43 +02001283 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001284 /* FIXME: request id? close channel? */
1285 return -EINVAL;
1286 }
1287
Harald Welte255539c2008-12-28 02:26:27 +00001288 lchan->subscr = subscr;
1289
Harald Welte24516ea2009-07-04 10:18:00 +02001290 /* check if we can let the subscriber into our network immediately
1291 * or if we need to wait for identity responses. */
Holger Freytherd51524f2009-06-09 08:27:07 +00001292 return gsm0408_authorize(lchan, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001293}
1294
Harald Welte13cac662009-07-29 12:10:35 +02001295/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Harald Welte7584aea2009-02-11 11:44:12 +00001296int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1297{
1298 struct msgb *msg = gsm48_msgb_alloc();
1299 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1300 struct gsm48_chan_mode_modify *cmm =
1301 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
Harald Welte4a543e82009-02-28 13:17:55 +00001302 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
Harald Welte7584aea2009-02-11 11:44:12 +00001303
Harald Welte4a543e82009-02-28 13:17:55 +00001304 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
Harald Welte7ccf7782009-02-17 01:43:01 +00001305
Harald Welte45b407a2009-05-23 15:51:12 +00001306 lchan->tch_mode = mode;
Harald Welte7584aea2009-02-11 11:44:12 +00001307 msg->lchan = lchan;
1308 gh->proto_discr = GSM48_PDISC_RR;
1309 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1310
1311 /* fill the channel information element, this code
1312 * should probably be shared with rsl_rx_chan_rqd() */
1313 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte02b0e092009-02-28 13:11:07 +00001314 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
Harald Welte7584aea2009-02-11 11:44:12 +00001315 cmm->chan_desc.h0.h = 0;
1316 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1317 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1318 cmm->mode = mode;
1319
Harald Welte39e2ead2009-07-23 21:13:03 +02001320 return gsm48_sendmsg(msg, NULL);
Harald Welte7584aea2009-02-11 11:44:12 +00001321}
1322
Harald Welte4bfdfe72009-06-10 23:11:52 +08001323#if 0
1324static u_int8_t to_bcd8(u_int8_t val)
1325{
1326 return ((val / 10) << 4) | (val % 10);
1327}
1328#endif
1329
Harald Weltedb253af2008-12-30 17:56:55 +00001330/* Section 9.2.15a */
1331int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1332{
1333 struct msgb *msg = gsm48_msgb_alloc();
1334 struct gsm48_hdr *gh;
1335 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Weltedb253af2008-12-30 17:56:55 +00001336 u_int8_t *ptr8;
1337 u_int16_t *ptr16;
1338 int name_len;
Harald Weltedb253af2008-12-30 17:56:55 +00001339 int i;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001340#if 0
1341 time_t cur_t;
1342 struct tm* cur_time;
1343 int tz15min;
1344#endif
Harald Weltedb253af2008-12-30 17:56:55 +00001345
1346 msg->lchan = lchan;
1347
1348 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1349 gh->proto_discr = GSM48_PDISC_MM;
1350 gh->msg_type = GSM48_MT_MM_INFO;
1351
1352 if (net->name_long) {
1353 name_len = strlen(net->name_long);
1354 /* 10.5.3.5a */
1355 ptr8 = msgb_put(msg, 3);
1356 ptr8[0] = GSM48_IE_NAME_LONG;
1357 ptr8[1] = name_len*2 +1;
1358 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1359
1360 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1361 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001362 ptr16[i] = htons(net->name_long[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001363
1364 /* FIXME: Use Cell Broadcast, not UCS-2, since
1365 * UCS-2 is only supported by later revisions of the spec */
1366 }
1367
1368 if (net->name_short) {
1369 name_len = strlen(net->name_short);
1370 /* 10.5.3.5a */
1371 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Welte7543eb72009-07-19 17:51:36 +02001372 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Weltedb253af2008-12-30 17:56:55 +00001373 ptr8[1] = name_len*2 + 1;
1374 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1375
Harald Weltee872cb12009-01-01 00:33:37 +00001376 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
Harald Weltedb253af2008-12-30 17:56:55 +00001377 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001378 ptr16[i] = htons(net->name_short[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001379 }
1380
1381#if 0
1382 /* Section 10.5.3.9 */
1383 cur_t = time(NULL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001384 cur_time = gmtime(&cur_t);
Harald Weltedb253af2008-12-30 17:56:55 +00001385 ptr8 = msgb_put(msg, 8);
1386 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1387 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1388 ptr8[2] = to_bcd8(cur_time->tm_mon);
1389 ptr8[3] = to_bcd8(cur_time->tm_mday);
1390 ptr8[4] = to_bcd8(cur_time->tm_hour);
1391 ptr8[5] = to_bcd8(cur_time->tm_min);
1392 ptr8[6] = to_bcd8(cur_time->tm_sec);
1393 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1394 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001395 ptr8[7] = to_bcd8(tz15min);
Harald Weltedb253af2008-12-30 17:56:55 +00001396 if (tz15min < 0)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001397 ptr8[7] |= 0x80;
Harald Weltedb253af2008-12-30 17:56:55 +00001398#endif
1399
Harald Welte39e2ead2009-07-23 21:13:03 +02001400 return gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001401}
1402
Harald Welte7984d5c2009-08-12 22:56:50 +02001403/* Section 9.2.2 */
1404int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand)
1405{
1406 struct msgb *msg = gsm48_msgb_alloc();
1407 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1408 u_int8_t *r;
1409
1410 DEBUGP(DMM, "-> AUTH REQ\n");
1411
1412 msg->lchan = lchan;
1413 gh->proto_discr = GSM48_PDISC_MM;
1414 gh->msg_type = GSM48_MT_MM_AUTH_REQ;
1415
1416 /* 16 bytes RAND parameters */
1417 r = msgb_put(msg, 16);
1418 if (rand)
1419 memcpy(r, rand, 16);
1420
1421 return gsm48_sendmsg(msg, NULL);
1422}
1423
1424/* Section 9.2.1 */
1425int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan)
1426{
1427 DEBUGP(DMM, "-> AUTH REJECT\n");
1428 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ);
1429}
1430
Harald Welte4b634542008-12-27 01:55:51 +00001431static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1432{
Harald Welte4b634542008-12-27 01:55:51 +00001433 DEBUGP(DMM, "-> CM SERVICE ACK\n");
Harald Welte65e74cc2008-12-29 01:55:35 +00001434 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
Harald Welte4b634542008-12-27 01:55:51 +00001435}
Harald Welteba4cf162009-01-10 01:49:35 +00001436
1437/* 9.2.6 CM service reject */
1438static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1439 enum gsm48_reject_value value)
1440{
1441 struct msgb *msg = gsm48_msgb_alloc();
1442 struct gsm48_hdr *gh;
1443
1444 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1445
1446 msg->lchan = lchan;
1447 use_lchan(lchan);
1448
1449 gh->proto_discr = GSM48_PDISC_MM;
1450 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1451 gh->data[0] = value;
1452 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1453
Harald Welte39e2ead2009-07-23 21:13:03 +02001454 return gsm48_sendmsg(msg, NULL);
Harald Welteba4cf162009-01-10 01:49:35 +00001455}
1456
Harald Welte3ac7f102009-08-10 10:12:45 +02001457static int send_siemens_mrpci(struct gsm_lchan *lchan,
1458 u_int8_t *classmark2_lv)
1459{
1460 struct rsl_mrpci mrpci;
1461
1462 if (classmark2_lv[0] < 2)
1463 return -EINVAL;
1464
1465 mrpci.power_class = classmark2_lv[1] & 0x7;
1466 mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
1467 mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
1468 mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
1469
1470 return rsl_siemens_mrpci(lchan, &mrpci);
1471}
Harald Welte4ed0e922009-01-10 03:17:30 +00001472
1473/*
1474 * Handle CM Service Requests
1475 * a) Verify that the packet is long enough to contain the information
1476 * we require otherwsie reject with INCORRECT_MESSAGE
1477 * b) Try to parse the TMSI. If we do not have one reject
1478 * c) Check that we know the subscriber with the TMSI otherwise reject
1479 * with a HLR cause
1480 * d) Set the subscriber on the gsm_lchan and accept
1481 */
Harald Welte4b634542008-12-27 01:55:51 +00001482static int gsm48_rx_mm_serv_req(struct msgb *msg)
1483{
Harald Welteba4cf162009-01-10 01:49:35 +00001484 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001485 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001486
Harald Welte9176bd42009-07-23 18:46:00 +02001487 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welteba4cf162009-01-10 01:49:35 +00001488 struct gsm_subscriber *subscr;
1489 struct gsm48_hdr *gh = msgb_l3(msg);
1490 struct gsm48_service_request *req =
1491 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001492 /* unfortunately in Phase1 the classmar2 length is variable */
1493 u_int8_t classmark2_len = gh->data[1];
1494 u_int8_t *classmark2 = gh->data+2;
1495 u_int8_t mi_len = *(classmark2 + classmark2_len);
1496 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001497
Harald Weltec9e02182009-05-01 19:07:53 +00001498 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001499 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001500 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001501 return gsm48_tx_mm_serv_rej(msg->lchan,
1502 GSM48_REJECT_INCORRECT_MESSAGE);
1503 }
1504
1505 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001506 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001507 return gsm48_tx_mm_serv_rej(msg->lchan,
1508 GSM48_REJECT_INCORRECT_MESSAGE);
1509 }
1510
Harald Weltec9e02182009-05-01 19:07:53 +00001511 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001512 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001513 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001514 return gsm48_tx_mm_serv_rej(msg->lchan,
1515 GSM48_REJECT_INCORRECT_MESSAGE);
1516 }
1517
Harald Weltec9e02182009-05-01 19:07:53 +00001518 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001519 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001520 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001521
Harald Welte3ac7f102009-08-10 10:12:45 +02001522 if (is_siemens_bts(bts))
1523 send_siemens_mrpci(msg->lchan, classmark2-1);
1524
Harald Welte9176bd42009-07-23 18:46:00 +02001525 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Holger Freythereb443982009-06-04 13:58:42 +00001526
Harald Welte2a139372009-02-22 21:14:55 +00001527 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001528 if (!subscr)
1529 return gsm48_tx_mm_serv_rej(msg->lchan,
1530 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1531
1532 if (!msg->lchan->subscr)
1533 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001534 else if (msg->lchan->subscr != subscr) {
1535 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1536 subscr_put(subscr);
1537 }
1538
Harald Weltec2e302d2009-07-05 14:08:13 +02001539 subscr->equipment.classmark2_len = classmark2_len;
1540 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1541 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001542
Harald Welte4b634542008-12-27 01:55:51 +00001543 return gsm48_tx_mm_serv_ack(msg->lchan);
1544}
1545
Harald Welte2a139372009-02-22 21:14:55 +00001546static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1547{
Harald Welte9176bd42009-07-23 18:46:00 +02001548 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2a139372009-02-22 21:14:55 +00001549 struct gsm48_hdr *gh = msgb_l3(msg);
1550 struct gsm48_imsi_detach_ind *idi =
1551 (struct gsm48_imsi_detach_ind *) gh->data;
1552 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1553 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001554 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001555
1556 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1557 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1558 mi_type, mi_string);
1559
1560 switch (mi_type) {
1561 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001562 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001563 break;
1564 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001565 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001566 break;
1567 case GSM_MI_TYPE_IMEI:
1568 case GSM_MI_TYPE_IMEISV:
1569 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001570 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001571 break;
1572 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001573 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001574 break;
1575 }
1576
Holger Freyther4a49e772009-04-12 05:37:29 +00001577 if (subscr) {
1578 subscr_update(subscr, msg->trx->bts,
1579 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001580 DEBUGP(DMM, "Subscriber: %s\n",
1581 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001582 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001583 } else
Harald Welte2a139372009-02-22 21:14:55 +00001584 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1585
Harald Welte2a139372009-02-22 21:14:55 +00001586 return 0;
1587}
1588
Harald Welted2a7f5a2009-06-05 20:08:20 +00001589static int gsm48_rx_mm_status(struct msgb *msg)
1590{
1591 struct gsm48_hdr *gh = msgb_l3(msg);
1592
1593 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1594
1595 return 0;
1596}
1597
Harald Weltebf5e8df2009-02-03 12:59:45 +00001598/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001599static int gsm0408_rcv_mm(struct msgb *msg)
1600{
1601 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001602 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001603
1604 switch (gh->msg_type & 0xbf) {
1605 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001606 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001607 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001608 break;
1609 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001610 rc = mm_rx_id_resp(msg);
1611 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001612 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001613 rc = gsm48_rx_mm_serv_req(msg);
1614 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001615 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001616 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001617 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001618 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001619 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1620 msg->lchan->subscr ?
1621 msg->lchan->subscr->imsi :
1622 "unknown subscriber");
1623 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001624 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001625 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1626 break;
1627 case GSM48_MT_MM_CM_REEST_REQ:
1628 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1629 break;
1630 case GSM48_MT_MM_AUTH_RESP:
1631 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001632 break;
1633 default:
1634 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1635 gh->msg_type);
1636 break;
1637 }
1638
1639 return rc;
1640}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001641
Harald Welte2d35ae62009-02-06 12:02:13 +00001642/* Receive a PAGING RESPONSE message from the MS */
1643static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1644{
Harald Welte9176bd42009-07-23 18:46:00 +02001645 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2d35ae62009-02-06 12:02:13 +00001646 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001647 u_int8_t *classmark2_lv = gh->data + 1;
1648 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1649 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001650 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001651 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001652 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001653 int rc = 0;
1654
Harald Welte61548982009-02-22 21:26:29 +00001655 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001656 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1657 mi_type, mi_string);
Harald Welte3ac7f102009-08-10 10:12:45 +02001658
1659 if (is_siemens_bts(bts))
1660 send_siemens_mrpci(msg->lchan, classmark2_lv);
1661
Harald Weltefe18d8f2009-02-22 21:14:24 +00001662 switch (mi_type) {
1663 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001664 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001665 break;
1666 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001667 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001668 break;
1669 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001670
1671 if (!subscr) {
1672 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001673 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001674 return -EINVAL;
1675 }
1676 DEBUGP(DRR, "<- Channel was requested by %s\n",
Harald Welte76042182009-08-08 16:03:15 +02001677 subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001678
Harald Weltec2e302d2009-07-05 14:08:13 +02001679 subscr->equipment.classmark2_len = *classmark2_lv;
1680 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1681 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001682
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001683 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001684 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001685 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001686 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1687 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001688 return -EINVAL;
1689 } else {
1690 DEBUGP(DRR, "<- Channel already owned by us\n");
1691 subscr_put(subscr);
1692 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001693 }
1694
Harald Welte595ad7b2009-02-16 22:05:44 +00001695 sig_data.subscr = subscr;
1696 sig_data.bts = msg->lchan->ts->trx->bts;
1697 sig_data.lchan = msg->lchan;
1698
1699 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001700
1701 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001702 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001703
Harald Welte7584aea2009-02-11 11:44:12 +00001704 /* FIXME: somehow signal the completion of the PAGING to
1705 * the entity that requested the paging */
1706
Harald Welte2d35ae62009-02-06 12:02:13 +00001707 return rc;
1708}
1709
Harald Weltef7c43522009-06-09 20:24:21 +00001710static int gsm48_rx_rr_classmark(struct msgb *msg)
1711{
1712 struct gsm48_hdr *gh = msgb_l3(msg);
1713 struct gsm_subscriber *subscr = msg->lchan->subscr;
1714 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1715 u_int8_t cm2_len, cm3_len = 0;
1716 u_int8_t *cm2, *cm3 = NULL;
1717
1718 DEBUGP(DRR, "CLASSMARK CHANGE ");
1719
1720 /* classmark 2 */
1721 cm2_len = gh->data[0];
1722 cm2 = &gh->data[1];
1723 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1724
1725 if (payload_len > cm2_len + 1) {
1726 /* we must have a classmark3 */
1727 if (gh->data[cm2_len+1] != 0x20) {
1728 DEBUGPC(DRR, "ERR CM3 TAG\n");
1729 return -EINVAL;
1730 }
1731 if (cm2_len > 3) {
1732 DEBUGPC(DRR, "CM2 too long!\n");
1733 return -EINVAL;
1734 }
1735
1736 cm3_len = gh->data[cm2_len+2];
1737 cm3 = &gh->data[cm2_len+3];
1738 if (cm3_len > 14) {
1739 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1740 return -EINVAL;
1741 }
1742 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1743 }
1744 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001745 subscr->equipment.classmark2_len = cm2_len;
1746 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001747 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001748 subscr->equipment.classmark3_len = cm3_len;
1749 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001750 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001751 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001752 }
1753
Harald Weltef7c43522009-06-09 20:24:21 +00001754 return 0;
1755}
1756
Harald Weltecf5b3592009-05-01 18:28:42 +00001757static int gsm48_rx_rr_status(struct msgb *msg)
1758{
1759 struct gsm48_hdr *gh = msgb_l3(msg);
1760
1761 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1762 rr_cause_name(gh->data[0]));
1763
1764 return 0;
1765}
1766
Harald Weltef7c43522009-06-09 20:24:21 +00001767static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1768{
1769 struct gsm48_hdr *gh = msgb_l3(msg);
1770 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1771 static struct gsm_meas_rep meas_rep;
1772
Harald Welte10d0e672009-06-27 02:53:10 +02001773 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001774 parse_meas_rep(&meas_rep, gh->data, payload_len);
1775 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001776 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001777 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001778 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001779 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001780 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001781 else
Harald Welte10d0e672009-06-27 02:53:10 +02001782 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001783 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1784 meas_rep.rxqual_sub);
1785
Harald Welte10d0e672009-06-27 02:53:10 +02001786 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001787
1788 /* FIXME: put the results somwhere */
1789
1790 return 0;
1791}
1792
Harald Weltebf5e8df2009-02-03 12:59:45 +00001793/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001794static int gsm0408_rcv_rr(struct msgb *msg)
1795{
1796 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001797 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001798
1799 switch (gh->msg_type) {
1800 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001801 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001802 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001803 case GSM48_MT_RR_GPRS_SUSP_REQ:
1804 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1805 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001806 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001807 rc = gsm48_rr_rx_pag_resp(msg);
1808 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001809 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1810 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte13cac662009-07-29 12:10:35 +02001811 /* We've successfully modified the MS side of the channel,
1812 * now go on to modify the BTS side of the channel */
Harald Welte9943c5b2009-07-29 15:41:29 +02001813 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
Harald Welte2c38aa82009-02-18 03:44:24 +00001814 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001815 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001816 case GSM48_MT_RR_STATUS:
1817 rc = gsm48_rx_rr_status(msg);
1818 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001819 case GSM48_MT_RR_MEAS_REP:
1820 rc = gsm48_rx_rr_meas_rep(msg);
1821 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001822 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001823 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001824 gh->msg_type);
1825 break;
1826 }
1827
Harald Welte2d35ae62009-02-06 12:02:13 +00001828 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001829}
1830
Harald Welte115d1032009-08-10 11:43:22 +02001831/* 7.1.7 and 9.1.7: RR CHANnel RELease */
Holger Freythere64a7a32009-02-06 21:55:37 +00001832int gsm48_send_rr_release(struct gsm_lchan *lchan)
1833{
1834 struct msgb *msg = gsm48_msgb_alloc();
1835 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1836 u_int8_t *cause;
1837
1838 msg->lchan = lchan;
1839 gh->proto_discr = GSM48_PDISC_RR;
1840 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1841
1842 cause = msgb_put(msg, 1);
1843 cause[0] = GSM48_RR_CAUSE_NORMAL;
1844
1845 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1846 lchan->nr, lchan->type);
1847
Harald Welteae0f2362009-07-19 18:36:49 +02001848 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001849 gsm48_sendmsg(msg, NULL);
Harald Welte76042182009-08-08 16:03:15 +02001850 /* FIXME: Start Timer T3109 */
Harald Welteae0f2362009-07-19 18:36:49 +02001851
1852 /* Deactivate the SACCH on the BTS side */
1853 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001854}
1855
Harald Welte4bc90a12008-12-27 16:32:52 +00001856/* Call Control */
1857
Harald Welte7584aea2009-02-11 11:44:12 +00001858/* The entire call control code is written in accordance with Figure 7.10c
1859 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1860 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1861 * it for voice */
1862
Harald Welte4bfdfe72009-06-10 23:11:52 +08001863static void new_cc_state(struct gsm_trans *trans, int state)
1864{
1865 if (state > 31 || state < 0)
1866 return;
1867
1868 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001869 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001870
Harald Weltedcaf5652009-07-23 18:56:43 +02001871 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001872}
1873
1874static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001875{
1876 struct msgb *msg = gsm48_msgb_alloc();
1877 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1878 u_int8_t *cause, *call_state;
1879
Harald Welte4bc90a12008-12-27 16:32:52 +00001880 gh->msg_type = GSM48_MT_CC_STATUS;
1881
1882 cause = msgb_put(msg, 3);
1883 cause[0] = 2;
1884 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1885 cause[2] = 0x80 | 30; /* response to status inquiry */
1886
1887 call_state = msgb_put(msg, 1);
1888 call_state[0] = 0xc0 | 0x00;
1889
Harald Welte39e2ead2009-07-23 21:13:03 +02001890 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001891}
1892
Harald Welte6f4b7532008-12-29 00:39:37 +00001893static int gsm48_tx_simple(struct gsm_lchan *lchan,
1894 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001895{
1896 struct msgb *msg = gsm48_msgb_alloc();
1897 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1898
1899 msg->lchan = lchan;
1900
Harald Welte6f4b7532008-12-29 00:39:37 +00001901 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001902 gh->msg_type = msg_type;
1903
Harald Welte39e2ead2009-07-23 21:13:03 +02001904 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001905}
1906
Harald Welte4bfdfe72009-06-10 23:11:52 +08001907static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1908{
Harald Weltedcaf5652009-07-23 18:56:43 +02001909 if (bsc_timer_pending(&trans->cc.timer)) {
1910 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1911 bsc_del_timer(&trans->cc.timer);
1912 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001913 }
1914}
1915
1916static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1917 int msg_type, struct gsm_mncc *mncc)
1918{
1919 struct msgb *msg;
1920
1921 if (trans)
1922 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001923 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001924 "Sending '%s' to MNCC.\n",
1925 trans->lchan->ts->trx->bts->nr,
1926 trans->lchan->ts->trx->nr,
1927 trans->lchan->ts->nr, trans->transaction_id,
1928 (trans->subscr)?(trans->subscr->extension):"-",
1929 get_mncc_name(msg_type));
1930 else
1931 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1932 "Sending '%s' to MNCC.\n",
1933 (trans->subscr)?(trans->subscr->extension):"-",
1934 get_mncc_name(msg_type));
1935 else
1936 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1937 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1938
1939 mncc->msg_type = msg_type;
1940
Harald Welte966636f2009-06-26 19:39:35 +02001941 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001942 if (!msg)
1943 return -ENOMEM;
1944 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1945 msgb_enqueue(&net->upqueue, msg);
1946
1947 return 0;
1948}
1949
1950int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1951 u_int32_t callref, int location, int value)
1952{
1953 struct gsm_mncc rel;
1954
Harald Welte92f70c52009-06-12 01:54:08 +08001955 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001956 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001957 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001958 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1959}
1960
Harald Weltedcaf5652009-07-23 18:56:43 +02001961/* Call Control Specific transaction release.
1962 * gets called by trans_free, DO NOT CALL YOURSELF! */
1963void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001964{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001965 gsm48_stop_cc_timer(trans);
1966
1967 /* send release to L4, if callref still exists */
1968 if (trans->callref) {
1969 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02001970 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001971 GSM48_CAUSE_LOC_PRN_S_LU,
1972 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001973 }
Harald Weltedcaf5652009-07-23 18:56:43 +02001974 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001975 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02001976 if (trans->lchan)
1977 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001978}
1979
1980static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1981
Harald Welte09e38af2009-02-16 22:52:23 +00001982/* call-back from paging the B-end of the connection */
1983static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001984 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001985{
Harald Welte7ccf7782009-02-17 01:43:01 +00001986 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001987 struct gsm_subscriber *subscr = param;
1988 struct gsm_trans *transt, *tmp;
1989 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001990
Harald Welte09e38af2009-02-16 22:52:23 +00001991 if (hooknum != GSM_HOOK_RR_PAGING)
1992 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001993
1994 if (!subscr)
1995 return -EINVAL;
1996 net = subscr->net;
1997 if (!net) {
1998 DEBUGP(DCC, "Error Network not set!\n");
1999 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00002000 }
Harald Welte7584aea2009-02-11 11:44:12 +00002001
Harald Welte4bfdfe72009-06-10 23:11:52 +08002002 /* check all tranactions (without lchan) for subscriber */
2003 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
2004 if (transt->subscr != subscr || transt->lchan)
2005 continue;
2006 switch (event) {
2007 case GSM_PAGING_SUCCEEDED:
2008 if (!lchan) // paranoid
2009 break;
2010 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
2011 subscr->extension);
2012 /* Assign lchan */
2013 if (!transt->lchan) {
2014 transt->lchan = lchan;
2015 use_lchan(lchan);
2016 }
2017 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02002018 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002019 break;
2020 case GSM_PAGING_EXPIRED:
2021 DEBUGP(DCC, "Paging subscr %s expired!\n",
2022 subscr->extension);
2023 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002024 mncc_release_ind(transt->subscr->net, transt,
2025 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002026 GSM48_CAUSE_LOC_PRN_S_LU,
2027 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002028 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002029 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002030 break;
2031 }
2032 }
Harald Welte09e38af2009-02-16 22:52:23 +00002033 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00002034}
Harald Welte7584aea2009-02-11 11:44:12 +00002035
Harald Welte805f6442009-07-28 18:25:29 +02002036/* some other part of the code sends us a signal */
2037static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
2038 void *handler_data, void *signal_data)
2039{
2040 struct gsm_lchan *lchan = signal_data;
2041 struct gsm_bts_trx_ts *ts;
2042 int rc;
2043
2044 if (subsys != SS_ABISIP)
2045 return 0;
2046
2047 /* in case we use direct BTS-to-BTS RTP */
2048 if (ipacc_rtp_direct)
2049 return 0;
2050
2051 ts = lchan->ts;
2052
2053 switch (signal) {
2054 case S_ABISIP_BIND_ACK:
2055 /* the BTS has successfully bound a TCH to a local ip/port,
2056 * which means we can connect our UDP socket to it */
2057 if (ts->abis_ip.rtp_socket) {
2058 rtp_socket_free(ts->abis_ip.rtp_socket);
2059 ts->abis_ip.rtp_socket = NULL;
2060 }
2061
2062 ts->abis_ip.rtp_socket = rtp_socket_create();
2063 if (!ts->abis_ip.rtp_socket)
2064 goto out_err;
2065
2066 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2067 ts->abis_ip.bound_ip,
2068 ts->abis_ip.bound_port);
2069 if (rc < 0)
2070 goto out_err;
2071 break;
2072 case S_ABISIP_DISC_IND:
2073 /* the BTS tells us a RTP stream has been disconnected */
2074 if (ts->abis_ip.rtp_socket) {
2075 rtp_socket_free(ts->abis_ip.rtp_socket);
2076 ts->abis_ip.rtp_socket = NULL;
2077 }
2078 break;
2079 }
2080
2081 return 0;
2082out_err:
2083 /* FIXME: do something */
2084 return 0;
2085}
2086
2087/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2088static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2089{
2090 struct gsm_bts_trx_ts *ts = lchan->ts;
2091 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2092 int rc;
2093
2094 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2095 ntohs(rs->rtp.sin_local.sin_port),
2096 ts->abis_ip.conn_id,
2097 /* FIXME: use RTP payload of bound socket, not BTS*/
2098 ts->abis_ip.rtp_payload2);
2099
2100 return rc;
2101}
2102
Harald Welte49f48b82009-02-17 15:29:33 +00002103/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002104static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002105{
Harald Welte11fa29c2009-02-19 17:24:39 +00002106 struct gsm_bts *bts = lchan->ts->trx->bts;
2107 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002108 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002109 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002110
Harald Welte11fa29c2009-02-19 17:24:39 +00002111 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2112 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2113 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2114
2115 if (bts->type != remote_bts->type) {
2116 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2117 return -EINVAL;
2118 }
Harald Welte49f48b82009-02-17 15:29:33 +00002119
Harald Welte11fa29c2009-02-19 17:24:39 +00002120 switch (bts->type) {
2121 case GSM_BTS_TYPE_NANOBTS_900:
2122 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002123 if (!ipacc_rtp_direct) {
2124 /* connect the TCH's to our RTP proxy */
2125 rc = ipacc_connect_proxy_bind(lchan);
2126 if (rc < 0)
2127 return rc;
2128 rc = ipacc_connect_proxy_bind(remote_lchan);
2129
2130 /* connect them with each other */
2131 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2132 remote_lchan->ts->abis_ip.rtp_socket);
2133 } else {
2134 /* directly connect TCH RTP streams to each other */
2135 ts = remote_lchan->ts;
2136 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2137 ts->abis_ip.bound_port,
2138 lchan->ts->abis_ip.conn_id,
2139 ts->abis_ip.rtp_payload2);
2140 if (rc < 0)
2141 return rc;
2142 ts = lchan->ts;
2143 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2144 ts->abis_ip.bound_port,
2145 remote_lchan->ts->abis_ip.conn_id,
2146 ts->abis_ip.rtp_payload2);
2147 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002148 break;
2149 case GSM_BTS_TYPE_BS11:
2150 trau_mux_map_lchan(lchan, remote_lchan);
2151 break;
2152 default:
2153 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002154 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002155 break;
2156 }
Harald Welte49f48b82009-02-17 15:29:33 +00002157
2158 return 0;
2159}
2160
Harald Welte4bfdfe72009-06-10 23:11:52 +08002161/* bridge channels of two transactions */
2162static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002163{
Harald Weltedcaf5652009-07-23 18:56:43 +02002164 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2165 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002166
Harald Welte4bfdfe72009-06-10 23:11:52 +08002167 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002168 return -EIO;
2169
Harald Welte4bfdfe72009-06-10 23:11:52 +08002170 if (!trans1->lchan || !trans2->lchan)
2171 return -EIO;
2172
2173 /* through-connect channel */
2174 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002175}
2176
Harald Welte4bfdfe72009-06-10 23:11:52 +08002177/* enable receive of channels to upqueue */
2178static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2179{
2180 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002181
Harald Welte4bfdfe72009-06-10 23:11:52 +08002182 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002183 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002184 if (!trans)
2185 return -EIO;
2186 if (!trans->lchan)
2187 return 0;
2188
2189 // todo IPACCESS
2190 if (enable)
2191 return trau_recv_lchan(trans->lchan, data->callref);
2192 return trau_mux_unmap(NULL, data->callref);
2193}
2194
2195/* send a frame to channel */
2196static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2197{
2198 struct gsm_trans *trans;
2199
2200 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002201 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002202 if (!trans)
2203 return -EIO;
2204 if (!trans->lchan)
2205 return 0;
2206 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2207 trans->lchan->type != GSM_LCHAN_TCH_H)
2208 return 0;
2209
2210 // todo IPACCESS
2211 return trau_send_lchan(trans->lchan,
2212 (struct decoded_trau_frame *)frame->data);
2213}
2214
2215
2216static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2217{
2218 DEBUGP(DCC, "-> STATUS ENQ\n");
2219 return gsm48_cc_tx_status(trans, msg);
2220}
2221
2222static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2223static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2224
2225static void gsm48_cc_timeout(void *arg)
2226{
2227 struct gsm_trans *trans = arg;
2228 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002229 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2230 int mo_location = GSM48_CAUSE_LOC_USER;
2231 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2232 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002233 struct gsm_mncc mo_rel, l4_rel;
2234
2235 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2236 mo_rel.callref = trans->callref;
2237 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2238 l4_rel.callref = trans->callref;
2239
Harald Weltedcaf5652009-07-23 18:56:43 +02002240 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002241 case 0x303:
2242 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002243 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002244 break;
2245 case 0x310:
2246 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002247 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002248 break;
2249 case 0x313:
2250 disconnect = 1;
2251 /* unknown, did not find it in the specs */
2252 break;
2253 case 0x301:
2254 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002255 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002256 break;
2257 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002258 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002259 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002260 gsm48_cc_tx_release(trans, &trans->cc.msg);
2261 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002262 break; /* stay in release state */
2263 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002264 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002265 return;
2266// release = 1;
2267// l4_cause = 14;
2268// break;
2269 case 0x306:
2270 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002271 mo_cause = trans->cc.msg.cause.value;
2272 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002273 break;
2274 case 0x323:
2275 disconnect = 1;
2276 break;
2277 default:
2278 release = 1;
2279 }
2280
2281 if (release && trans->callref) {
2282 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002283 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002284 l4_location, l4_cause);
2285 trans->callref = 0;
2286 }
2287
2288 if (disconnect && trans->callref) {
2289 /* process disconnect towards layer 4 */
2290 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002291 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002292 }
2293
2294 /* process disconnect towards mobile station */
2295 if (disconnect || release) {
2296 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002297 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2298 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2299 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002300 mo_rel.cause.diag_len = 3;
2301
2302 if (disconnect)
2303 gsm48_cc_tx_disconnect(trans, &mo_rel);
2304 if (release)
2305 gsm48_cc_tx_release(trans, &mo_rel);
2306 }
2307
2308}
2309
2310static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2311 int sec, int micro)
2312{
2313 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002314 trans->cc.timer.cb = gsm48_cc_timeout;
2315 trans->cc.timer.data = trans;
2316 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2317 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002318}
2319
2320static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2321{
2322 struct gsm48_hdr *gh = msgb_l3(msg);
2323 u_int8_t msg_type = gh->msg_type & 0xbf;
2324 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2325 struct tlv_parsed tp;
2326 struct gsm_mncc setup;
2327
2328 memset(&setup, 0, sizeof(struct gsm_mncc));
2329 setup.callref = trans->callref;
2330 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2331 /* emergency setup is identified by msg_type */
2332 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2333 setup.emergency = 1;
2334
2335 /* use subscriber as calling party number */
2336 if (trans->subscr) {
2337 setup.fields |= MNCC_F_CALLING;
2338 strncpy(setup.calling.number, trans->subscr->extension,
2339 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002340 strncpy(setup.imsi, trans->subscr->imsi,
2341 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002342 }
2343 /* bearer capability */
2344 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2345 setup.fields |= MNCC_F_BEARER_CAP;
2346 decode_bearer_cap(&setup.bearer_cap,
2347 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2348 }
2349 /* facility */
2350 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2351 setup.fields |= MNCC_F_FACILITY;
2352 decode_facility(&setup.facility,
2353 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2354 }
2355 /* called party bcd number */
2356 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2357 setup.fields |= MNCC_F_CALLED;
2358 decode_called(&setup.called,
2359 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2360 }
2361 /* user-user */
2362 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2363 setup.fields |= MNCC_F_USERUSER;
2364 decode_useruser(&setup.useruser,
2365 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2366 }
2367 /* ss-version */
2368 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2369 setup.fields |= MNCC_F_SSVERSION;
2370 decode_ssversion(&setup.ssversion,
2371 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2372 }
2373 /* CLIR suppression */
2374 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2375 setup.clir.sup = 1;
2376 /* CLIR invocation */
2377 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2378 setup.clir.inv = 1;
2379 /* cc cap */
2380 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2381 setup.fields |= MNCC_F_CCCAP;
2382 decode_cccap(&setup.cccap,
2383 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2384 }
2385
Harald Welte4bfdfe72009-06-10 23:11:52 +08002386 new_cc_state(trans, GSM_CSTATE_INITIATED);
2387
2388 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002389 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002390
Harald Welte13cac662009-07-29 12:10:35 +02002391 /* MNCC code will modify the channel asynchronously, we should
2392 * ipaccess-bind only after the modification has been made to the
2393 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002394 return 0;
2395}
2396
2397static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002398{
2399 struct msgb *msg = gsm48_msgb_alloc();
2400 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002401 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002402 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002403
Harald Welte7ccf7782009-02-17 01:43:01 +00002404 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002405
Harald Welte4bfdfe72009-06-10 23:11:52 +08002406 /* transaction id must not be assigned */
2407 if (trans->transaction_id != 0xff) { /* unasssigned */
2408 DEBUGP(DCC, "TX Setup with assigned transaction. "
2409 "This is not allowed!\n");
2410 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002411 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002412 GSM48_CAUSE_LOC_PRN_S_LU,
2413 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002414 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002415 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002416 return rc;
2417 }
2418
2419 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002420 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2421 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002422 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002423 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002424 GSM48_CAUSE_LOC_PRN_S_LU,
2425 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002426 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002427 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002428 return rc;
2429 }
Harald Welte78283ef2009-07-23 21:36:44 +02002430 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002431
Harald Welte65e74cc2008-12-29 01:55:35 +00002432 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002433
Harald Welte4bfdfe72009-06-10 23:11:52 +08002434 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002435
Harald Welte4bfdfe72009-06-10 23:11:52 +08002436 /* bearer capability */
2437 if (setup->fields & MNCC_F_BEARER_CAP)
2438 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2439 /* facility */
2440 if (setup->fields & MNCC_F_FACILITY)
2441 encode_facility(msg, 0, &setup->facility);
2442 /* progress */
2443 if (setup->fields & MNCC_F_PROGRESS)
2444 encode_progress(msg, 0, &setup->progress);
2445 /* calling party BCD number */
2446 if (setup->fields & MNCC_F_CALLING)
2447 encode_calling(msg, &setup->calling);
2448 /* called party BCD number */
2449 if (setup->fields & MNCC_F_CALLED)
2450 encode_called(msg, &setup->called);
2451 /* user-user */
2452 if (setup->fields & MNCC_F_USERUSER)
2453 encode_useruser(msg, 0, &setup->useruser);
2454 /* redirecting party BCD number */
2455 if (setup->fields & MNCC_F_REDIRECTING)
2456 encode_redirecting(msg, &setup->redirecting);
2457 /* signal */
2458 if (setup->fields & MNCC_F_SIGNAL)
2459 encode_signal(msg, setup->signal);
2460
2461 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002462
Harald Welte39e2ead2009-07-23 21:13:03 +02002463 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002464}
2465
Harald Welte4bfdfe72009-06-10 23:11:52 +08002466static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2467{
2468 struct gsm48_hdr *gh = msgb_l3(msg);
2469 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2470 struct tlv_parsed tp;
2471 struct gsm_mncc call_conf;
2472
2473 gsm48_stop_cc_timer(trans);
2474 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2475
2476 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2477 call_conf.callref = trans->callref;
2478 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2479#if 0
2480 /* repeat */
2481 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2482 call_conf.repeat = 1;
2483 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2484 call_conf.repeat = 2;
2485#endif
2486 /* bearer capability */
2487 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2488 call_conf.fields |= MNCC_F_BEARER_CAP;
2489 decode_bearer_cap(&call_conf.bearer_cap,
2490 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2491 }
2492 /* cause */
2493 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2494 call_conf.fields |= MNCC_F_CAUSE;
2495 decode_cause(&call_conf.cause,
2496 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2497 }
2498 /* cc cap */
2499 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2500 call_conf.fields |= MNCC_F_CCCAP;
2501 decode_cccap(&call_conf.cccap,
2502 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2503 }
2504
2505 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2506
Harald Welte596fed42009-07-23 19:06:52 +02002507 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2508 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002509}
2510
2511static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2512{
2513 struct gsm_mncc *proceeding = arg;
2514 struct msgb *msg = gsm48_msgb_alloc();
2515 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2516
Harald Welte4bfdfe72009-06-10 23:11:52 +08002517 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2518
2519 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2520
2521 /* bearer capability */
2522 if (proceeding->fields & MNCC_F_BEARER_CAP)
2523 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2524 /* facility */
2525 if (proceeding->fields & MNCC_F_FACILITY)
2526 encode_facility(msg, 0, &proceeding->facility);
2527 /* progress */
2528 if (proceeding->fields & MNCC_F_PROGRESS)
2529 encode_progress(msg, 0, &proceeding->progress);
2530
Harald Welte39e2ead2009-07-23 21:13:03 +02002531 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002532}
2533
2534static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2535{
2536 struct gsm48_hdr *gh = msgb_l3(msg);
2537 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2538 struct tlv_parsed tp;
2539 struct gsm_mncc alerting;
2540
2541 gsm48_stop_cc_timer(trans);
2542 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2543
2544 memset(&alerting, 0, sizeof(struct gsm_mncc));
2545 alerting.callref = trans->callref;
2546 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2547 /* facility */
2548 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2549 alerting.fields |= MNCC_F_FACILITY;
2550 decode_facility(&alerting.facility,
2551 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2552 }
2553
2554 /* progress */
2555 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2556 alerting.fields |= MNCC_F_PROGRESS;
2557 decode_progress(&alerting.progress,
2558 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2559 }
2560 /* ss-version */
2561 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2562 alerting.fields |= MNCC_F_SSVERSION;
2563 decode_ssversion(&alerting.ssversion,
2564 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2565 }
2566
2567 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2568
Harald Welte596fed42009-07-23 19:06:52 +02002569 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2570 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002571}
2572
2573static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2574{
2575 struct gsm_mncc *alerting = arg;
2576 struct msgb *msg = gsm48_msgb_alloc();
2577 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2578
Harald Welte4bfdfe72009-06-10 23:11:52 +08002579 gh->msg_type = GSM48_MT_CC_ALERTING;
2580
2581 /* facility */
2582 if (alerting->fields & MNCC_F_FACILITY)
2583 encode_facility(msg, 0, &alerting->facility);
2584 /* progress */
2585 if (alerting->fields & MNCC_F_PROGRESS)
2586 encode_progress(msg, 0, &alerting->progress);
2587 /* user-user */
2588 if (alerting->fields & MNCC_F_USERUSER)
2589 encode_useruser(msg, 0, &alerting->useruser);
2590
2591 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2592
Harald Welte39e2ead2009-07-23 21:13:03 +02002593 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002594}
2595
2596static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2597{
2598 struct gsm_mncc *progress = arg;
2599 struct msgb *msg = gsm48_msgb_alloc();
2600 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2601
Harald Welte4bfdfe72009-06-10 23:11:52 +08002602 gh->msg_type = GSM48_MT_CC_PROGRESS;
2603
2604 /* progress */
2605 encode_progress(msg, 1, &progress->progress);
2606 /* user-user */
2607 if (progress->fields & MNCC_F_USERUSER)
2608 encode_useruser(msg, 0, &progress->useruser);
2609
Harald Welte39e2ead2009-07-23 21:13:03 +02002610 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002611}
2612
2613static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2614{
2615 struct gsm_mncc *connect = arg;
2616 struct msgb *msg = gsm48_msgb_alloc();
2617 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2618
Harald Welte4bfdfe72009-06-10 23:11:52 +08002619 gh->msg_type = GSM48_MT_CC_CONNECT;
2620
2621 gsm48_stop_cc_timer(trans);
2622 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2623
2624 /* facility */
2625 if (connect->fields & MNCC_F_FACILITY)
2626 encode_facility(msg, 0, &connect->facility);
2627 /* progress */
2628 if (connect->fields & MNCC_F_PROGRESS)
2629 encode_progress(msg, 0, &connect->progress);
2630 /* connected number */
2631 if (connect->fields & MNCC_F_CONNECTED)
2632 encode_connected(msg, &connect->connected);
2633 /* user-user */
2634 if (connect->fields & MNCC_F_USERUSER)
2635 encode_useruser(msg, 0, &connect->useruser);
2636
2637 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2638
Harald Welte39e2ead2009-07-23 21:13:03 +02002639 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002640}
2641
2642static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2643{
2644 struct gsm48_hdr *gh = msgb_l3(msg);
2645 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2646 struct tlv_parsed tp;
2647 struct gsm_mncc connect;
2648
2649 gsm48_stop_cc_timer(trans);
2650
2651 memset(&connect, 0, sizeof(struct gsm_mncc));
2652 connect.callref = trans->callref;
2653 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2654 /* use subscriber as connected party number */
2655 if (trans->subscr) {
2656 connect.fields |= MNCC_F_CONNECTED;
2657 strncpy(connect.connected.number, trans->subscr->extension,
2658 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002659 strncpy(connect.imsi, trans->subscr->imsi,
2660 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002661 }
2662 /* facility */
2663 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2664 connect.fields |= MNCC_F_FACILITY;
2665 decode_facility(&connect.facility,
2666 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2667 }
2668 /* user-user */
2669 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2670 connect.fields |= MNCC_F_USERUSER;
2671 decode_useruser(&connect.useruser,
2672 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2673 }
2674 /* ss-version */
2675 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2676 connect.fields |= MNCC_F_SSVERSION;
2677 decode_ssversion(&connect.ssversion,
2678 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2679 }
2680
2681 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2682
Harald Welte596fed42009-07-23 19:06:52 +02002683 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002684}
2685
2686
2687static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2688{
2689 struct gsm_mncc connect_ack;
2690
2691 gsm48_stop_cc_timer(trans);
2692
2693 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2694
2695 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2696 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002697 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002698 &connect_ack);
2699}
2700
2701static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2702{
2703 struct msgb *msg = gsm48_msgb_alloc();
2704 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2705
Harald Welte4bfdfe72009-06-10 23:11:52 +08002706 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2707
2708 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2709
Harald Welte39e2ead2009-07-23 21:13:03 +02002710 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002711}
2712
2713static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2714{
2715 struct gsm48_hdr *gh = msgb_l3(msg);
2716 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2717 struct tlv_parsed tp;
2718 struct gsm_mncc disc;
2719
2720 gsm48_stop_cc_timer(trans);
2721
2722 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2723
2724 memset(&disc, 0, sizeof(struct gsm_mncc));
2725 disc.callref = trans->callref;
2726 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2727 /* cause */
2728 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2729 disc.fields |= MNCC_F_CAUSE;
2730 decode_cause(&disc.cause,
2731 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2732 }
2733 /* facility */
2734 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2735 disc.fields |= MNCC_F_FACILITY;
2736 decode_facility(&disc.facility,
2737 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2738 }
2739 /* user-user */
2740 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2741 disc.fields |= MNCC_F_USERUSER;
2742 decode_useruser(&disc.useruser,
2743 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2744 }
2745 /* ss-version */
2746 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2747 disc.fields |= MNCC_F_SSVERSION;
2748 decode_ssversion(&disc.ssversion,
2749 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2750 }
2751
Harald Welte596fed42009-07-23 19:06:52 +02002752 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002753
2754}
2755
Harald Weltec66b71c2009-06-11 14:23:20 +08002756static struct gsm_mncc_cause default_cause = {
2757 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2758 .coding = 0,
2759 .rec = 0,
2760 .rec_val = 0,
2761 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2762 .diag_len = 0,
2763 .diag = { 0 },
2764};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002765
2766static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2767{
2768 struct gsm_mncc *disc = arg;
2769 struct msgb *msg = gsm48_msgb_alloc();
2770 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2771
Harald Welte4bfdfe72009-06-10 23:11:52 +08002772 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2773
2774 gsm48_stop_cc_timer(trans);
2775 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2776
2777 /* cause */
2778 if (disc->fields & MNCC_F_CAUSE)
2779 encode_cause(msg, 1, &disc->cause);
2780 else
2781 encode_cause(msg, 1, &default_cause);
2782
2783 /* facility */
2784 if (disc->fields & MNCC_F_FACILITY)
2785 encode_facility(msg, 0, &disc->facility);
2786 /* progress */
2787 if (disc->fields & MNCC_F_PROGRESS)
2788 encode_progress(msg, 0, &disc->progress);
2789 /* user-user */
2790 if (disc->fields & MNCC_F_USERUSER)
2791 encode_useruser(msg, 0, &disc->useruser);
2792
2793 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002794 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002795
2796 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2797
Harald Welte39e2ead2009-07-23 21:13:03 +02002798 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002799}
2800
2801static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2802{
2803 struct gsm48_hdr *gh = msgb_l3(msg);
2804 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2805 struct tlv_parsed tp;
2806 struct gsm_mncc rel;
2807 int rc;
2808
2809 gsm48_stop_cc_timer(trans);
2810
2811 memset(&rel, 0, sizeof(struct gsm_mncc));
2812 rel.callref = trans->callref;
2813 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2814 /* cause */
2815 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2816 rel.fields |= MNCC_F_CAUSE;
2817 decode_cause(&rel.cause,
2818 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2819 }
2820 /* facility */
2821 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2822 rel.fields |= MNCC_F_FACILITY;
2823 decode_facility(&rel.facility,
2824 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2825 }
2826 /* user-user */
2827 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2828 rel.fields |= MNCC_F_USERUSER;
2829 decode_useruser(&rel.useruser,
2830 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2831 }
2832 /* ss-version */
2833 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2834 rel.fields |= MNCC_F_SSVERSION;
2835 decode_ssversion(&rel.ssversion,
2836 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2837 }
2838
Harald Weltedcaf5652009-07-23 18:56:43 +02002839 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002840 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002841 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002842 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002843 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002844 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002845 GSM48_MT_CC_RELEASE_COMPL);
2846 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002847 }
2848
2849 new_cc_state(trans, GSM_CSTATE_NULL);
2850
2851 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002852 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002853
2854 return rc;
2855}
2856
2857static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2858{
2859 struct gsm_mncc *rel = arg;
2860 struct msgb *msg = gsm48_msgb_alloc();
2861 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2862
Harald Welte4bfdfe72009-06-10 23:11:52 +08002863 gh->msg_type = GSM48_MT_CC_RELEASE;
2864
2865 trans->callref = 0;
2866
2867 gsm48_stop_cc_timer(trans);
2868 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2869
2870 /* cause */
2871 if (rel->fields & MNCC_F_CAUSE)
2872 encode_cause(msg, 0, &rel->cause);
2873 /* facility */
2874 if (rel->fields & MNCC_F_FACILITY)
2875 encode_facility(msg, 0, &rel->facility);
2876 /* user-user */
2877 if (rel->fields & MNCC_F_USERUSER)
2878 encode_useruser(msg, 0, &rel->useruser);
2879
Harald Weltedcaf5652009-07-23 18:56:43 +02002880 trans->cc.T308_second = 0;
2881 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002882
Harald Weltedcaf5652009-07-23 18:56:43 +02002883 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002884 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2885
Harald Welte39e2ead2009-07-23 21:13:03 +02002886 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002887}
2888
2889static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2890{
2891 struct gsm48_hdr *gh = msgb_l3(msg);
2892 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2893 struct tlv_parsed tp;
2894 struct gsm_mncc rel;
2895 int rc = 0;
2896
2897 gsm48_stop_cc_timer(trans);
2898
2899 memset(&rel, 0, sizeof(struct gsm_mncc));
2900 rel.callref = trans->callref;
2901 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2902 /* cause */
2903 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2904 rel.fields |= MNCC_F_CAUSE;
2905 decode_cause(&rel.cause,
2906 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2907 }
2908 /* facility */
2909 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2910 rel.fields |= MNCC_F_FACILITY;
2911 decode_facility(&rel.facility,
2912 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2913 }
2914 /* user-user */
2915 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2916 rel.fields |= MNCC_F_USERUSER;
2917 decode_useruser(&rel.useruser,
2918 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2919 }
2920 /* ss-version */
2921 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2922 rel.fields |= MNCC_F_SSVERSION;
2923 decode_ssversion(&rel.ssversion,
2924 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2925 }
2926
2927 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002928 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002929 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002930 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002931 MNCC_REJ_IND, &rel);
2932 break;
2933 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002934 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002935 MNCC_REL_CNF, &rel);
2936 break;
2937 default:
Harald Welte596fed42009-07-23 19:06:52 +02002938 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002939 MNCC_REL_IND, &rel);
2940 }
2941 }
2942
2943 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002944 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002945
2946 return rc;
2947}
2948
2949static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2950{
2951 struct gsm_mncc *rel = arg;
2952 struct msgb *msg = gsm48_msgb_alloc();
2953 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2954
Harald Welte4bfdfe72009-06-10 23:11:52 +08002955 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2956
2957 trans->callref = 0;
2958
2959 gsm48_stop_cc_timer(trans);
2960
2961 /* cause */
2962 if (rel->fields & MNCC_F_CAUSE)
2963 encode_cause(msg, 0, &rel->cause);
2964 /* facility */
2965 if (rel->fields & MNCC_F_FACILITY)
2966 encode_facility(msg, 0, &rel->facility);
2967 /* user-user */
2968 if (rel->fields & MNCC_F_USERUSER)
2969 encode_useruser(msg, 0, &rel->useruser);
2970
Harald Weltedcaf5652009-07-23 18:56:43 +02002971 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002972
Harald Welte39e2ead2009-07-23 21:13:03 +02002973 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002974}
2975
2976static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2977{
2978 struct gsm48_hdr *gh = msgb_l3(msg);
2979 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2980 struct tlv_parsed tp;
2981 struct gsm_mncc fac;
2982
2983 memset(&fac, 0, sizeof(struct gsm_mncc));
2984 fac.callref = trans->callref;
2985 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2986 /* facility */
2987 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2988 fac.fields |= MNCC_F_FACILITY;
2989 decode_facility(&fac.facility,
2990 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2991 }
2992 /* ss-version */
2993 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2994 fac.fields |= MNCC_F_SSVERSION;
2995 decode_ssversion(&fac.ssversion,
2996 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2997 }
2998
Harald Welte596fed42009-07-23 19:06:52 +02002999 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003000}
3001
3002static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
3003{
3004 struct gsm_mncc *fac = arg;
3005 struct msgb *msg = gsm48_msgb_alloc();
3006 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3007
Harald Welte4bfdfe72009-06-10 23:11:52 +08003008 gh->msg_type = GSM48_MT_CC_FACILITY;
3009
3010 /* facility */
3011 encode_facility(msg, 1, &fac->facility);
3012
Harald Welte39e2ead2009-07-23 21:13:03 +02003013 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003014}
3015
3016static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
3017{
3018 struct gsm_mncc hold;
3019
3020 memset(&hold, 0, sizeof(struct gsm_mncc));
3021 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003022 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003023}
3024
3025static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
3026{
3027 struct msgb *msg = gsm48_msgb_alloc();
3028 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3029
Harald Welte4bfdfe72009-06-10 23:11:52 +08003030 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
3031
Harald Welte39e2ead2009-07-23 21:13:03 +02003032 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003033}
3034
3035static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
3036{
3037 struct gsm_mncc *hold_rej = 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_HOLD_REJ;
3042
3043 /* cause */
3044 if (hold_rej->fields & MNCC_F_CAUSE)
3045 encode_cause(msg, 1, &hold_rej->cause);
3046 else
3047 encode_cause(msg, 1, &default_cause);
3048
Harald Welte39e2ead2009-07-23 21:13:03 +02003049 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003050}
3051
3052static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
3053{
3054 struct gsm_mncc retrieve;
3055
3056 memset(&retrieve, 0, sizeof(struct gsm_mncc));
3057 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003058 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
3059 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003060}
3061
3062static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
3063{
3064 struct msgb *msg = gsm48_msgb_alloc();
3065 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3066
Harald Welte4bfdfe72009-06-10 23:11:52 +08003067 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3068
Harald Welte39e2ead2009-07-23 21:13:03 +02003069 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003070}
3071
3072static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3073{
3074 struct gsm_mncc *retrieve_rej = arg;
3075 struct msgb *msg = gsm48_msgb_alloc();
3076 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3077
Harald Welte4bfdfe72009-06-10 23:11:52 +08003078 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3079
3080 /* cause */
3081 if (retrieve_rej->fields & MNCC_F_CAUSE)
3082 encode_cause(msg, 1, &retrieve_rej->cause);
3083 else
3084 encode_cause(msg, 1, &default_cause);
3085
Harald Welte39e2ead2009-07-23 21:13:03 +02003086 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003087}
3088
3089static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3090{
3091 struct gsm48_hdr *gh = msgb_l3(msg);
3092 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3093 struct tlv_parsed tp;
3094 struct gsm_mncc dtmf;
3095
3096 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3097 dtmf.callref = trans->callref;
3098 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3099 /* keypad facility */
3100 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3101 dtmf.fields |= MNCC_F_KEYPAD;
3102 decode_keypad(&dtmf.keypad,
3103 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3104 }
3105
Harald Welte596fed42009-07-23 19:06:52 +02003106 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003107}
3108
3109static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3110{
3111 struct gsm_mncc *dtmf = arg;
3112 struct msgb *msg = gsm48_msgb_alloc();
3113 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3114
Harald Welte4bfdfe72009-06-10 23:11:52 +08003115 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3116
3117 /* keypad */
3118 if (dtmf->fields & MNCC_F_KEYPAD)
3119 encode_keypad(msg, dtmf->keypad);
3120
Harald Welte39e2ead2009-07-23 21:13:03 +02003121 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003122}
3123
3124static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3125{
3126 struct gsm_mncc *dtmf = arg;
3127 struct msgb *msg = gsm48_msgb_alloc();
3128 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3129
Harald Welte4bfdfe72009-06-10 23:11:52 +08003130 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3131
3132 /* cause */
3133 if (dtmf->fields & MNCC_F_CAUSE)
3134 encode_cause(msg, 1, &dtmf->cause);
3135 else
3136 encode_cause(msg, 1, &default_cause);
3137
Harald Welte39e2ead2009-07-23 21:13:03 +02003138 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003139}
3140
3141static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3142{
3143 struct msgb *msg = gsm48_msgb_alloc();
3144 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3145
Harald Welte4bfdfe72009-06-10 23:11:52 +08003146 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3147
Harald Welte39e2ead2009-07-23 21:13:03 +02003148 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003149}
3150
3151static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3152{
3153 struct gsm_mncc dtmf;
3154
3155 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3156 dtmf.callref = trans->callref;
3157
Harald Welte596fed42009-07-23 19:06:52 +02003158 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003159}
3160
3161static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3162{
3163 struct gsm48_hdr *gh = msgb_l3(msg);
3164 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3165 struct tlv_parsed tp;
3166 struct gsm_mncc modify;
3167
3168 memset(&modify, 0, sizeof(struct gsm_mncc));
3169 modify.callref = trans->callref;
3170 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3171 /* bearer capability */
3172 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3173 modify.fields |= MNCC_F_BEARER_CAP;
3174 decode_bearer_cap(&modify.bearer_cap,
3175 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3176 }
3177
3178 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3179
Harald Welte596fed42009-07-23 19:06:52 +02003180 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003181}
3182
3183static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3184{
3185 struct gsm_mncc *modify = arg;
3186 struct msgb *msg = gsm48_msgb_alloc();
3187 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3188
Harald Welte4bfdfe72009-06-10 23:11:52 +08003189 gh->msg_type = GSM48_MT_CC_MODIFY;
3190
3191 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3192
3193 /* bearer capability */
3194 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3195
3196 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3197
Harald Welte39e2ead2009-07-23 21:13:03 +02003198 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003199}
3200
3201static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3202{
3203 struct gsm48_hdr *gh = msgb_l3(msg);
3204 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3205 struct tlv_parsed tp;
3206 struct gsm_mncc modify;
3207
3208 gsm48_stop_cc_timer(trans);
3209
3210 memset(&modify, 0, sizeof(struct gsm_mncc));
3211 modify.callref = trans->callref;
3212 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3213 /* bearer capability */
3214 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3215 modify.fields |= MNCC_F_BEARER_CAP;
3216 decode_bearer_cap(&modify.bearer_cap,
3217 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3218 }
3219
3220 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3221
Harald Welte596fed42009-07-23 19:06:52 +02003222 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003223}
3224
3225static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3226{
3227 struct gsm_mncc *modify = arg;
3228 struct msgb *msg = gsm48_msgb_alloc();
3229 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3230
Harald Welte4bfdfe72009-06-10 23:11:52 +08003231 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3232
3233 /* bearer capability */
3234 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3235
3236 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3237
Harald Welte39e2ead2009-07-23 21:13:03 +02003238 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003239}
3240
3241static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3242{
3243 struct gsm48_hdr *gh = msgb_l3(msg);
3244 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3245 struct tlv_parsed tp;
3246 struct gsm_mncc modify;
3247
3248 gsm48_stop_cc_timer(trans);
3249
3250 memset(&modify, 0, sizeof(struct gsm_mncc));
3251 modify.callref = trans->callref;
3252 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3253 /* bearer capability */
3254 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3255 modify.fields |= GSM48_IE_BEARER_CAP;
3256 decode_bearer_cap(&modify.bearer_cap,
3257 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3258 }
3259 /* cause */
3260 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3261 modify.fields |= MNCC_F_CAUSE;
3262 decode_cause(&modify.cause,
3263 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3264 }
3265
3266 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3267
Harald Welte596fed42009-07-23 19:06:52 +02003268 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003269}
3270
3271static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3272{
3273 struct gsm_mncc *modify = arg;
3274 struct msgb *msg = gsm48_msgb_alloc();
3275 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3276
Harald Welte4bfdfe72009-06-10 23:11:52 +08003277 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3278
3279 /* bearer capability */
3280 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3281 /* cause */
3282 encode_cause(msg, 1, &modify->cause);
3283
3284 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3285
Harald Welte39e2ead2009-07-23 21:13:03 +02003286 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003287}
3288
3289static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3290{
3291 struct gsm_mncc *notify = arg;
3292 struct msgb *msg = gsm48_msgb_alloc();
3293 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3294
Harald Welte4bfdfe72009-06-10 23:11:52 +08003295 gh->msg_type = GSM48_MT_CC_NOTIFY;
3296
3297 /* notify */
3298 encode_notify(msg, notify->notify);
3299
Harald Welte39e2ead2009-07-23 21:13:03 +02003300 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003301}
3302
3303static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3304{
3305 struct gsm48_hdr *gh = msgb_l3(msg);
3306 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3307// struct tlv_parsed tp;
3308 struct gsm_mncc notify;
3309
3310 memset(&notify, 0, sizeof(struct gsm_mncc));
3311 notify.callref = trans->callref;
3312// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3313 if (payload_len >= 1)
3314 decode_notify(&notify.notify, gh->data);
3315
Harald Welte596fed42009-07-23 19:06:52 +02003316 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003317}
3318
3319static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3320{
3321 struct gsm_mncc *user = arg;
3322 struct msgb *msg = gsm48_msgb_alloc();
3323 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3324
Harald Welte4bfdfe72009-06-10 23:11:52 +08003325 gh->msg_type = GSM48_MT_CC_USER_INFO;
3326
3327 /* user-user */
3328 if (user->fields & MNCC_F_USERUSER)
3329 encode_useruser(msg, 1, &user->useruser);
3330 /* more data */
3331 if (user->more)
3332 encode_more(msg);
3333
Harald Welte39e2ead2009-07-23 21:13:03 +02003334 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003335}
3336
3337static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3338{
3339 struct gsm48_hdr *gh = msgb_l3(msg);
3340 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3341 struct tlv_parsed tp;
3342 struct gsm_mncc user;
3343
3344 memset(&user, 0, sizeof(struct gsm_mncc));
3345 user.callref = trans->callref;
3346 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3347 /* user-user */
3348 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3349 user.fields |= MNCC_F_USERUSER;
3350 decode_useruser(&user.useruser,
3351 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3352 }
3353 /* more data */
3354 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3355 user.more = 1;
3356
Harald Welte596fed42009-07-23 19:06:52 +02003357 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003358}
3359
3360static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3361{
3362 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003363 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003364
Harald Welte13cac662009-07-29 12:10:35 +02003365 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3366 if (rc < 0)
3367 return rc;
3368
3369 /* FIXME: we not only need to do this after mode modify, but
3370 * also after channel activation */
3371 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3372 mode->lchan_mode != GSM48_CMODE_SIGN)
3373 rc = rsl_ipacc_bind(trans->lchan);
3374
3375 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003376}
3377
3378static struct downstate {
3379 u_int32_t states;
3380 int type;
3381 int (*rout) (struct gsm_trans *trans, void *arg);
3382} downstatelist[] = {
3383 /* mobile originating call establishment */
3384 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3385 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3386 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3387 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3388 {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 */
3389 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3390 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3391 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3392 /* mobile terminating call establishment */
3393 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3394 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3395 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3396 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3397 /* signalling during call */
3398 {SBIT(GSM_CSTATE_ACTIVE),
3399 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3400 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3401 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3402 {ALL_STATES,
3403 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3404 {ALL_STATES,
3405 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3406 {ALL_STATES,
3407 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3408 {SBIT(GSM_CSTATE_ACTIVE),
3409 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3410 {SBIT(GSM_CSTATE_ACTIVE),
3411 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3412 {SBIT(GSM_CSTATE_ACTIVE),
3413 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3414 {SBIT(GSM_CSTATE_ACTIVE),
3415 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3416 {SBIT(GSM_CSTATE_ACTIVE),
3417 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3418 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3419 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3420 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3421 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3422 {SBIT(GSM_CSTATE_ACTIVE),
3423 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3424 /* clearing */
3425 {SBIT(GSM_CSTATE_INITIATED),
3426 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3427 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3428 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3429 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3430 MNCC_REL_REQ, gsm48_cc_tx_release},
3431 /* special */
3432 {ALL_STATES,
3433 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3434};
3435
3436#define DOWNSLLEN \
3437 (sizeof(downstatelist) / sizeof(struct downstate))
3438
3439
3440int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3441{
Harald Welte1a6f7982009-08-09 18:52:33 +02003442 int i, rc = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003443 struct gsm_trans *trans = NULL, *transt;
3444 struct gsm_subscriber *subscr;
Harald Welte1a6f7982009-08-09 18:52:33 +02003445 struct gsm_lchan *lchan = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003446 struct gsm_bts *bts = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003447 struct gsm_mncc *data = arg, rel;
3448
3449 /* handle special messages */
3450 switch(msg_type) {
3451 case MNCC_BRIDGE:
3452 return tch_bridge(net, arg);
3453 case MNCC_FRAME_DROP:
3454 return tch_recv(net, arg, 0);
3455 case MNCC_FRAME_RECV:
3456 return tch_recv(net, arg, 1);
3457 case GSM_TRAU_FRAME:
3458 return tch_frame(net, arg);
3459 }
3460
3461 memset(&rel, 0, sizeof(struct gsm_mncc));
3462 rel.callref = data->callref;
3463
3464 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003465 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003466
3467 /* Callref unknown */
3468 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003469 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003470 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3471 "Received '%s' from MNCC with "
3472 "unknown callref %d\n", data->called.number,
3473 get_mncc_name(msg_type), data->callref);
3474 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003475 return mncc_release_ind(net, NULL, data->callref,
3476 GSM48_CAUSE_LOC_PRN_S_LU,
3477 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003478 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003479 if (!data->called.number[0] && !data->imsi[0]) {
3480 DEBUGP(DCC, "(bts - trx - ts - ti) "
3481 "Received '%s' from MNCC with "
3482 "no number or IMSI\n", get_mncc_name(msg_type));
3483 /* Invalid number */
3484 return mncc_release_ind(net, NULL, data->callref,
3485 GSM48_CAUSE_LOC_PRN_S_LU,
3486 GSM48_CC_CAUSE_INV_NR_FORMAT);
3487 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003488 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003489 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003490 subscr = subscr_get_by_extension(net,
3491 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003492 else
Harald Welte9176bd42009-07-23 18:46:00 +02003493 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003494 /* If subscriber is not found */
3495 if (!subscr) {
3496 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3497 "Received '%s' from MNCC with "
3498 "unknown subscriber %s\n", data->called.number,
3499 get_mncc_name(msg_type), data->called.number);
3500 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003501 return mncc_release_ind(net, NULL, data->callref,
3502 GSM48_CAUSE_LOC_PRN_S_LU,
3503 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003504 }
3505 /* If subscriber is not "attached" */
3506 if (!subscr->lac) {
3507 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3508 "Received '%s' from MNCC with "
3509 "detached subscriber %s\n", data->called.number,
3510 get_mncc_name(msg_type), data->called.number);
3511 subscr_put(subscr);
3512 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003513 return mncc_release_ind(net, NULL, data->callref,
3514 GSM48_CAUSE_LOC_PRN_S_LU,
3515 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003516 }
3517 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003518 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3519 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003520 DEBUGP(DCC, "No memory for trans.\n");
3521 subscr_put(subscr);
3522 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003523 mncc_release_ind(net, NULL, data->callref,
3524 GSM48_CAUSE_LOC_PRN_S_LU,
3525 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003526 return -ENOMEM;
3527 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003528 /* Find lchan */
Harald Welte1a6f7982009-08-09 18:52:33 +02003529 lchan = lchan_for_subscr(subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003530 /* If subscriber has no lchan */
3531 if (!lchan) {
3532 /* find transaction with this subscriber already paging */
3533 llist_for_each_entry(transt, &net->trans_list, entry) {
3534 /* Transaction of our lchan? */
3535 if (transt == trans ||
3536 transt->subscr != subscr)
3537 continue;
3538 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3539 "Received '%s' from MNCC with "
3540 "unallocated channel, paging already "
3541 "started.\n", bts->nr,
3542 data->called.number,
3543 get_mncc_name(msg_type));
3544 return 0;
3545 }
3546 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003547 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003548 /* Trigger paging */
3549 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3550 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003551 return 0;
3552 }
3553 /* Assign lchan */
3554 trans->lchan = lchan;
3555 use_lchan(lchan);
3556 }
3557 lchan = trans->lchan;
3558
3559 /* if paging did not respond yet */
3560 if (!lchan) {
3561 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3562 "Received '%s' from MNCC in paging state\n",
3563 (trans->subscr)?(trans->subscr->extension):"-",
3564 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003565 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3566 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003567 if (msg_type == MNCC_REL_REQ)
3568 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3569 else
3570 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3571 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003572 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003573 return rc;
3574 }
3575
3576 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3577 "Received '%s' from MNCC in state %d (%s)\n",
3578 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3579 trans->transaction_id,
3580 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003581 get_mncc_name(msg_type), trans->cc.state,
3582 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003583
3584 /* Find function for current state and message */
3585 for (i = 0; i < DOWNSLLEN; i++)
3586 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003587 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003588 break;
3589 if (i == DOWNSLLEN) {
3590 DEBUGP(DCC, "Message unhandled at this state.\n");
3591 return 0;
3592 }
3593
3594 rc = downstatelist[i].rout(trans, arg);
3595
3596 return rc;
3597}
3598
3599
3600static struct datastate {
3601 u_int32_t states;
3602 int type;
3603 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3604} datastatelist[] = {
3605 /* mobile originating call establishment */
3606 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3607 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3608 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3609 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3610 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3611 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3612 /* mobile terminating call establishment */
3613 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3614 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3615 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3616 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3617 {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 */
3618 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3619 /* signalling during call */
3620 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3621 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3622 {SBIT(GSM_CSTATE_ACTIVE),
3623 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3624 {ALL_STATES,
3625 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3626 {ALL_STATES,
3627 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3628 {ALL_STATES,
3629 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3630 {SBIT(GSM_CSTATE_ACTIVE),
3631 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3632 {SBIT(GSM_CSTATE_ACTIVE),
3633 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3634 {SBIT(GSM_CSTATE_ACTIVE),
3635 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3636 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3637 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3638 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3639 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3640 {SBIT(GSM_CSTATE_ACTIVE),
3641 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3642 /* clearing */
3643 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3644 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3645 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3646 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3647 {ALL_STATES, /* 5.4.3.4 */
3648 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3649};
3650
3651#define DATASLLEN \
3652 (sizeof(datastatelist) / sizeof(struct datastate))
3653
Harald Welte4bc90a12008-12-27 16:32:52 +00003654static int gsm0408_rcv_cc(struct msgb *msg)
3655{
3656 struct gsm48_hdr *gh = msgb_l3(msg);
3657 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003658 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003659 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003660 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003661 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003662
Harald Welte4bfdfe72009-06-10 23:11:52 +08003663 if (msg_type & 0x80) {
3664 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3665 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003666 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003667
3668 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003669 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003670
Harald Welte6f5aee02009-07-23 21:21:14 +02003671 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003672 "Received '%s' from MS in state %d (%s)\n",
3673 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3674 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003675 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3676 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003677
3678 /* Create transaction */
3679 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003680 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003681 "creating new trans.\n", transaction_id);
3682 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003683 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3684 transaction_id, new_callref++);
3685 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003686 DEBUGP(DCC, "No memory for trans.\n");
3687 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003688 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003689 GSM48_MT_CC_RELEASE_COMPL);
3690 return -ENOMEM;
3691 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003692 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003693 trans->lchan = lchan;
3694 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003695 }
3696
3697 /* find function for current state and message */
3698 for (i = 0; i < DATASLLEN; i++)
3699 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003700 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003701 break;
3702 if (i == DATASLLEN) {
3703 DEBUGP(DCC, "Message unhandled at this state.\n");
3704 return 0;
3705 }
3706
3707 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003708
3709 return rc;
3710}
3711
Harald Welte52b1f982008-12-23 20:25:15 +00003712/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3713int gsm0408_rcvmsg(struct msgb *msg)
3714{
3715 struct gsm48_hdr *gh = msgb_l3(msg);
3716 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003717 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003718
3719 switch (pdisc) {
3720 case GSM48_PDISC_CC:
3721 rc = gsm0408_rcv_cc(msg);
3722 break;
3723 case GSM48_PDISC_MM:
3724 rc = gsm0408_rcv_mm(msg);
3725 break;
3726 case GSM48_PDISC_RR:
3727 rc = gsm0408_rcv_rr(msg);
3728 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003729 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003730 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003731 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003732 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003733 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003734 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3735 pdisc);
3736 break;
3737 default:
3738 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3739 pdisc);
3740 break;
3741 }
3742
3743 return rc;
3744}
Harald Welte8470bf22008-12-25 23:28:35 +00003745
Harald Welte8470bf22008-12-25 23:28:35 +00003746/* Section 9.1.8 / Table 9.9 */
3747struct chreq {
3748 u_int8_t val;
3749 u_int8_t mask;
3750 enum chreq_type type;
3751};
3752
3753/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3754static const struct chreq chreq_type_neci1[] = {
3755 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3756 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3757 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3758 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3759 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3760 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3761 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3762 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3763 { 0x10, 0xf0, CHREQ_T_SDCCH },
3764 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3765 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3766 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3767};
3768
3769/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3770static const struct chreq chreq_type_neci0[] = {
3771 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3772 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3773 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3774 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3775 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3776 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3777 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3778 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3779};
3780
3781static const enum gsm_chan_t ctype_by_chreq[] = {
3782 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3783 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3784 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3785 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3786 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3787 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3788 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3789 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3790 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3791 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3792 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3793 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3794};
3795
Harald Weltee14a57c2008-12-29 04:08:28 +00003796static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3797 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3798 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3799 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3800 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3801 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3802 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3803 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3804 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3805 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3806 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3807 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3808 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3809};
3810
Harald Welte8470bf22008-12-25 23:28:35 +00003811enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3812{
3813 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003814 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Welte8470bf22008-12-25 23:28:35 +00003815
Harald Weltee58ca7c2009-08-10 02:14:46 +02003816 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3817 const struct chreq *chr = &chreq_type_neci0[i];
Harald Welte8470bf22008-12-25 23:28:35 +00003818 if ((ra & chr->mask) == chr->val)
3819 return ctype_by_chreq[chr->type];
3820 }
3821 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3822 return GSM_LCHAN_SDCCH;
3823}
Harald Weltee14a57c2008-12-29 04:08:28 +00003824
3825enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3826{
3827 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003828 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Weltee14a57c2008-12-29 04:08:28 +00003829
Harald Weltee58ca7c2009-08-10 02:14:46 +02003830 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3831 const struct chreq *chr = &chreq_type_neci0[i];
Harald Weltee14a57c2008-12-29 04:08:28 +00003832 if ((ra & chr->mask) == chr->val)
3833 return reason_by_chreq[chr->type];
3834 }
3835 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3836 return GSM_CHREQ_REASON_OTHER;
3837}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003838
3839/* dequeue messages to layer 4 */
3840int bsc_upqueue(struct gsm_network *net)
3841{
3842 struct gsm_mncc *mncc;
3843 struct msgb *msg;
3844 int work = 0;
3845
3846 if (net)
3847 while ((msg = msgb_dequeue(&net->upqueue))) {
3848 mncc = (struct gsm_mncc *)msg->data;
3849 if (net->mncc_recv)
3850 net->mncc_recv(net, mncc->msg_type, mncc);
3851 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003852 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003853 }
3854
3855 return work;
3856}
Harald Weltedcaf5652009-07-23 18:56:43 +02003857
Harald Welte805f6442009-07-28 18:25:29 +02003858/*
3859 * This will be ran by the linker when loading the DSO. We use it to
3860 * do system initialization, e.g. registration of signal handlers.
3861 */
3862static __attribute__((constructor)) void on_dso_load_0408(void)
3863{
3864 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3865 "loc_updating_oper");
3866 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3867 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3868}