blob: ec7b4d3394d388b55676b89de6f3258745fa2b1f [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
2 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
3
Harald Weltebf5e8df2009-02-03 12:59:45 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte498b0bb2009-01-09 21:27:43 +00005 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte8470bf22008-12-25 23:28:35 +00006 *
Harald Welte52b1f982008-12-23 20:25:15 +00007 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
Harald Weltedb253af2008-12-30 17:56:55 +000030#include <time.h>
Harald Welte4b634542008-12-27 01:55:51 +000031#include <netinet/in.h>
Harald Welte52b1f982008-12-23 20:25:15 +000032
Harald Welte75a983f2008-12-27 21:34:06 +000033#include <openbsc/db.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <openbsc/msgb.h>
Harald Welte7584aea2009-02-11 11:44:12 +000035#include <openbsc/tlv.h>
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <openbsc/debug.h>
37#include <openbsc/gsm_data.h>
38#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000039#include <openbsc/gsm_04_11.h>
Harald Welte8470bf22008-12-25 23:28:35 +000040#include <openbsc/gsm_04_08.h>
41#include <openbsc/abis_rsl.h>
Holger Freytherca362a62009-01-04 21:05:01 +000042#include <openbsc/chan_alloc.h>
Harald Welte0b4c34e2009-02-09 17:54:43 +000043#include <openbsc/paging.h>
Holger Freyther053e09d2009-02-14 22:51:06 +000044#include <openbsc/signal.h>
Harald Welte45b407a2009-05-23 15:51:12 +000045#include <openbsc/trau_frame.h>
Harald Welte11fa29c2009-02-19 17:24:39 +000046#include <openbsc/trau_mux.h>
Harald Welte805f6442009-07-28 18:25:29 +020047#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020048#include <openbsc/talloc.h>
Harald Weltedcaf5652009-07-23 18:56:43 +020049#include <openbsc/transaction.h>
Harald Welte52b1f982008-12-23 20:25:15 +000050
Harald Welte8470bf22008-12-25 23:28:35 +000051#define GSM48_ALLOC_SIZE 1024
52#define GSM48_ALLOC_HEADROOM 128
Harald Welte52b1f982008-12-23 20:25:15 +000053
Harald Welte0c389302009-06-10 12:08:54 +080054#define GSM_MAX_FACILITY 128
55#define GSM_MAX_SSVERSION 128
56#define GSM_MAX_USERUSER 128
57
Harald Welte2cf161b2009-06-20 22:36:41 +020058static void *tall_locop_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020059
Harald Welte805f6442009-07-28 18:25:29 +020060/* should ip.access BTS use direct RTP streams between each other (1),
61 * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
62int ipacc_rtp_direct = 1;
63
Harald Welte09e38af2009-02-16 22:52:23 +000064static const struct tlv_definition rsl_att_tlvdef = {
65 .def = {
66 [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
67 [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
68 [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
69 [GSM48_IE_UTC] = { TLV_TYPE_TV },
70 [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
71 [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
72
73 [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
74 [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
75 [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
76 [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
77 [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
78 [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
79 [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
Harald Welte0c389302009-06-10 12:08:54 +080080 [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
Harald Welte09e38af2009-02-16 22:52:23 +000081 [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
82 [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
Harald Welte0c389302009-06-10 12:08:54 +080083 [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
84 [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
Harald Welte09e38af2009-02-16 22:52:23 +000085 [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
86 [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
87 [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
88 [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
89 [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
90 [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
91 [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
92 [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
93 [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
94 [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
95 [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
96 [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
97 [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
98 [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
Harald Welte0c389302009-06-10 12:08:54 +080099 [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
100 [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
Harald Welte09e38af2009-02-16 22:52:23 +0000101 /* FIXME: more elements */
102 },
103};
Harald Weltecf5b3592009-05-01 18:28:42 +0000104
105static const char *rr_cause_names[] = {
106 [GSM48_RR_CAUSE_NORMAL] = "Normal event",
107 [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
108 [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
109 [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
110 [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
111 [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
112 [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
113 [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
114 [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
115 [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
116 [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
117 [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
118 [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
119 [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
120 [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
121 [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
122 [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
123};
124
Harald Welte4bfdfe72009-06-10 23:11:52 +0800125static const char *cc_state_names[] = {
126 "NULL",
127 "INITIATED",
128 "illegal state 2",
129 "MO_CALL_PROC",
130 "CALL_DELIVERED",
131 "illegal state 5",
132 "CALL_PRESENT",
133 "CALL_RECEIVED",
134 "CONNECT_REQUEST",
135 "MO_TERM_CALL_CONF",
136 "ACTIVE",
137 "DISCONNECT_REQ",
138 "DISCONNECT_IND",
139 "illegal state 13",
140 "illegal state 14",
141 "illegal state 15",
142 "illegal state 16",
143 "illegal state 17",
144 "illegal state 18",
145 "RELEASE_REQ",
146 "illegal state 20",
147 "illegal state 21",
148 "illegal state 22",
149 "illegal state 23",
150 "illegal state 24",
151 "illegal state 25",
152 "MO_ORIG_MODIFY",
153 "MO_TERM_MODIFY",
154 "CONNECT_IND",
155 "illegal state 29",
156 "illegal state 30",
157 "illegal state 31",
158};
159
160static const char *cc_msg_names[] = {
161 "unknown 0x00",
162 "ALERTING",
163 "CALL_PROC",
164 "PROGRESS",
165 "ESTAB",
166 "SETUP",
167 "ESTAB_CONF",
168 "CONNECT",
169 "CALL_CONF",
170 "START_CC",
171 "unknown 0x0a",
172 "RECALL",
173 "unknown 0x0c",
174 "unknown 0x0d",
175 "EMERG_SETUP",
176 "CONNECT_ACK",
177 "USER_INFO",
178 "unknown 0x11",
179 "unknown 0x12",
180 "MODIFY_REJECT",
181 "unknown 0x14",
182 "unknown 0x15",
183 "unknown 0x16",
184 "MODIFY",
185 "HOLD",
186 "HOLD_ACK",
187 "HOLD_REJ",
188 "unknown 0x1b",
189 "RETR",
190 "RETR_ACK",
191 "RETR_REJ",
192 "MODIFY_COMPL",
193 "unknown 0x20",
194 "unknown 0x21",
195 "unknown 0x22",
196 "unknown 0x23",
197 "unknown 0x24",
198 "DISCONNECT",
199 "unknown 0x26",
200 "unknown 0x27",
201 "unknown 0x28",
202 "unknown 0x29",
203 "RELEASE_COMPL",
204 "unknown 0x2b",
205 "unknown 0x2c",
206 "RELEASE",
207 "unknown 0x2e",
208 "unknown 0x2f",
209 "unknown 0x30",
210 "STOP_DTMF",
211 "STOP_DTMF_ACK",
212 "unknown 0x33",
213 "STATUS_ENQ",
214 "START_DTMF",
215 "START_DTMF_ACK",
216 "START_DTMF_REJ",
217 "unknown 0x38",
218 "CONG_CTRL",
219 "FACILITY",
220 "unknown 0x3b",
221 "STATUS",
222 "unknown 0x3c",
223 "NOTIFY",
224 "unknown 0x3f",
225};
226
Harald Weltecf5b3592009-05-01 18:28:42 +0000227static char strbuf[64];
228
229static const char *rr_cause_name(u_int8_t cause)
230{
231 if (cause < ARRAY_SIZE(rr_cause_names) &&
232 rr_cause_names[cause])
233 return rr_cause_names[cause];
234
235 snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
236 return strbuf;
237}
238
Harald Weltef7c43522009-06-09 20:24:21 +0000239static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
240 int len)
241{
242 memset(rep, 0, sizeof(*rep));
243
244 if (data[0] & 0x80)
245 rep->flags |= MEAS_REP_F_BA1;
246 if (data[0] & 0x40)
247 rep->flags |= MEAS_REP_F_DTX;
Harald Welte5a691b52009-07-05 04:05:44 +0200248 if ((data[1] & 0x40) == 0x00)
Harald Weltef7c43522009-06-09 20:24:21 +0000249 rep->flags |= MEAS_REP_F_VALID;
250
251 rep->rxlev_full = data[0] & 0x3f;
252 rep->rxlev_sub = data[1] & 0x3f;
253 rep->rxqual_full = (data[3] >> 4) & 0x7;
254 rep->rxqual_sub = (data[3] >> 1) & 0x7;
255 rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2);
256 if (rep->num_cell < 1)
257 return;
258
259 /* an encoding nightmare in perfection */
260
261 rep->cell[0].rxlev = data[4] & 0x3f;
262 rep->cell[0].bcch_freq = data[5] >> 2;
263 rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5);
264 if (rep->num_cell < 2)
265 return;
266
267 rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7);
268 rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f;
269 rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4);
270 if (rep->num_cell < 3)
271 return;
272
273 rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6);
274 rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f;
275 rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3);
276 if (rep->num_cell < 4)
277 return;
278
279 rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5);
280 rep->cell[3].bcch_freq = data[11] & 0x1f;
281 rep->cell[3].bsic = data[12] >> 2;
282 if (rep->num_cell < 5)
283 return;
284
285 rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4);
286 rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7);
287 rep->cell[4].bsic = (data[14] >> 1) & 0x3f;
288 if (rep->num_cell < 6)
289 return;
290
291 rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3);
292 rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6);
293 rep->cell[5].bsic = data[16] & 0x3f;
294}
295
Holger Freytherd51524f2009-06-09 08:27:07 +0000296int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
Harald Welte65e74cc2008-12-29 01:55:35 +0000297static int gsm48_tx_simple(struct gsm_lchan *lchan,
298 u_int8_t pdisc, u_int8_t msg_type);
Holger Freytherb7193e42008-12-29 17:44:08 +0000299static void schedule_reject(struct gsm_lchan *lchan);
Harald Welte65e74cc2008-12-29 01:55:35 +0000300
Harald Welte52b1f982008-12-23 20:25:15 +0000301struct gsm_lai {
302 u_int16_t mcc;
303 u_int16_t mnc;
304 u_int16_t lac;
305};
306
Holger Freyther89824fc2008-12-30 16:18:18 +0000307static int authorize_everonye = 0;
308void gsm0408_allow_everyone(int everyone)
309{
310 printf("Allowing everyone?\n");
311 authorize_everonye = everyone;
312}
313
Holger Freythere97f7fb2008-12-31 18:52:11 +0000314static int reject_cause = 0;
315void gsm0408_set_reject_cause(int cause)
316{
317 reject_cause = cause;
318}
319
Harald Welte4bfdfe72009-06-10 23:11:52 +0800320static u_int32_t new_callref = 0x80000001;
321
Holger Freyther73487a22008-12-31 18:53:57 +0000322static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
323 struct gsm_subscriber *subscriber)
Holger Freyther89824fc2008-12-30 16:18:18 +0000324{
325 if (!subscriber)
326 return 0;
327
Holger Freyther73487a22008-12-31 18:53:57 +0000328 /*
329 * Do not send accept yet as more information should arrive. Some
330 * phones will not send us the information and we will have to check
331 * what we want to do with that.
332 */
333 if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
334 return 0;
335
Holger Freyther89824fc2008-12-30 16:18:18 +0000336 if (authorize_everonye)
337 return 1;
338
339 return subscriber->authorized;
340}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000341
Holger Freyther73487a22008-12-31 18:53:57 +0000342static void release_loc_updating_req(struct gsm_lchan *lchan)
343{
Harald Welte179f0642008-12-31 23:59:18 +0000344 if (!lchan->loc_operation)
Holger Freyther73487a22008-12-31 18:53:57 +0000345 return;
346
Harald Welteff117a82009-05-23 05:22:08 +0000347 bsc_del_timer(&lchan->loc_operation->updating_timer);
Harald Welte2cf161b2009-06-20 22:36:41 +0200348 talloc_free(lchan->loc_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000349 lchan->loc_operation = 0;
Holger Freyther3eaa7922009-01-01 02:59:03 +0000350 put_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000351}
352
353static void allocate_loc_updating_req(struct gsm_lchan *lchan)
354{
Holger Freyther67b4b9a2009-01-01 03:46:11 +0000355 use_lchan(lchan);
Holger Freyther73487a22008-12-31 18:53:57 +0000356 release_loc_updating_req(lchan);
357
Harald Welte470ec292009-06-26 20:25:23 +0200358 lchan->loc_operation = talloc_zero(tall_locop_ctx,
359 struct gsm_loc_updating_operation);
Holger Freyther73487a22008-12-31 18:53:57 +0000360}
Holger Freyther07cc8d82008-12-29 06:23:46 +0000361
Holger Freytherd51524f2009-06-09 08:27:07 +0000362static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
363{
364 u_int32_t tmsi;
365
366 if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
Harald Welteee5ad162009-08-09 19:07:00 +0200367 int rc;
368
Holger Freytherd51524f2009-06-09 08:27:07 +0000369 db_subscriber_alloc_tmsi(lchan->subscr);
Holger Freytherd51524f2009-06-09 08:27:07 +0000370 tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
371 release_loc_updating_req(lchan);
Harald Welteee5ad162009-08-09 19:07:00 +0200372 rc = gsm0408_loc_upd_acc(msg->lchan, tmsi);
373 /* call subscr_update after putting the loc_upd_acc
374 * in the transmit queue, since S_SUBSCR_ATTACHED might
375 * trigger further action like SMS delivery */
376 subscr_update(lchan->subscr, msg->trx->bts,
377 GSM_SUBSCRIBER_UPDATE_ATTACHED);
378 return rc;
Holger Freytherd51524f2009-06-09 08:27:07 +0000379 }
380
381 return 0;
382}
383
Holger Freyther7c19f742009-06-06 13:54:35 +0000384static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
385 void *handler_data, void *signal_data)
386{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800387 struct gsm_trans *trans, *temp;
388
Holger Freyther7c19f742009-06-06 13:54:35 +0000389 if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
390 return 0;
391
392 /*
393 * Cancel any outstanding location updating request
394 * operation taking place on the lchan.
395 */
Harald Welte1a5c6bd2009-07-04 09:35:21 +0200396 struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
Harald Weltec05677b2009-06-26 20:17:06 +0200397 if (!lchan)
398 return 0;
399
Holger Freyther7c19f742009-06-06 13:54:35 +0000400 release_loc_updating_req(lchan);
401
Harald Welte4bfdfe72009-06-10 23:11:52 +0800402 /* Free all transactions that are associated with the released lchan */
Harald Weltedcaf5652009-07-23 18:56:43 +0200403 /* FIXME: this is not neccessarily the right thing to do, we should
404 * only set trans->lchan to NULL and wait for another lchan to be
405 * established to the same MM entity (phone/subscriber) */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800406 llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
407 if (trans->lchan == lchan)
Harald Weltedcaf5652009-07-23 18:56:43 +0200408 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800409 }
410
Holger Freyther7c19f742009-06-06 13:54:35 +0000411 return 0;
412}
413
Harald Welte52b1f982008-12-23 20:25:15 +0000414static void to_bcd(u_int8_t *bcd, u_int16_t val)
415{
Harald Welte4b634542008-12-27 01:55:51 +0000416 bcd[2] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000417 val = val / 10;
418 bcd[1] = val % 10;
419 val = val / 10;
Harald Welte4b634542008-12-27 01:55:51 +0000420 bcd[0] = val % 10;
Harald Welte52b1f982008-12-23 20:25:15 +0000421 val = val / 10;
422}
423
Holger Freyther17746612008-12-28 16:32:44 +0000424void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
Harald Welte52b1f982008-12-23 20:25:15 +0000425 u_int16_t mnc, u_int16_t lac)
426{
427 u_int8_t bcd[3];
428
429 to_bcd(bcd, mcc);
430 lai48->digits[0] = bcd[0] | (bcd[1] << 4);
431 lai48->digits[1] = bcd[2];
432
433 to_bcd(bcd, mnc);
Harald Welte4b634542008-12-27 01:55:51 +0000434 /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
435#if 0
Harald Welte8470bf22008-12-25 23:28:35 +0000436 lai48->digits[1] |= bcd[2] << 4;
437 lai48->digits[2] = bcd[0] | (bcd[1] << 4);
Harald Welte4b634542008-12-27 01:55:51 +0000438#else
439 lai48->digits[1] |= 0xf << 4;
440 lai48->digits[2] = bcd[1] | (bcd[2] << 4);
441#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000442
Harald Welte4b634542008-12-27 01:55:51 +0000443 lai48->lac = htons(lac);
Harald Welte52b1f982008-12-23 20:25:15 +0000444}
445
Harald Welte255539c2008-12-28 02:26:27 +0000446#define TMSI_LEN 5
Harald Welte52b1f982008-12-23 20:25:15 +0000447#define MID_TMSI_LEN (TMSI_LEN + 2)
448
Harald Welte255539c2008-12-28 02:26:27 +0000449int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +0000450{
Harald Welte65e74cc2008-12-29 01:55:35 +0000451 u_int32_t *tptr = (u_int32_t *) &buf[3];
Harald Welte255539c2008-12-28 02:26:27 +0000452
Harald Welte4b634542008-12-27 01:55:51 +0000453 buf[0] = GSM48_IE_MOBILE_ID;
Harald Welte1a412182008-12-27 22:13:43 +0000454 buf[1] = TMSI_LEN;
Harald Welte4b634542008-12-27 01:55:51 +0000455 buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
Harald Welte255539c2008-12-28 02:26:27 +0000456 *tptr = htonl(tmsi);
457
458 return 7;
Harald Welte52b1f982008-12-23 20:25:15 +0000459}
460
Harald Welte09e38af2009-02-16 22:52:23 +0000461static const char bcd_num_digits[] = {
462 '0', '1', '2', '3', '4', '5', '6', '7',
463 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
464};
465
Harald Welte0c389302009-06-10 12:08:54 +0800466/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
467int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
468 int h_len)
Harald Welte09e38af2009-02-16 22:52:23 +0000469{
470 u_int8_t in_len = bcd_lv[0];
471 int i;
472
Harald Welte0c389302009-06-10 12:08:54 +0800473 for (i = 1 + h_len; i <= in_len; i++) {
Harald Welte09e38af2009-02-16 22:52:23 +0000474 /* lower nibble */
475 output_len--;
476 if (output_len <= 1)
477 break;
478 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
479
480 /* higher nibble */
481 output_len--;
482 if (output_len <= 1)
483 break;
484 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
485 }
486 if (output_len >= 1)
487 *output++ = '\0';
488
Harald Welte0c389302009-06-10 12:08:54 +0800489 return 0;
Harald Welte09e38af2009-02-16 22:52:23 +0000490}
491
492/* convert a single ASCII character to call-control BCD */
493static int asc_to_bcd(const char asc)
494{
495 int i;
496
497 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
498 if (bcd_num_digits[i] == asc)
499 return i;
500 }
501 return -EINVAL;
502}
503
Harald Welte0c389302009-06-10 12:08:54 +0800504/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
Harald Welte09e38af2009-02-16 22:52:23 +0000505int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
Harald Welte0c389302009-06-10 12:08:54 +0800506 int h_len, const char *input)
Harald Welte09e38af2009-02-16 22:52:23 +0000507{
508 int in_len = strlen(input);
509 int i;
Harald Welte0c389302009-06-10 12:08:54 +0800510 u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000511
512 /* two digits per byte, plus type byte */
Harald Welte0c389302009-06-10 12:08:54 +0800513 bcd_lv[0] = in_len/2 + h_len;
Harald Welte09e38af2009-02-16 22:52:23 +0000514 if (in_len % 2)
515 bcd_lv[0]++;
516
Harald Welte0c389302009-06-10 12:08:54 +0800517 if (bcd_lv[0] > max_len)
518 return -EIO;
Harald Welte09e38af2009-02-16 22:52:23 +0000519
520 for (i = 0; i < in_len; i++) {
521 int rc = asc_to_bcd(input[i]);
522 if (rc < 0)
523 return rc;
524 if (i % 2 == 0)
525 *bcd_cur = rc;
526 else
527 *bcd_cur++ |= (rc << 4);
528 }
529 /* append padding nibble in case of odd length */
530 if (i % 2)
531 *bcd_cur++ |= 0xf0;
532
533 /* return how many bytes we used */
534 return (bcd_cur - bcd_lv);
535}
536
Harald Welte0c389302009-06-10 12:08:54 +0800537/* decode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800538static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
Harald Welte0c389302009-06-10 12:08:54 +0800539 const u_int8_t *lv)
540{
541 u_int8_t in_len = lv[0];
542 int i, s;
543
544 if (in_len < 1)
545 return -EINVAL;
546
Harald Welte4bfdfe72009-06-10 23:11:52 +0800547 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
Harald Welte0c389302009-06-10 12:08:54 +0800548
549 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800550 bcap->transfer = lv[1] & 0x07;
551 bcap->mode = (lv[1] & 0x08) >> 3;
552 bcap->coding = (lv[1] & 0x10) >> 4;
553 bcap->radio = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800554
555 i = 1;
556 s = 0;
557 while(!(lv[i] & 0x80)) {
558 i++; /* octet 3a etc */
559 if (in_len < i)
560 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800561 bcap->speech_ver[s++] = lv[i] & 0x0f;
562 bcap->speech_ver[s] = -1; /* end of list */
Harald Welte0c389302009-06-10 12:08:54 +0800563 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800564 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800565 if (s == 7) /* maximum speech versions + end of list */
566 return 0;
567 }
568
569 return 0;
570}
571
572/* encode 'bearer capability' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800573static int encode_bearer_cap(struct msgb *msg, int lv_only,
574 const struct gsm_mncc_bearer_cap *bcap)
Harald Welte0c389302009-06-10 12:08:54 +0800575{
576 u_int8_t lv[32 + 1];
577 int i, s;
578
Harald Welte4bfdfe72009-06-10 23:11:52 +0800579 lv[1] = bcap->transfer;
580 lv[1] |= bcap->mode << 3;
581 lv[1] |= bcap->coding << 4;
582 lv[1] |= bcap->radio << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800583
584 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800585 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
Harald Welte0c389302009-06-10 12:08:54 +0800586 i++; /* octet 3a etc */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800587 lv[i] = bcap->speech_ver[s];
Harald Welte0c389302009-06-10 12:08:54 +0800588 if (i == 2) /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800589 lv[i] |= bcap->speech_ctm << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800590 }
591 lv[i] |= 0x80; /* last IE of octet 3 etc */
592
593 lv[0] = i;
594 if (lv_only)
595 msgb_lv_put(msg, lv[0], lv+1);
596 else
597 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
598
599 return 0;
600}
601
602/* decode 'call control cap' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800603static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800604{
605 u_int8_t in_len = lv[0];
606
607 if (in_len < 1)
608 return -EINVAL;
609
610 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800611 ccap->dtmf = lv[1] & 0x01;
612 ccap->pcp = (lv[1] & 0x02) >> 1;
Harald Welte0c389302009-06-10 12:08:54 +0800613
614 return 0;
615}
616
617/* decode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800618static int decode_called(struct gsm_mncc_number *called,
619 const u_int8_t *lv)
Harald Welte0c389302009-06-10 12:08:54 +0800620{
621 u_int8_t in_len = lv[0];
622
623 if (in_len < 1)
624 return -EINVAL;
625
626 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800627 called->plan = lv[1] & 0x0f;
628 called->type = (lv[1] & 0x70) >> 4;
Harald Welte0c389302009-06-10 12:08:54 +0800629
630 /* octet 4..N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800631 decode_bcd_number(called->number, sizeof(called->number), lv, 1);
Harald Welte0c389302009-06-10 12:08:54 +0800632
633 return 0;
634}
635
636/* encode 'called party BCD number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800637static int encode_called(struct msgb *msg,
638 const struct gsm_mncc_number *called)
Harald Welte0c389302009-06-10 12:08:54 +0800639{
640 u_int8_t lv[18];
641 int ret;
642
643 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800644 lv[1] = called->plan;
645 lv[1] |= called->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800646
647 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800648 ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
Harald Welte0c389302009-06-10 12:08:54 +0800649 if (ret < 0)
650 return ret;
651
652 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
653
654 return 0;
655}
656
657/* encode callerid of various IEs */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800658static int encode_callerid(struct msgb *msg, int ie,
659 const struct gsm_mncc_number *callerid)
Harald Welte0c389302009-06-10 12:08:54 +0800660{
661 u_int8_t lv[13];
662 int h_len = 1;
663 int ret;
664
665 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800666 lv[1] = callerid->plan;
667 lv[1] |= callerid->type << 4;
Harald Welte0c389302009-06-10 12:08:54 +0800668
Harald Welte4bfdfe72009-06-10 23:11:52 +0800669 if (callerid->present || callerid->screen) {
Harald Welte0c389302009-06-10 12:08:54 +0800670 /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800671 lv[2] = callerid->screen;
672 lv[2] |= callerid->present << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800673 lv[2] |= 0x80;
674 h_len++;
675 } else
676 lv[1] |= 0x80;
677
678 /* octet 4..N, octet 2 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800679 ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
Harald Welte0c389302009-06-10 12:08:54 +0800680 if (ret < 0)
681 return ret;
682
683 msgb_tlv_put(msg, ie, lv[0], lv+1);
684
685 return 0;
686}
687
688/* decode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800689static int decode_cause(struct gsm_mncc_cause *cause,
Harald Welte0c389302009-06-10 12:08:54 +0800690 const u_int8_t *lv)
691{
692 u_int8_t in_len = lv[0];
693 int i;
694
695 if (in_len < 2)
696 return -EINVAL;
697
Harald Welte4bfdfe72009-06-10 23:11:52 +0800698 cause->diag_len = 0;
Harald Welte0c389302009-06-10 12:08:54 +0800699
700 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800701 cause->location = lv[1] & 0x0f;
702 cause->coding = (lv[1] & 0x60) >> 5;
Harald Welte0c389302009-06-10 12:08:54 +0800703
704 i = 1;
705 if (!(lv[i] & 0x80)) {
706 i++; /* octet 3a */
707 if (in_len < i+1)
708 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800709 cause->rec = 1;
710 cause->rec_val = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800711
712 }
713 i++;
714
715 /* octet 4 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800716 cause->value = lv[i] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800717 i++;
718
719 if (in_len < i) /* no diag */
720 return 0;
721
722 if (in_len - (i-1) > 32) /* maximum 32 octets */
723 return 0;
724
725 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800726 memcpy(cause->diag, lv + i, in_len - (i-1));
727 cause->diag_len = in_len - (i-1);
Harald Welte0c389302009-06-10 12:08:54 +0800728
729 return 0;
730}
731
732/* encode 'cause' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800733static int encode_cause(struct msgb *msg, int lv_only,
734 const struct gsm_mncc_cause *cause)
Harald Welte0c389302009-06-10 12:08:54 +0800735{
736 u_int8_t lv[32+4];
737 int i;
738
Harald Welte4bfdfe72009-06-10 23:11:52 +0800739 if (cause->diag_len > 32)
Harald Welte0c389302009-06-10 12:08:54 +0800740 return -EINVAL;
741
742 /* octet 3 */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800743 lv[1] = cause->location;
744 lv[1] |= cause->coding << 5;
Harald Welte0c389302009-06-10 12:08:54 +0800745
746 i = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800747 if (cause->rec) {
Harald Welte0c389302009-06-10 12:08:54 +0800748 i++; /* octet 3a */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800749 lv[i] = cause->rec_val;
Harald Welte0c389302009-06-10 12:08:54 +0800750 }
751 lv[i] |= 0x80; /* end of octet 3 */
752
753 /* octet 4 */
754 i++;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800755 lv[i] = 0x80 | cause->value;
Harald Welte0c389302009-06-10 12:08:54 +0800756
757 /* octet 5-N */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800758 if (cause->diag_len) {
759 memcpy(lv + i, cause->diag, cause->diag_len);
760 i += cause->diag_len;
Harald Welte0c389302009-06-10 12:08:54 +0800761 }
762
763 lv[0] = i;
764 if (lv_only)
765 msgb_lv_put(msg, lv[0], lv+1);
766 else
767 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
768
769 return 0;
770}
771
772/* encode 'calling number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800773static int encode_calling(struct msgb *msg,
774 const struct gsm_mncc_number *calling)
Harald Welte0c389302009-06-10 12:08:54 +0800775{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800776 return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
Harald Welte0c389302009-06-10 12:08:54 +0800777}
778
779/* encode 'connected number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800780static int encode_connected(struct msgb *msg,
781 const struct gsm_mncc_number *connected)
Harald Welte0c389302009-06-10 12:08:54 +0800782{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800783 return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
Harald Welte0c389302009-06-10 12:08:54 +0800784}
785
786/* encode 'redirecting number' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800787static int encode_redirecting(struct msgb *msg,
788 const struct gsm_mncc_number *redirecting)
Harald Welte0c389302009-06-10 12:08:54 +0800789{
Harald Welte4bfdfe72009-06-10 23:11:52 +0800790 return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
Harald Welte0c389302009-06-10 12:08:54 +0800791}
792
793/* decode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800794static int decode_facility(struct gsm_mncc_facility *facility,
Harald Welte0c389302009-06-10 12:08:54 +0800795 const u_int8_t *lv)
796{
797 u_int8_t in_len = lv[0];
798
799 if (in_len < 1)
800 return -EINVAL;
801
Harald Welte4bfdfe72009-06-10 23:11:52 +0800802 if (in_len > sizeof(facility->info))
Harald Welte0c389302009-06-10 12:08:54 +0800803 return -EINVAL;
804
Harald Welte4bfdfe72009-06-10 23:11:52 +0800805 memcpy(facility->info, lv+1, in_len);
806 facility->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800807
808 return 0;
809}
810
811/* encode 'facility' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800812static int encode_facility(struct msgb *msg, int lv_only,
813 const struct gsm_mncc_facility *facility)
Harald Welte0c389302009-06-10 12:08:54 +0800814{
815 u_int8_t lv[GSM_MAX_FACILITY + 1];
816
Harald Welte4bfdfe72009-06-10 23:11:52 +0800817 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
Harald Welte0c389302009-06-10 12:08:54 +0800818 return -EINVAL;
819
Harald Welte4bfdfe72009-06-10 23:11:52 +0800820 memcpy(lv+1, facility->info, facility->len);
821 lv[0] = facility->len;
Harald Welte0c389302009-06-10 12:08:54 +0800822 if (lv_only)
823 msgb_lv_put(msg, lv[0], lv+1);
824 else
825 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
826
827 return 0;
828}
829
830/* decode 'notify' */
831static int decode_notify(int *notify, const u_int8_t *v)
832{
833 *notify = v[0] & 0x7f;
834
835 return 0;
836}
837
838/* encode 'notify' */
839static int encode_notify(struct msgb *msg, int notify)
840{
841 msgb_v_put(msg, notify | 0x80);
842
843 return 0;
844}
845
846/* encode 'signal' */
847static int encode_signal(struct msgb *msg, int signal)
848{
849 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
850
851 return 0;
852}
853
854/* decode 'keypad' */
855static int decode_keypad(int *keypad, const u_int8_t *lv)
856{
857 u_int8_t in_len = lv[0];
858
859 if (in_len < 1)
860 return -EINVAL;
861
862 *keypad = lv[1] & 0x7f;
863
864 return 0;
865}
866
867/* encode 'keypad' */
868static int encode_keypad(struct msgb *msg, int keypad)
869{
870 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
871
872 return 0;
873}
874
875/* decode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800876static int decode_progress(struct gsm_mncc_progress *progress,
Harald Welte0c389302009-06-10 12:08:54 +0800877 const u_int8_t *lv)
878{
879 u_int8_t in_len = lv[0];
880
881 if (in_len < 2)
882 return -EINVAL;
883
Harald Welte4bfdfe72009-06-10 23:11:52 +0800884 progress->coding = (lv[1] & 0x60) >> 5;
885 progress->location = lv[1] & 0x0f;
886 progress->descr = lv[2] & 0x7f;
Harald Welte0c389302009-06-10 12:08:54 +0800887
888 return 0;
889}
890
891/* encode 'progress' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800892static int encode_progress(struct msgb *msg, int lv_only,
893 const struct gsm_mncc_progress *p)
Harald Welte0c389302009-06-10 12:08:54 +0800894{
895 u_int8_t lv[3];
896
897 lv[0] = 2;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800898 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
899 lv[2] = 0x80 | (p->descr & 0x7f);
Harald Welte0c389302009-06-10 12:08:54 +0800900 if (lv_only)
901 msgb_lv_put(msg, lv[0], lv+1);
902 else
903 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
904
905 return 0;
906}
907
908/* decode 'user-user' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800909static int decode_useruser(struct gsm_mncc_useruser *uu,
Harald Welte0c389302009-06-10 12:08:54 +0800910 const u_int8_t *lv)
911{
912 u_int8_t in_len = lv[0];
Harald Welte4bfdfe72009-06-10 23:11:52 +0800913 char *info = uu->info;
914 int info_len = sizeof(uu->info);
Harald Welte0c389302009-06-10 12:08:54 +0800915 int i;
916
917 if (in_len < 1)
918 return -EINVAL;
919
Harald Welte4bfdfe72009-06-10 23:11:52 +0800920 uu->proto = lv[1];
Harald Welte0c389302009-06-10 12:08:54 +0800921
922 for (i = 2; i <= in_len; i++) {
923 info_len--;
924 if (info_len <= 1)
925 break;
926 *info++ = lv[i];
927 }
928 if (info_len >= 1)
929 *info++ = '\0';
930
931 return 0;
932}
933
934/* encode 'useruser' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800935static int encode_useruser(struct msgb *msg, int lv_only,
936 const struct gsm_mncc_useruser *uu)
Harald Welte0c389302009-06-10 12:08:54 +0800937{
938 u_int8_t lv[GSM_MAX_USERUSER + 2];
939
Harald Welte4bfdfe72009-06-10 23:11:52 +0800940 if (strlen(uu->info) > GSM_MAX_USERUSER)
Harald Welte0c389302009-06-10 12:08:54 +0800941 return -EINVAL;
942
Harald Welte4bfdfe72009-06-10 23:11:52 +0800943 lv[0] = 1 + strlen(uu->info);
944 lv[1] = uu->proto;
945 memcpy(lv + 2, uu->info, strlen(uu->info));
Harald Welte0c389302009-06-10 12:08:54 +0800946 if (lv_only)
947 msgb_lv_put(msg, lv[0], lv+1);
948 else
949 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
950
951 return 0;
952}
953
954/* decode 'ss version' */
Harald Welte4bfdfe72009-06-10 23:11:52 +0800955static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
Harald Welte0c389302009-06-10 12:08:54 +0800956 const u_int8_t *lv)
957{
958 u_int8_t in_len = lv[0];
959
Harald Welte4bfdfe72009-06-10 23:11:52 +0800960 if (in_len < 1 || in_len < sizeof(ssv->info))
Harald Welte0c389302009-06-10 12:08:54 +0800961 return -EINVAL;
962
Harald Welte4bfdfe72009-06-10 23:11:52 +0800963 memcpy(ssv->info, lv + 1, in_len);
964 ssv->len = in_len;
Harald Welte0c389302009-06-10 12:08:54 +0800965
966 return 0;
967}
968
969/* encode 'more data' */
970static int encode_more(struct msgb *msg)
971{
972 u_int8_t *ie;
973
974 ie = msgb_put(msg, 1);
975 ie[0] = GSM48_IE_MORE_DATA;
976
977 return 0;
978}
979
Holger Freyther819dd202009-01-04 03:52:50 +0000980struct msgb *gsm48_msgb_alloc(void)
Harald Welte8470bf22008-12-25 23:28:35 +0000981{
Harald Welte966636f2009-06-26 19:39:35 +0200982 return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
983 "GSM 04.08");
Harald Welte8470bf22008-12-25 23:28:35 +0000984}
985
Harald Welte39e2ead2009-07-23 21:13:03 +0200986int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
Harald Welte52b1f982008-12-23 20:25:15 +0000987{
Harald Welte39e2ead2009-07-23 21:13:03 +0200988 struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
989
990 /* if we get passed a transaction reference, do some common
991 * work that the caller no longer has to do */
992 if (trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +0200993 gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
Harald Welte39e2ead2009-07-23 21:13:03 +0200994 msg->lchan = trans->lchan;
995 }
996
Harald Welte65e74cc2008-12-29 01:55:35 +0000997 if (msg->lchan) {
Harald Welte8470bf22008-12-25 23:28:35 +0000998 msg->trx = msg->lchan->ts->trx;
Harald Welte52b1f982008-12-23 20:25:15 +0000999
Harald Welte4bfdfe72009-06-10 23:11:52 +08001000 if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
1001 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
1002 "Sending '%s' to MS.\n", msg->trx->bts->nr,
1003 msg->trx->nr, msg->lchan->ts->nr,
1004 gh->proto_discr & 0xf0,
1005 cc_msg_names[gh->msg_type & 0x3f]);
1006 else
1007 DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
1008 "Sending 0x%02x to MS.\n", msg->trx->bts->nr,
1009 msg->trx->nr, msg->lchan->ts->nr,
1010 gh->proto_discr, gh->msg_type);
Harald Welte65e74cc2008-12-29 01:55:35 +00001011 }
1012
Harald Welte4b634542008-12-27 01:55:51 +00001013 msg->l3h = msg->data;
1014
Harald Welte8470bf22008-12-25 23:28:35 +00001015 return rsl_data_request(msg, 0);
Harald Welte52b1f982008-12-23 20:25:15 +00001016}
1017
Holger Freyther429e7762008-12-30 13:28:30 +00001018/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
Harald Welte8470bf22008-12-25 23:28:35 +00001019int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
Harald Welte52b1f982008-12-23 20:25:15 +00001020{
Harald Welte8470bf22008-12-25 23:28:35 +00001021 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001022 struct gsm48_hdr *gh;
1023
Harald Welte8470bf22008-12-25 23:28:35 +00001024 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001025
1026 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1027 gh->proto_discr = GSM48_PDISC_MM;
Harald Welte10b487b2008-12-27 19:53:37 +00001028 gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
Harald Welte52b1f982008-12-23 20:25:15 +00001029 gh->data[0] = cause;
1030
Harald Weltedb253af2008-12-30 17:56:55 +00001031 DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
1032
Harald Welte39e2ead2009-07-23 21:13:03 +02001033 return gsm48_sendmsg(msg, NULL);
Harald Welte52b1f982008-12-23 20:25:15 +00001034}
1035
1036/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
Harald Welte75a983f2008-12-27 21:34:06 +00001037int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
Harald Welte52b1f982008-12-23 20:25:15 +00001038{
Harald Welte8470bf22008-12-25 23:28:35 +00001039 struct gsm_bts *bts = lchan->ts->trx->bts;
1040 struct msgb *msg = gsm48_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001041 struct gsm48_hdr *gh;
1042 struct gsm48_loc_area_id *lai;
1043 u_int8_t *mid;
Holger Freyther07cc8d82008-12-29 06:23:46 +00001044 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001045
Harald Welte8470bf22008-12-25 23:28:35 +00001046 msg->lchan = lchan;
Harald Welte52b1f982008-12-23 20:25:15 +00001047
1048 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1049 gh->proto_discr = GSM48_PDISC_MM;
1050 gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
1051
1052 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
Holger Freyther17746612008-12-28 16:32:44 +00001053 gsm0408_generate_lai(lai, bts->network->country_code,
Harald Welte52b1f982008-12-23 20:25:15 +00001054 bts->network->network_code, bts->location_area_code);
1055
1056 mid = msgb_put(msg, MID_TMSI_LEN);
1057 generate_mid_from_tmsi(mid, tmsi);
1058
1059 DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
1060
Harald Welte39e2ead2009-07-23 21:13:03 +02001061 ret = gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001062
Harald Welteee5ad162009-08-09 19:07:00 +02001063 /* send MM INFO with network name */
Harald Weltedb253af2008-12-30 17:56:55 +00001064 ret = gsm48_tx_mm_info(lchan);
Harald Weltedb253af2008-12-30 17:56:55 +00001065
Holger Freyther07cc8d82008-12-29 06:23:46 +00001066 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001067}
1068
Harald Weltefc977a82008-12-27 10:19:37 +00001069static char bcd2char(u_int8_t bcd)
1070{
1071 if (bcd < 0xa)
1072 return '0' + bcd;
1073 else
1074 return 'A' + (bcd - 0xa);
1075}
1076
Harald Weltebf5e8df2009-02-03 12:59:45 +00001077/* Convert Mobile Identity (10.5.1.4) to string */
Harald Weltefc977a82008-12-27 10:19:37 +00001078static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
1079{
1080 int i;
1081 u_int8_t mi_type;
1082 char *str_cur = string;
Harald Welte4ed0e922009-01-10 03:17:30 +00001083 u_int32_t tmsi;
Harald Weltefc977a82008-12-27 10:19:37 +00001084
1085 mi_type = mi[0] & GSM_MI_TYPE_MASK;
1086
1087 switch (mi_type) {
1088 case GSM_MI_TYPE_NONE:
1089 break;
1090 case GSM_MI_TYPE_TMSI:
Harald Welte4ed0e922009-01-10 03:17:30 +00001091 /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
1092 if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
1093 memcpy(&tmsi, &mi[1], 4);
1094 tmsi = ntohl(tmsi);
1095 return snprintf(string, str_len, "%u", tmsi);
Harald Weltefc977a82008-12-27 10:19:37 +00001096 }
1097 break;
1098 case GSM_MI_TYPE_IMSI:
1099 case GSM_MI_TYPE_IMEI:
1100 case GSM_MI_TYPE_IMEISV:
Harald Weltedb253af2008-12-30 17:56:55 +00001101 *str_cur++ = bcd2char(mi[0] >> 4);
1102
1103 for (i = 1; i < mi_len; i++) {
Harald Weltefc977a82008-12-27 10:19:37 +00001104 if (str_cur + 2 >= string + str_len)
1105 return str_cur - string;
1106 *str_cur++ = bcd2char(mi[i] & 0xf);
Harald Weltedb253af2008-12-30 17:56:55 +00001107 /* skip last nibble in last input byte when GSM_EVEN */
1108 if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
1109 *str_cur++ = bcd2char(mi[i] >> 4);
Harald Weltefc977a82008-12-27 10:19:37 +00001110 }
1111 break;
1112 default:
1113 break;
1114 }
Harald Weltefc977a82008-12-27 10:19:37 +00001115 *str_cur++ = '\0';
Harald Weltedb253af2008-12-30 17:56:55 +00001116
Harald Weltefc977a82008-12-27 10:19:37 +00001117 return str_cur - string;
1118}
1119
Harald Weltebf5e8df2009-02-03 12:59:45 +00001120/* Transmit Chapter 9.2.10 Identity Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001121static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
1122{
1123 struct msgb *msg = gsm48_msgb_alloc();
1124 struct gsm48_hdr *gh;
Harald Weltefc977a82008-12-27 10:19:37 +00001125
Harald Welte231ad4f2008-12-27 11:15:38 +00001126 msg->lchan = lchan;
1127
1128 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1129 gh->proto_discr = GSM48_PDISC_MM;
1130 gh->msg_type = GSM48_MT_MM_ID_REQ;
1131 gh->data[0] = id_type;
1132
Harald Welte39e2ead2009-07-23 21:13:03 +02001133 return gsm48_sendmsg(msg, NULL);
Harald Welte231ad4f2008-12-27 11:15:38 +00001134}
1135
1136#define MI_SIZE 32
1137
Harald Weltebf5e8df2009-02-03 12:59:45 +00001138/* Parse Chapter 9.2.11 Identity Response */
Harald Welte231ad4f2008-12-27 11:15:38 +00001139static int mm_rx_id_resp(struct msgb *msg)
1140{
1141 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte75a983f2008-12-27 21:34:06 +00001142 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001143 struct gsm_bts *bts = lchan->ts->trx->bts;
1144 struct gsm_network *net = bts->network;
Harald Welte231ad4f2008-12-27 11:15:38 +00001145 u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
1146 char mi_string[MI_SIZE];
1147
1148 mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
Harald Welte61253062008-12-27 11:25:50 +00001149 DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
Harald Welte231ad4f2008-12-27 11:15:38 +00001150 mi_type, mi_string);
1151
Harald Welte75a983f2008-12-27 21:34:06 +00001152 switch (mi_type) {
1153 case GSM_MI_TYPE_IMSI:
1154 if (!lchan->subscr)
Harald Welte9176bd42009-07-23 18:46:00 +02001155 lchan->subscr = db_create_subscriber(net, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001156 if (lchan->loc_operation)
1157 lchan->loc_operation->waiting_for_imsi = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001158 break;
1159 case GSM_MI_TYPE_IMEI:
Harald Welte255539c2008-12-28 02:26:27 +00001160 case GSM_MI_TYPE_IMEISV:
Harald Welte75a983f2008-12-27 21:34:06 +00001161 /* update subscribe <-> IMEI mapping */
1162 if (lchan->subscr)
1163 db_subscriber_assoc_imei(lchan->subscr, mi_string);
Holger Freyther73487a22008-12-31 18:53:57 +00001164 if (lchan->loc_operation)
1165 lchan->loc_operation->waiting_for_imei = 0;
Harald Welte75a983f2008-12-27 21:34:06 +00001166 break;
1167 }
Holger Freyther73487a22008-12-31 18:53:57 +00001168
1169 /* Check if we can let the mobile station enter */
Holger Freytherd51524f2009-06-09 08:27:07 +00001170 return gsm0408_authorize(lchan, msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001171}
1172
Harald Welte255539c2008-12-28 02:26:27 +00001173
1174static void loc_upd_rej_cb(void *data)
1175{
1176 struct gsm_lchan *lchan = data;
1177
Holger Freyther73487a22008-12-31 18:53:57 +00001178 release_loc_updating_req(lchan);
Holger Freythere97f7fb2008-12-31 18:52:11 +00001179 gsm0408_loc_upd_rej(lchan, reject_cause);
Holger Freyther67b4b9a2009-01-01 03:46:11 +00001180 lchan_auto_release(lchan);
Harald Welte255539c2008-12-28 02:26:27 +00001181}
1182
Holger Freytherb7193e42008-12-29 17:44:08 +00001183static void schedule_reject(struct gsm_lchan *lchan)
1184{
Holger Freyther73487a22008-12-31 18:53:57 +00001185 lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
1186 lchan->loc_operation->updating_timer.data = lchan;
Harald Welteff117a82009-05-23 05:22:08 +00001187 bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
Holger Freytherb7193e42008-12-29 17:44:08 +00001188}
1189
Harald Welte2a139372009-02-22 21:14:55 +00001190static const char *lupd_name(u_int8_t type)
1191{
1192 switch (type) {
1193 case GSM48_LUPD_NORMAL:
1194 return "NORMAL";
1195 case GSM48_LUPD_PERIODIC:
1196 return "PEROIDOC";
1197 case GSM48_LUPD_IMSI_ATT:
1198 return "IMSI ATTACH";
1199 default:
1200 return "UNKNOWN";
1201 }
1202}
1203
Harald Welte231ad4f2008-12-27 11:15:38 +00001204#define MI_SIZE 32
Harald Weltebf5e8df2009-02-03 12:59:45 +00001205/* Chapter 9.2.15: Receive Location Updating Request */
Harald Welte231ad4f2008-12-27 11:15:38 +00001206static int mm_rx_loc_upd_req(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001207{
Harald Welte8470bf22008-12-25 23:28:35 +00001208 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001209 struct gsm48_loc_upd_req *lu;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001210 struct gsm_subscriber *subscr = NULL;
Harald Welte255539c2008-12-28 02:26:27 +00001211 struct gsm_lchan *lchan = msg->lchan;
Harald Welte9176bd42009-07-23 18:46:00 +02001212 struct gsm_bts *bts = lchan->ts->trx->bts;
Harald Welte8470bf22008-12-25 23:28:35 +00001213 u_int8_t mi_type;
Harald Welte231ad4f2008-12-27 11:15:38 +00001214 char mi_string[MI_SIZE];
1215 int rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001216
Harald Welte8470bf22008-12-25 23:28:35 +00001217 lu = (struct gsm48_loc_upd_req *) gh->data;
1218
1219 mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
Harald Welte52b1f982008-12-23 20:25:15 +00001220
Harald Weltefc977a82008-12-27 10:19:37 +00001221 mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
1222
Harald Weltea0368542009-06-27 02:58:43 +02001223 DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
Harald Welte2a139372009-02-22 21:14:55 +00001224 lupd_name(lu->type));
Holger Freyther73487a22008-12-31 18:53:57 +00001225
Holger Freythereaf04692009-06-06 13:54:44 +00001226 /*
1227 * Pseudo Spoof detection: Just drop a second/concurrent
1228 * location updating request.
1229 */
1230 if (lchan->loc_operation) {
Harald Weltea0368542009-06-27 02:58:43 +02001231 DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
Holger Freythereaf04692009-06-06 13:54:44 +00001232 lchan->loc_operation);
1233 gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
1234 return 0;
1235 }
1236
Holger Freyther73487a22008-12-31 18:53:57 +00001237 allocate_loc_updating_req(lchan);
1238
Harald Welte52b1f982008-12-23 20:25:15 +00001239 switch (mi_type) {
1240 case GSM_MI_TYPE_IMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001241 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001242 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001243 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001244 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001245
Harald Welte52b1f982008-12-23 20:25:15 +00001246 /* look up subscriber based on IMSI */
Harald Welte9176bd42009-07-23 18:46:00 +02001247 subscr = db_create_subscriber(bts->network, mi_string);
Harald Welte4b634542008-12-27 01:55:51 +00001248 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001249 case GSM_MI_TYPE_TMSI:
Harald Weltea0368542009-06-27 02:58:43 +02001250 DEBUGPC(DMM, "\n");
Harald Welte231ad4f2008-12-27 11:15:38 +00001251 /* we always want the IMEI, too */
Harald Welte015b9ad2009-02-28 18:22:03 +00001252 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
Holger Freyther73487a22008-12-31 18:53:57 +00001253 lchan->loc_operation->waiting_for_imei = 1;
Holger Freytherc6ea9db2008-12-30 19:18:21 +00001254
Harald Welte52b1f982008-12-23 20:25:15 +00001255 /* look up the subscriber based on TMSI, request IMSI if it fails */
Harald Welte9176bd42009-07-23 18:46:00 +02001256 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte52b1f982008-12-23 20:25:15 +00001257 if (!subscr) {
Harald Welte231ad4f2008-12-27 11:15:38 +00001258 /* send IDENTITY REQUEST message to get IMSI */
Harald Welte255539c2008-12-28 02:26:27 +00001259 rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
Holger Freyther73487a22008-12-31 18:53:57 +00001260 lchan->loc_operation->waiting_for_imsi = 1;
Harald Welte52b1f982008-12-23 20:25:15 +00001261 }
1262 break;
1263 case GSM_MI_TYPE_IMEI:
1264 case GSM_MI_TYPE_IMEISV:
1265 /* no sim card... FIXME: what to do ? */
Harald Weltea0368542009-06-27 02:58:43 +02001266 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001267 break;
1268 default:
Harald Weltea0368542009-06-27 02:58:43 +02001269 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001270 break;
1271 }
1272
Harald Welte24516ea2009-07-04 10:18:00 +02001273 /* schedule the reject timer */
1274 schedule_reject(lchan);
1275
Harald Welte4bfdfe72009-06-10 23:11:52 +08001276 if (!subscr) {
Harald Weltea0368542009-06-27 02:58:43 +02001277 DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001278 /* FIXME: request id? close channel? */
1279 return -EINVAL;
1280 }
1281
Harald Welte255539c2008-12-28 02:26:27 +00001282 lchan->subscr = subscr;
1283
Harald Welte24516ea2009-07-04 10:18:00 +02001284 /* check if we can let the subscriber into our network immediately
1285 * or if we need to wait for identity responses. */
Holger Freytherd51524f2009-06-09 08:27:07 +00001286 return gsm0408_authorize(lchan, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001287}
1288
Harald Welte13cac662009-07-29 12:10:35 +02001289/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
Harald Welte7584aea2009-02-11 11:44:12 +00001290int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
1291{
1292 struct msgb *msg = gsm48_msgb_alloc();
1293 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1294 struct gsm48_chan_mode_modify *cmm =
1295 (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
Harald Welte4a543e82009-02-28 13:17:55 +00001296 u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
Harald Welte7584aea2009-02-11 11:44:12 +00001297
Harald Welte4a543e82009-02-28 13:17:55 +00001298 DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
Harald Welte7ccf7782009-02-17 01:43:01 +00001299
Harald Welte45b407a2009-05-23 15:51:12 +00001300 lchan->tch_mode = mode;
Harald Welte7584aea2009-02-11 11:44:12 +00001301 msg->lchan = lchan;
1302 gh->proto_discr = GSM48_PDISC_RR;
1303 gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
1304
1305 /* fill the channel information element, this code
1306 * should probably be shared with rsl_rx_chan_rqd() */
1307 cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
Harald Welte02b0e092009-02-28 13:11:07 +00001308 cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
Harald Welte7584aea2009-02-11 11:44:12 +00001309 cmm->chan_desc.h0.h = 0;
1310 cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
1311 cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
1312 cmm->mode = mode;
1313
Harald Welte39e2ead2009-07-23 21:13:03 +02001314 return gsm48_sendmsg(msg, NULL);
Harald Welte7584aea2009-02-11 11:44:12 +00001315}
1316
Harald Welte4bfdfe72009-06-10 23:11:52 +08001317#if 0
1318static u_int8_t to_bcd8(u_int8_t val)
1319{
1320 return ((val / 10) << 4) | (val % 10);
1321}
1322#endif
1323
Harald Weltedb253af2008-12-30 17:56:55 +00001324/* Section 9.2.15a */
1325int gsm48_tx_mm_info(struct gsm_lchan *lchan)
1326{
1327 struct msgb *msg = gsm48_msgb_alloc();
1328 struct gsm48_hdr *gh;
1329 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Weltedb253af2008-12-30 17:56:55 +00001330 u_int8_t *ptr8;
1331 u_int16_t *ptr16;
1332 int name_len;
Harald Weltedb253af2008-12-30 17:56:55 +00001333 int i;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001334#if 0
1335 time_t cur_t;
1336 struct tm* cur_time;
1337 int tz15min;
1338#endif
Harald Weltedb253af2008-12-30 17:56:55 +00001339
1340 msg->lchan = lchan;
1341
1342 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1343 gh->proto_discr = GSM48_PDISC_MM;
1344 gh->msg_type = GSM48_MT_MM_INFO;
1345
1346 if (net->name_long) {
1347 name_len = strlen(net->name_long);
1348 /* 10.5.3.5a */
1349 ptr8 = msgb_put(msg, 3);
1350 ptr8[0] = GSM48_IE_NAME_LONG;
1351 ptr8[1] = name_len*2 +1;
1352 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1353
1354 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
1355 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001356 ptr16[i] = htons(net->name_long[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001357
1358 /* FIXME: Use Cell Broadcast, not UCS-2, since
1359 * UCS-2 is only supported by later revisions of the spec */
1360 }
1361
1362 if (net->name_short) {
1363 name_len = strlen(net->name_short);
1364 /* 10.5.3.5a */
1365 ptr8 = (u_int8_t *) msgb_put(msg, 3);
Harald Welte7543eb72009-07-19 17:51:36 +02001366 ptr8[0] = GSM48_IE_NAME_SHORT;
Harald Weltedb253af2008-12-30 17:56:55 +00001367 ptr8[1] = name_len*2 + 1;
1368 ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
1369
Harald Weltee872cb12009-01-01 00:33:37 +00001370 ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
Harald Weltedb253af2008-12-30 17:56:55 +00001371 for (i = 0; i < name_len; i++)
Harald Welte179f0642008-12-31 23:59:18 +00001372 ptr16[i] = htons(net->name_short[i]);
Harald Weltedb253af2008-12-30 17:56:55 +00001373 }
1374
1375#if 0
1376 /* Section 10.5.3.9 */
1377 cur_t = time(NULL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001378 cur_time = gmtime(&cur_t);
Harald Weltedb253af2008-12-30 17:56:55 +00001379 ptr8 = msgb_put(msg, 8);
1380 ptr8[0] = GSM48_IE_NET_TIME_TZ;
1381 ptr8[1] = to_bcd8(cur_time->tm_year % 100);
1382 ptr8[2] = to_bcd8(cur_time->tm_mon);
1383 ptr8[3] = to_bcd8(cur_time->tm_mday);
1384 ptr8[4] = to_bcd8(cur_time->tm_hour);
1385 ptr8[5] = to_bcd8(cur_time->tm_min);
1386 ptr8[6] = to_bcd8(cur_time->tm_sec);
1387 /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
1388 tz15min = (cur_time->tm_gmtoff)/(60*15);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001389 ptr8[7] = to_bcd8(tz15min);
Harald Weltedb253af2008-12-30 17:56:55 +00001390 if (tz15min < 0)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001391 ptr8[7] |= 0x80;
Harald Weltedb253af2008-12-30 17:56:55 +00001392#endif
1393
Harald Welte39e2ead2009-07-23 21:13:03 +02001394 return gsm48_sendmsg(msg, NULL);
Harald Weltedb253af2008-12-30 17:56:55 +00001395}
1396
Harald Welte4b634542008-12-27 01:55:51 +00001397static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
1398{
Harald Welte4b634542008-12-27 01:55:51 +00001399 DEBUGP(DMM, "-> CM SERVICE ACK\n");
Harald Welte65e74cc2008-12-29 01:55:35 +00001400 return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
Harald Welte4b634542008-12-27 01:55:51 +00001401}
Harald Welteba4cf162009-01-10 01:49:35 +00001402
1403/* 9.2.6 CM service reject */
1404static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
1405 enum gsm48_reject_value value)
1406{
1407 struct msgb *msg = gsm48_msgb_alloc();
1408 struct gsm48_hdr *gh;
1409
1410 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
1411
1412 msg->lchan = lchan;
1413 use_lchan(lchan);
1414
1415 gh->proto_discr = GSM48_PDISC_MM;
1416 gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
1417 gh->data[0] = value;
1418 DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
1419
Harald Welte39e2ead2009-07-23 21:13:03 +02001420 return gsm48_sendmsg(msg, NULL);
Harald Welteba4cf162009-01-10 01:49:35 +00001421}
1422
Harald Welte3ac7f102009-08-10 10:12:45 +02001423static int send_siemens_mrpci(struct gsm_lchan *lchan,
1424 u_int8_t *classmark2_lv)
1425{
1426 struct rsl_mrpci mrpci;
1427
1428 if (classmark2_lv[0] < 2)
1429 return -EINVAL;
1430
1431 mrpci.power_class = classmark2_lv[1] & 0x7;
1432 mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
1433 mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
1434 mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
1435
1436 return rsl_siemens_mrpci(lchan, &mrpci);
1437}
Harald Welte4ed0e922009-01-10 03:17:30 +00001438
1439/*
1440 * Handle CM Service Requests
1441 * a) Verify that the packet is long enough to contain the information
1442 * we require otherwsie reject with INCORRECT_MESSAGE
1443 * b) Try to parse the TMSI. If we do not have one reject
1444 * c) Check that we know the subscriber with the TMSI otherwise reject
1445 * with a HLR cause
1446 * d) Set the subscriber on the gsm_lchan and accept
1447 */
Harald Welte4b634542008-12-27 01:55:51 +00001448static int gsm48_rx_mm_serv_req(struct msgb *msg)
1449{
Harald Welteba4cf162009-01-10 01:49:35 +00001450 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001451 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001452
Harald Welte9176bd42009-07-23 18:46:00 +02001453 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welteba4cf162009-01-10 01:49:35 +00001454 struct gsm_subscriber *subscr;
1455 struct gsm48_hdr *gh = msgb_l3(msg);
1456 struct gsm48_service_request *req =
1457 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001458 /* unfortunately in Phase1 the classmar2 length is variable */
1459 u_int8_t classmark2_len = gh->data[1];
1460 u_int8_t *classmark2 = gh->data+2;
1461 u_int8_t mi_len = *(classmark2 + classmark2_len);
1462 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001463
Harald Weltec9e02182009-05-01 19:07:53 +00001464 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001465 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001466 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001467 return gsm48_tx_mm_serv_rej(msg->lchan,
1468 GSM48_REJECT_INCORRECT_MESSAGE);
1469 }
1470
1471 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001472 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001473 return gsm48_tx_mm_serv_rej(msg->lchan,
1474 GSM48_REJECT_INCORRECT_MESSAGE);
1475 }
1476
Harald Weltec9e02182009-05-01 19:07:53 +00001477 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001478 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001479 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001480 return gsm48_tx_mm_serv_rej(msg->lchan,
1481 GSM48_REJECT_INCORRECT_MESSAGE);
1482 }
1483
Harald Weltec9e02182009-05-01 19:07:53 +00001484 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001485 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001486 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001487
Harald Welte3ac7f102009-08-10 10:12:45 +02001488 if (is_siemens_bts(bts))
1489 send_siemens_mrpci(msg->lchan, classmark2-1);
1490
Harald Welte9176bd42009-07-23 18:46:00 +02001491 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Holger Freythereb443982009-06-04 13:58:42 +00001492
Harald Welte2a139372009-02-22 21:14:55 +00001493 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001494 if (!subscr)
1495 return gsm48_tx_mm_serv_rej(msg->lchan,
1496 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1497
1498 if (!msg->lchan->subscr)
1499 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001500 else if (msg->lchan->subscr != subscr) {
1501 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1502 subscr_put(subscr);
1503 }
1504
Harald Weltec2e302d2009-07-05 14:08:13 +02001505 subscr->equipment.classmark2_len = classmark2_len;
1506 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1507 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001508
Harald Welte4b634542008-12-27 01:55:51 +00001509 return gsm48_tx_mm_serv_ack(msg->lchan);
1510}
1511
Harald Welte2a139372009-02-22 21:14:55 +00001512static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1513{
Harald Welte9176bd42009-07-23 18:46:00 +02001514 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2a139372009-02-22 21:14:55 +00001515 struct gsm48_hdr *gh = msgb_l3(msg);
1516 struct gsm48_imsi_detach_ind *idi =
1517 (struct gsm48_imsi_detach_ind *) gh->data;
1518 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1519 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001520 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001521
1522 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1523 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1524 mi_type, mi_string);
1525
1526 switch (mi_type) {
1527 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001528 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001529 break;
1530 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001531 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001532 break;
1533 case GSM_MI_TYPE_IMEI:
1534 case GSM_MI_TYPE_IMEISV:
1535 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001536 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001537 break;
1538 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001539 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001540 break;
1541 }
1542
Holger Freyther4a49e772009-04-12 05:37:29 +00001543 if (subscr) {
1544 subscr_update(subscr, msg->trx->bts,
1545 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001546 DEBUGP(DMM, "Subscriber: %s\n",
1547 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001548 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001549 } else
Harald Welte2a139372009-02-22 21:14:55 +00001550 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1551
Harald Welte2a139372009-02-22 21:14:55 +00001552 return 0;
1553}
1554
Harald Welted2a7f5a2009-06-05 20:08:20 +00001555static int gsm48_rx_mm_status(struct msgb *msg)
1556{
1557 struct gsm48_hdr *gh = msgb_l3(msg);
1558
1559 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1560
1561 return 0;
1562}
1563
Harald Weltebf5e8df2009-02-03 12:59:45 +00001564/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001565static int gsm0408_rcv_mm(struct msgb *msg)
1566{
1567 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001568 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001569
1570 switch (gh->msg_type & 0xbf) {
1571 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001572 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001573 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001574 break;
1575 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001576 rc = mm_rx_id_resp(msg);
1577 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001578 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001579 rc = gsm48_rx_mm_serv_req(msg);
1580 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001581 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001582 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001583 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001584 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001585 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1586 msg->lchan->subscr ?
1587 msg->lchan->subscr->imsi :
1588 "unknown subscriber");
1589 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001590 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001591 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1592 break;
1593 case GSM48_MT_MM_CM_REEST_REQ:
1594 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1595 break;
1596 case GSM48_MT_MM_AUTH_RESP:
1597 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001598 break;
1599 default:
1600 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1601 gh->msg_type);
1602 break;
1603 }
1604
1605 return rc;
1606}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001607
Harald Welte2d35ae62009-02-06 12:02:13 +00001608/* Receive a PAGING RESPONSE message from the MS */
1609static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1610{
Harald Welte9176bd42009-07-23 18:46:00 +02001611 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2d35ae62009-02-06 12:02:13 +00001612 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001613 u_int8_t *classmark2_lv = gh->data + 1;
1614 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1615 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001616 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001617 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001618 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001619 int rc = 0;
1620
Harald Welte61548982009-02-22 21:26:29 +00001621 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001622 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1623 mi_type, mi_string);
Harald Welte3ac7f102009-08-10 10:12:45 +02001624
1625 if (is_siemens_bts(bts))
1626 send_siemens_mrpci(msg->lchan, classmark2_lv);
1627
Harald Weltefe18d8f2009-02-22 21:14:24 +00001628 switch (mi_type) {
1629 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001630 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001631 break;
1632 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001633 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001634 break;
1635 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001636
1637 if (!subscr) {
1638 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001639 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001640 return -EINVAL;
1641 }
1642 DEBUGP(DRR, "<- Channel was requested by %s\n",
Harald Welte76042182009-08-08 16:03:15 +02001643 subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001644
Harald Weltec2e302d2009-07-05 14:08:13 +02001645 subscr->equipment.classmark2_len = *classmark2_lv;
1646 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1647 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001648
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001649 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001650 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001651 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001652 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1653 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001654 return -EINVAL;
1655 } else {
1656 DEBUGP(DRR, "<- Channel already owned by us\n");
1657 subscr_put(subscr);
1658 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001659 }
1660
Harald Welte595ad7b2009-02-16 22:05:44 +00001661 sig_data.subscr = subscr;
1662 sig_data.bts = msg->lchan->ts->trx->bts;
1663 sig_data.lchan = msg->lchan;
1664
1665 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001666
1667 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001668 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001669
Harald Welte7584aea2009-02-11 11:44:12 +00001670 /* FIXME: somehow signal the completion of the PAGING to
1671 * the entity that requested the paging */
1672
Harald Welte2d35ae62009-02-06 12:02:13 +00001673 return rc;
1674}
1675
Harald Weltef7c43522009-06-09 20:24:21 +00001676static int gsm48_rx_rr_classmark(struct msgb *msg)
1677{
1678 struct gsm48_hdr *gh = msgb_l3(msg);
1679 struct gsm_subscriber *subscr = msg->lchan->subscr;
1680 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1681 u_int8_t cm2_len, cm3_len = 0;
1682 u_int8_t *cm2, *cm3 = NULL;
1683
1684 DEBUGP(DRR, "CLASSMARK CHANGE ");
1685
1686 /* classmark 2 */
1687 cm2_len = gh->data[0];
1688 cm2 = &gh->data[1];
1689 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1690
1691 if (payload_len > cm2_len + 1) {
1692 /* we must have a classmark3 */
1693 if (gh->data[cm2_len+1] != 0x20) {
1694 DEBUGPC(DRR, "ERR CM3 TAG\n");
1695 return -EINVAL;
1696 }
1697 if (cm2_len > 3) {
1698 DEBUGPC(DRR, "CM2 too long!\n");
1699 return -EINVAL;
1700 }
1701
1702 cm3_len = gh->data[cm2_len+2];
1703 cm3 = &gh->data[cm2_len+3];
1704 if (cm3_len > 14) {
1705 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1706 return -EINVAL;
1707 }
1708 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1709 }
1710 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001711 subscr->equipment.classmark2_len = cm2_len;
1712 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001713 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001714 subscr->equipment.classmark3_len = cm3_len;
1715 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001716 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001717 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001718 }
1719
Harald Weltef7c43522009-06-09 20:24:21 +00001720 return 0;
1721}
1722
Harald Weltecf5b3592009-05-01 18:28:42 +00001723static int gsm48_rx_rr_status(struct msgb *msg)
1724{
1725 struct gsm48_hdr *gh = msgb_l3(msg);
1726
1727 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1728 rr_cause_name(gh->data[0]));
1729
1730 return 0;
1731}
1732
Harald Weltef7c43522009-06-09 20:24:21 +00001733static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1734{
1735 struct gsm48_hdr *gh = msgb_l3(msg);
1736 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1737 static struct gsm_meas_rep meas_rep;
1738
Harald Welte10d0e672009-06-27 02:53:10 +02001739 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001740 parse_meas_rep(&meas_rep, gh->data, payload_len);
1741 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001742 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001743 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001744 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001745 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001746 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001747 else
Harald Welte10d0e672009-06-27 02:53:10 +02001748 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001749 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1750 meas_rep.rxqual_sub);
1751
Harald Welte10d0e672009-06-27 02:53:10 +02001752 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001753
1754 /* FIXME: put the results somwhere */
1755
1756 return 0;
1757}
1758
Harald Weltebf5e8df2009-02-03 12:59:45 +00001759/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001760static int gsm0408_rcv_rr(struct msgb *msg)
1761{
1762 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001763 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001764
1765 switch (gh->msg_type) {
1766 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001767 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001768 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001769 case GSM48_MT_RR_GPRS_SUSP_REQ:
1770 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1771 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001772 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001773 rc = gsm48_rr_rx_pag_resp(msg);
1774 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001775 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1776 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte13cac662009-07-29 12:10:35 +02001777 /* We've successfully modified the MS side of the channel,
1778 * now go on to modify the BTS side of the channel */
Harald Welte9943c5b2009-07-29 15:41:29 +02001779 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
Harald Welte2c38aa82009-02-18 03:44:24 +00001780 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001781 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001782 case GSM48_MT_RR_STATUS:
1783 rc = gsm48_rx_rr_status(msg);
1784 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001785 case GSM48_MT_RR_MEAS_REP:
1786 rc = gsm48_rx_rr_meas_rep(msg);
1787 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001788 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001789 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001790 gh->msg_type);
1791 break;
1792 }
1793
Harald Welte2d35ae62009-02-06 12:02:13 +00001794 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001795}
1796
Harald Welte115d1032009-08-10 11:43:22 +02001797/* 7.1.7 and 9.1.7: RR CHANnel RELease */
Holger Freythere64a7a32009-02-06 21:55:37 +00001798int gsm48_send_rr_release(struct gsm_lchan *lchan)
1799{
1800 struct msgb *msg = gsm48_msgb_alloc();
1801 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1802 u_int8_t *cause;
1803
1804 msg->lchan = lchan;
1805 gh->proto_discr = GSM48_PDISC_RR;
1806 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1807
1808 cause = msgb_put(msg, 1);
1809 cause[0] = GSM48_RR_CAUSE_NORMAL;
1810
1811 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1812 lchan->nr, lchan->type);
1813
Harald Welteae0f2362009-07-19 18:36:49 +02001814 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001815 gsm48_sendmsg(msg, NULL);
Harald Welte76042182009-08-08 16:03:15 +02001816 /* FIXME: Start Timer T3109 */
Harald Welteae0f2362009-07-19 18:36:49 +02001817
1818 /* Deactivate the SACCH on the BTS side */
1819 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001820}
1821
Harald Welte4bc90a12008-12-27 16:32:52 +00001822/* Call Control */
1823
Harald Welte7584aea2009-02-11 11:44:12 +00001824/* The entire call control code is written in accordance with Figure 7.10c
1825 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1826 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1827 * it for voice */
1828
Harald Welte4bfdfe72009-06-10 23:11:52 +08001829static void new_cc_state(struct gsm_trans *trans, int state)
1830{
1831 if (state > 31 || state < 0)
1832 return;
1833
1834 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001835 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001836
Harald Weltedcaf5652009-07-23 18:56:43 +02001837 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001838}
1839
1840static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001841{
1842 struct msgb *msg = gsm48_msgb_alloc();
1843 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1844 u_int8_t *cause, *call_state;
1845
Harald Welte4bc90a12008-12-27 16:32:52 +00001846 gh->msg_type = GSM48_MT_CC_STATUS;
1847
1848 cause = msgb_put(msg, 3);
1849 cause[0] = 2;
1850 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1851 cause[2] = 0x80 | 30; /* response to status inquiry */
1852
1853 call_state = msgb_put(msg, 1);
1854 call_state[0] = 0xc0 | 0x00;
1855
Harald Welte39e2ead2009-07-23 21:13:03 +02001856 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001857}
1858
Harald Welte6f4b7532008-12-29 00:39:37 +00001859static int gsm48_tx_simple(struct gsm_lchan *lchan,
1860 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001861{
1862 struct msgb *msg = gsm48_msgb_alloc();
1863 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1864
1865 msg->lchan = lchan;
1866
Harald Welte6f4b7532008-12-29 00:39:37 +00001867 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001868 gh->msg_type = msg_type;
1869
Harald Welte39e2ead2009-07-23 21:13:03 +02001870 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001871}
1872
Harald Welte4bfdfe72009-06-10 23:11:52 +08001873static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1874{
Harald Weltedcaf5652009-07-23 18:56:43 +02001875 if (bsc_timer_pending(&trans->cc.timer)) {
1876 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1877 bsc_del_timer(&trans->cc.timer);
1878 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001879 }
1880}
1881
1882static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1883 int msg_type, struct gsm_mncc *mncc)
1884{
1885 struct msgb *msg;
1886
1887 if (trans)
1888 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001889 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001890 "Sending '%s' to MNCC.\n",
1891 trans->lchan->ts->trx->bts->nr,
1892 trans->lchan->ts->trx->nr,
1893 trans->lchan->ts->nr, trans->transaction_id,
1894 (trans->subscr)?(trans->subscr->extension):"-",
1895 get_mncc_name(msg_type));
1896 else
1897 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1898 "Sending '%s' to MNCC.\n",
1899 (trans->subscr)?(trans->subscr->extension):"-",
1900 get_mncc_name(msg_type));
1901 else
1902 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1903 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1904
1905 mncc->msg_type = msg_type;
1906
Harald Welte966636f2009-06-26 19:39:35 +02001907 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001908 if (!msg)
1909 return -ENOMEM;
1910 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1911 msgb_enqueue(&net->upqueue, msg);
1912
1913 return 0;
1914}
1915
1916int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1917 u_int32_t callref, int location, int value)
1918{
1919 struct gsm_mncc rel;
1920
Harald Welte92f70c52009-06-12 01:54:08 +08001921 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001922 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001923 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001924 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1925}
1926
Harald Weltedcaf5652009-07-23 18:56:43 +02001927/* Call Control Specific transaction release.
1928 * gets called by trans_free, DO NOT CALL YOURSELF! */
1929void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001930{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001931 gsm48_stop_cc_timer(trans);
1932
1933 /* send release to L4, if callref still exists */
1934 if (trans->callref) {
1935 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02001936 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001937 GSM48_CAUSE_LOC_PRN_S_LU,
1938 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001939 }
Harald Weltedcaf5652009-07-23 18:56:43 +02001940 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001941 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02001942 if (trans->lchan)
1943 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001944}
1945
1946static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1947
Harald Welte09e38af2009-02-16 22:52:23 +00001948/* call-back from paging the B-end of the connection */
1949static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001950 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001951{
Harald Welte7ccf7782009-02-17 01:43:01 +00001952 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001953 struct gsm_subscriber *subscr = param;
1954 struct gsm_trans *transt, *tmp;
1955 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001956
Harald Welte09e38af2009-02-16 22:52:23 +00001957 if (hooknum != GSM_HOOK_RR_PAGING)
1958 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001959
1960 if (!subscr)
1961 return -EINVAL;
1962 net = subscr->net;
1963 if (!net) {
1964 DEBUGP(DCC, "Error Network not set!\n");
1965 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00001966 }
Harald Welte7584aea2009-02-11 11:44:12 +00001967
Harald Welte4bfdfe72009-06-10 23:11:52 +08001968 /* check all tranactions (without lchan) for subscriber */
1969 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1970 if (transt->subscr != subscr || transt->lchan)
1971 continue;
1972 switch (event) {
1973 case GSM_PAGING_SUCCEEDED:
1974 if (!lchan) // paranoid
1975 break;
1976 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1977 subscr->extension);
1978 /* Assign lchan */
1979 if (!transt->lchan) {
1980 transt->lchan = lchan;
1981 use_lchan(lchan);
1982 }
1983 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02001984 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001985 break;
1986 case GSM_PAGING_EXPIRED:
1987 DEBUGP(DCC, "Paging subscr %s expired!\n",
1988 subscr->extension);
1989 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02001990 mncc_release_ind(transt->subscr->net, transt,
1991 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001992 GSM48_CAUSE_LOC_PRN_S_LU,
1993 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001994 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02001995 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001996 break;
1997 }
1998 }
Harald Welte09e38af2009-02-16 22:52:23 +00001999 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00002000}
Harald Welte7584aea2009-02-11 11:44:12 +00002001
Harald Welte805f6442009-07-28 18:25:29 +02002002/* some other part of the code sends us a signal */
2003static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
2004 void *handler_data, void *signal_data)
2005{
2006 struct gsm_lchan *lchan = signal_data;
2007 struct gsm_bts_trx_ts *ts;
2008 int rc;
2009
2010 if (subsys != SS_ABISIP)
2011 return 0;
2012
2013 /* in case we use direct BTS-to-BTS RTP */
2014 if (ipacc_rtp_direct)
2015 return 0;
2016
2017 ts = lchan->ts;
2018
2019 switch (signal) {
2020 case S_ABISIP_BIND_ACK:
2021 /* the BTS has successfully bound a TCH to a local ip/port,
2022 * which means we can connect our UDP socket to it */
2023 if (ts->abis_ip.rtp_socket) {
2024 rtp_socket_free(ts->abis_ip.rtp_socket);
2025 ts->abis_ip.rtp_socket = NULL;
2026 }
2027
2028 ts->abis_ip.rtp_socket = rtp_socket_create();
2029 if (!ts->abis_ip.rtp_socket)
2030 goto out_err;
2031
2032 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2033 ts->abis_ip.bound_ip,
2034 ts->abis_ip.bound_port);
2035 if (rc < 0)
2036 goto out_err;
2037 break;
2038 case S_ABISIP_DISC_IND:
2039 /* the BTS tells us a RTP stream has been disconnected */
2040 if (ts->abis_ip.rtp_socket) {
2041 rtp_socket_free(ts->abis_ip.rtp_socket);
2042 ts->abis_ip.rtp_socket = NULL;
2043 }
2044 break;
2045 }
2046
2047 return 0;
2048out_err:
2049 /* FIXME: do something */
2050 return 0;
2051}
2052
2053/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2054static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2055{
2056 struct gsm_bts_trx_ts *ts = lchan->ts;
2057 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2058 int rc;
2059
2060 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2061 ntohs(rs->rtp.sin_local.sin_port),
2062 ts->abis_ip.conn_id,
2063 /* FIXME: use RTP payload of bound socket, not BTS*/
2064 ts->abis_ip.rtp_payload2);
2065
2066 return rc;
2067}
2068
Harald Welte49f48b82009-02-17 15:29:33 +00002069/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002070static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002071{
Harald Welte11fa29c2009-02-19 17:24:39 +00002072 struct gsm_bts *bts = lchan->ts->trx->bts;
2073 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002074 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002075 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002076
Harald Welte11fa29c2009-02-19 17:24:39 +00002077 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2078 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2079 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2080
2081 if (bts->type != remote_bts->type) {
2082 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2083 return -EINVAL;
2084 }
Harald Welte49f48b82009-02-17 15:29:33 +00002085
Harald Welte11fa29c2009-02-19 17:24:39 +00002086 switch (bts->type) {
2087 case GSM_BTS_TYPE_NANOBTS_900:
2088 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002089 if (!ipacc_rtp_direct) {
2090 /* connect the TCH's to our RTP proxy */
2091 rc = ipacc_connect_proxy_bind(lchan);
2092 if (rc < 0)
2093 return rc;
2094 rc = ipacc_connect_proxy_bind(remote_lchan);
2095
2096 /* connect them with each other */
2097 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2098 remote_lchan->ts->abis_ip.rtp_socket);
2099 } else {
2100 /* directly connect TCH RTP streams to each other */
2101 ts = remote_lchan->ts;
2102 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2103 ts->abis_ip.bound_port,
2104 lchan->ts->abis_ip.conn_id,
2105 ts->abis_ip.rtp_payload2);
2106 if (rc < 0)
2107 return rc;
2108 ts = lchan->ts;
2109 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2110 ts->abis_ip.bound_port,
2111 remote_lchan->ts->abis_ip.conn_id,
2112 ts->abis_ip.rtp_payload2);
2113 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002114 break;
2115 case GSM_BTS_TYPE_BS11:
2116 trau_mux_map_lchan(lchan, remote_lchan);
2117 break;
2118 default:
2119 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002120 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002121 break;
2122 }
Harald Welte49f48b82009-02-17 15:29:33 +00002123
2124 return 0;
2125}
2126
Harald Welte4bfdfe72009-06-10 23:11:52 +08002127/* bridge channels of two transactions */
2128static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002129{
Harald Weltedcaf5652009-07-23 18:56:43 +02002130 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2131 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002132
Harald Welte4bfdfe72009-06-10 23:11:52 +08002133 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002134 return -EIO;
2135
Harald Welte4bfdfe72009-06-10 23:11:52 +08002136 if (!trans1->lchan || !trans2->lchan)
2137 return -EIO;
2138
2139 /* through-connect channel */
2140 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002141}
2142
Harald Welte4bfdfe72009-06-10 23:11:52 +08002143/* enable receive of channels to upqueue */
2144static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2145{
2146 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002147
Harald Welte4bfdfe72009-06-10 23:11:52 +08002148 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002149 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002150 if (!trans)
2151 return -EIO;
2152 if (!trans->lchan)
2153 return 0;
2154
2155 // todo IPACCESS
2156 if (enable)
2157 return trau_recv_lchan(trans->lchan, data->callref);
2158 return trau_mux_unmap(NULL, data->callref);
2159}
2160
2161/* send a frame to channel */
2162static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2163{
2164 struct gsm_trans *trans;
2165
2166 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002167 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002168 if (!trans)
2169 return -EIO;
2170 if (!trans->lchan)
2171 return 0;
2172 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2173 trans->lchan->type != GSM_LCHAN_TCH_H)
2174 return 0;
2175
2176 // todo IPACCESS
2177 return trau_send_lchan(trans->lchan,
2178 (struct decoded_trau_frame *)frame->data);
2179}
2180
2181
2182static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2183{
2184 DEBUGP(DCC, "-> STATUS ENQ\n");
2185 return gsm48_cc_tx_status(trans, msg);
2186}
2187
2188static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2189static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2190
2191static void gsm48_cc_timeout(void *arg)
2192{
2193 struct gsm_trans *trans = arg;
2194 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002195 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2196 int mo_location = GSM48_CAUSE_LOC_USER;
2197 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2198 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002199 struct gsm_mncc mo_rel, l4_rel;
2200
2201 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2202 mo_rel.callref = trans->callref;
2203 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2204 l4_rel.callref = trans->callref;
2205
Harald Weltedcaf5652009-07-23 18:56:43 +02002206 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002207 case 0x303:
2208 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002209 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002210 break;
2211 case 0x310:
2212 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002213 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002214 break;
2215 case 0x313:
2216 disconnect = 1;
2217 /* unknown, did not find it in the specs */
2218 break;
2219 case 0x301:
2220 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002221 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002222 break;
2223 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002224 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002225 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002226 gsm48_cc_tx_release(trans, &trans->cc.msg);
2227 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002228 break; /* stay in release state */
2229 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002230 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002231 return;
2232// release = 1;
2233// l4_cause = 14;
2234// break;
2235 case 0x306:
2236 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002237 mo_cause = trans->cc.msg.cause.value;
2238 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002239 break;
2240 case 0x323:
2241 disconnect = 1;
2242 break;
2243 default:
2244 release = 1;
2245 }
2246
2247 if (release && trans->callref) {
2248 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002249 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002250 l4_location, l4_cause);
2251 trans->callref = 0;
2252 }
2253
2254 if (disconnect && trans->callref) {
2255 /* process disconnect towards layer 4 */
2256 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002257 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002258 }
2259
2260 /* process disconnect towards mobile station */
2261 if (disconnect || release) {
2262 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002263 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2264 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2265 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002266 mo_rel.cause.diag_len = 3;
2267
2268 if (disconnect)
2269 gsm48_cc_tx_disconnect(trans, &mo_rel);
2270 if (release)
2271 gsm48_cc_tx_release(trans, &mo_rel);
2272 }
2273
2274}
2275
2276static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2277 int sec, int micro)
2278{
2279 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002280 trans->cc.timer.cb = gsm48_cc_timeout;
2281 trans->cc.timer.data = trans;
2282 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2283 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002284}
2285
2286static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2287{
2288 struct gsm48_hdr *gh = msgb_l3(msg);
2289 u_int8_t msg_type = gh->msg_type & 0xbf;
2290 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2291 struct tlv_parsed tp;
2292 struct gsm_mncc setup;
2293
2294 memset(&setup, 0, sizeof(struct gsm_mncc));
2295 setup.callref = trans->callref;
2296 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2297 /* emergency setup is identified by msg_type */
2298 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2299 setup.emergency = 1;
2300
2301 /* use subscriber as calling party number */
2302 if (trans->subscr) {
2303 setup.fields |= MNCC_F_CALLING;
2304 strncpy(setup.calling.number, trans->subscr->extension,
2305 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002306 strncpy(setup.imsi, trans->subscr->imsi,
2307 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002308 }
2309 /* bearer capability */
2310 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2311 setup.fields |= MNCC_F_BEARER_CAP;
2312 decode_bearer_cap(&setup.bearer_cap,
2313 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2314 }
2315 /* facility */
2316 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2317 setup.fields |= MNCC_F_FACILITY;
2318 decode_facility(&setup.facility,
2319 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2320 }
2321 /* called party bcd number */
2322 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2323 setup.fields |= MNCC_F_CALLED;
2324 decode_called(&setup.called,
2325 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2326 }
2327 /* user-user */
2328 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2329 setup.fields |= MNCC_F_USERUSER;
2330 decode_useruser(&setup.useruser,
2331 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2332 }
2333 /* ss-version */
2334 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2335 setup.fields |= MNCC_F_SSVERSION;
2336 decode_ssversion(&setup.ssversion,
2337 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2338 }
2339 /* CLIR suppression */
2340 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2341 setup.clir.sup = 1;
2342 /* CLIR invocation */
2343 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2344 setup.clir.inv = 1;
2345 /* cc cap */
2346 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2347 setup.fields |= MNCC_F_CCCAP;
2348 decode_cccap(&setup.cccap,
2349 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2350 }
2351
Harald Welte4bfdfe72009-06-10 23:11:52 +08002352 new_cc_state(trans, GSM_CSTATE_INITIATED);
2353
2354 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002355 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002356
Harald Welte13cac662009-07-29 12:10:35 +02002357 /* MNCC code will modify the channel asynchronously, we should
2358 * ipaccess-bind only after the modification has been made to the
2359 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002360 return 0;
2361}
2362
2363static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002364{
2365 struct msgb *msg = gsm48_msgb_alloc();
2366 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002367 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002368 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002369
Harald Welte7ccf7782009-02-17 01:43:01 +00002370 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002371
Harald Welte4bfdfe72009-06-10 23:11:52 +08002372 /* transaction id must not be assigned */
2373 if (trans->transaction_id != 0xff) { /* unasssigned */
2374 DEBUGP(DCC, "TX Setup with assigned transaction. "
2375 "This is not allowed!\n");
2376 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002377 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002378 GSM48_CAUSE_LOC_PRN_S_LU,
2379 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002380 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002381 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002382 return rc;
2383 }
2384
2385 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002386 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2387 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002388 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002389 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002390 GSM48_CAUSE_LOC_PRN_S_LU,
2391 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002392 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002393 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002394 return rc;
2395 }
Harald Welte78283ef2009-07-23 21:36:44 +02002396 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002397
Harald Welte65e74cc2008-12-29 01:55:35 +00002398 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002399
Harald Welte4bfdfe72009-06-10 23:11:52 +08002400 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002401
Harald Welte4bfdfe72009-06-10 23:11:52 +08002402 /* bearer capability */
2403 if (setup->fields & MNCC_F_BEARER_CAP)
2404 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2405 /* facility */
2406 if (setup->fields & MNCC_F_FACILITY)
2407 encode_facility(msg, 0, &setup->facility);
2408 /* progress */
2409 if (setup->fields & MNCC_F_PROGRESS)
2410 encode_progress(msg, 0, &setup->progress);
2411 /* calling party BCD number */
2412 if (setup->fields & MNCC_F_CALLING)
2413 encode_calling(msg, &setup->calling);
2414 /* called party BCD number */
2415 if (setup->fields & MNCC_F_CALLED)
2416 encode_called(msg, &setup->called);
2417 /* user-user */
2418 if (setup->fields & MNCC_F_USERUSER)
2419 encode_useruser(msg, 0, &setup->useruser);
2420 /* redirecting party BCD number */
2421 if (setup->fields & MNCC_F_REDIRECTING)
2422 encode_redirecting(msg, &setup->redirecting);
2423 /* signal */
2424 if (setup->fields & MNCC_F_SIGNAL)
2425 encode_signal(msg, setup->signal);
2426
2427 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002428
Harald Welte39e2ead2009-07-23 21:13:03 +02002429 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002430}
2431
Harald Welte4bfdfe72009-06-10 23:11:52 +08002432static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2433{
2434 struct gsm48_hdr *gh = msgb_l3(msg);
2435 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2436 struct tlv_parsed tp;
2437 struct gsm_mncc call_conf;
2438
2439 gsm48_stop_cc_timer(trans);
2440 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2441
2442 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2443 call_conf.callref = trans->callref;
2444 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2445#if 0
2446 /* repeat */
2447 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2448 call_conf.repeat = 1;
2449 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2450 call_conf.repeat = 2;
2451#endif
2452 /* bearer capability */
2453 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2454 call_conf.fields |= MNCC_F_BEARER_CAP;
2455 decode_bearer_cap(&call_conf.bearer_cap,
2456 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2457 }
2458 /* cause */
2459 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2460 call_conf.fields |= MNCC_F_CAUSE;
2461 decode_cause(&call_conf.cause,
2462 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2463 }
2464 /* cc cap */
2465 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2466 call_conf.fields |= MNCC_F_CCCAP;
2467 decode_cccap(&call_conf.cccap,
2468 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2469 }
2470
2471 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2472
Harald Welte596fed42009-07-23 19:06:52 +02002473 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2474 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002475}
2476
2477static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2478{
2479 struct gsm_mncc *proceeding = arg;
2480 struct msgb *msg = gsm48_msgb_alloc();
2481 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2482
Harald Welte4bfdfe72009-06-10 23:11:52 +08002483 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2484
2485 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2486
2487 /* bearer capability */
2488 if (proceeding->fields & MNCC_F_BEARER_CAP)
2489 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2490 /* facility */
2491 if (proceeding->fields & MNCC_F_FACILITY)
2492 encode_facility(msg, 0, &proceeding->facility);
2493 /* progress */
2494 if (proceeding->fields & MNCC_F_PROGRESS)
2495 encode_progress(msg, 0, &proceeding->progress);
2496
Harald Welte39e2ead2009-07-23 21:13:03 +02002497 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002498}
2499
2500static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2501{
2502 struct gsm48_hdr *gh = msgb_l3(msg);
2503 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2504 struct tlv_parsed tp;
2505 struct gsm_mncc alerting;
2506
2507 gsm48_stop_cc_timer(trans);
2508 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2509
2510 memset(&alerting, 0, sizeof(struct gsm_mncc));
2511 alerting.callref = trans->callref;
2512 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2513 /* facility */
2514 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2515 alerting.fields |= MNCC_F_FACILITY;
2516 decode_facility(&alerting.facility,
2517 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2518 }
2519
2520 /* progress */
2521 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2522 alerting.fields |= MNCC_F_PROGRESS;
2523 decode_progress(&alerting.progress,
2524 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2525 }
2526 /* ss-version */
2527 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2528 alerting.fields |= MNCC_F_SSVERSION;
2529 decode_ssversion(&alerting.ssversion,
2530 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2531 }
2532
2533 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2534
Harald Welte596fed42009-07-23 19:06:52 +02002535 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2536 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002537}
2538
2539static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2540{
2541 struct gsm_mncc *alerting = arg;
2542 struct msgb *msg = gsm48_msgb_alloc();
2543 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2544
Harald Welte4bfdfe72009-06-10 23:11:52 +08002545 gh->msg_type = GSM48_MT_CC_ALERTING;
2546
2547 /* facility */
2548 if (alerting->fields & MNCC_F_FACILITY)
2549 encode_facility(msg, 0, &alerting->facility);
2550 /* progress */
2551 if (alerting->fields & MNCC_F_PROGRESS)
2552 encode_progress(msg, 0, &alerting->progress);
2553 /* user-user */
2554 if (alerting->fields & MNCC_F_USERUSER)
2555 encode_useruser(msg, 0, &alerting->useruser);
2556
2557 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2558
Harald Welte39e2ead2009-07-23 21:13:03 +02002559 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002560}
2561
2562static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2563{
2564 struct gsm_mncc *progress = arg;
2565 struct msgb *msg = gsm48_msgb_alloc();
2566 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2567
Harald Welte4bfdfe72009-06-10 23:11:52 +08002568 gh->msg_type = GSM48_MT_CC_PROGRESS;
2569
2570 /* progress */
2571 encode_progress(msg, 1, &progress->progress);
2572 /* user-user */
2573 if (progress->fields & MNCC_F_USERUSER)
2574 encode_useruser(msg, 0, &progress->useruser);
2575
Harald Welte39e2ead2009-07-23 21:13:03 +02002576 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002577}
2578
2579static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2580{
2581 struct gsm_mncc *connect = arg;
2582 struct msgb *msg = gsm48_msgb_alloc();
2583 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2584
Harald Welte4bfdfe72009-06-10 23:11:52 +08002585 gh->msg_type = GSM48_MT_CC_CONNECT;
2586
2587 gsm48_stop_cc_timer(trans);
2588 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2589
2590 /* facility */
2591 if (connect->fields & MNCC_F_FACILITY)
2592 encode_facility(msg, 0, &connect->facility);
2593 /* progress */
2594 if (connect->fields & MNCC_F_PROGRESS)
2595 encode_progress(msg, 0, &connect->progress);
2596 /* connected number */
2597 if (connect->fields & MNCC_F_CONNECTED)
2598 encode_connected(msg, &connect->connected);
2599 /* user-user */
2600 if (connect->fields & MNCC_F_USERUSER)
2601 encode_useruser(msg, 0, &connect->useruser);
2602
2603 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2604
Harald Welte39e2ead2009-07-23 21:13:03 +02002605 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002606}
2607
2608static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2609{
2610 struct gsm48_hdr *gh = msgb_l3(msg);
2611 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2612 struct tlv_parsed tp;
2613 struct gsm_mncc connect;
2614
2615 gsm48_stop_cc_timer(trans);
2616
2617 memset(&connect, 0, sizeof(struct gsm_mncc));
2618 connect.callref = trans->callref;
2619 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2620 /* use subscriber as connected party number */
2621 if (trans->subscr) {
2622 connect.fields |= MNCC_F_CONNECTED;
2623 strncpy(connect.connected.number, trans->subscr->extension,
2624 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002625 strncpy(connect.imsi, trans->subscr->imsi,
2626 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002627 }
2628 /* facility */
2629 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2630 connect.fields |= MNCC_F_FACILITY;
2631 decode_facility(&connect.facility,
2632 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2633 }
2634 /* user-user */
2635 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2636 connect.fields |= MNCC_F_USERUSER;
2637 decode_useruser(&connect.useruser,
2638 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2639 }
2640 /* ss-version */
2641 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2642 connect.fields |= MNCC_F_SSVERSION;
2643 decode_ssversion(&connect.ssversion,
2644 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2645 }
2646
2647 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2648
Harald Welte596fed42009-07-23 19:06:52 +02002649 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002650}
2651
2652
2653static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2654{
2655 struct gsm_mncc connect_ack;
2656
2657 gsm48_stop_cc_timer(trans);
2658
2659 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2660
2661 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2662 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002663 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002664 &connect_ack);
2665}
2666
2667static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2668{
2669 struct msgb *msg = gsm48_msgb_alloc();
2670 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2671
Harald Welte4bfdfe72009-06-10 23:11:52 +08002672 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2673
2674 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2675
Harald Welte39e2ead2009-07-23 21:13:03 +02002676 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002677}
2678
2679static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2680{
2681 struct gsm48_hdr *gh = msgb_l3(msg);
2682 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2683 struct tlv_parsed tp;
2684 struct gsm_mncc disc;
2685
2686 gsm48_stop_cc_timer(trans);
2687
2688 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2689
2690 memset(&disc, 0, sizeof(struct gsm_mncc));
2691 disc.callref = trans->callref;
2692 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2693 /* cause */
2694 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2695 disc.fields |= MNCC_F_CAUSE;
2696 decode_cause(&disc.cause,
2697 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2698 }
2699 /* facility */
2700 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2701 disc.fields |= MNCC_F_FACILITY;
2702 decode_facility(&disc.facility,
2703 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2704 }
2705 /* user-user */
2706 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2707 disc.fields |= MNCC_F_USERUSER;
2708 decode_useruser(&disc.useruser,
2709 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2710 }
2711 /* ss-version */
2712 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2713 disc.fields |= MNCC_F_SSVERSION;
2714 decode_ssversion(&disc.ssversion,
2715 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2716 }
2717
Harald Welte596fed42009-07-23 19:06:52 +02002718 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002719
2720}
2721
Harald Weltec66b71c2009-06-11 14:23:20 +08002722static struct gsm_mncc_cause default_cause = {
2723 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2724 .coding = 0,
2725 .rec = 0,
2726 .rec_val = 0,
2727 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2728 .diag_len = 0,
2729 .diag = { 0 },
2730};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002731
2732static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2733{
2734 struct gsm_mncc *disc = arg;
2735 struct msgb *msg = gsm48_msgb_alloc();
2736 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2737
Harald Welte4bfdfe72009-06-10 23:11:52 +08002738 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2739
2740 gsm48_stop_cc_timer(trans);
2741 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2742
2743 /* cause */
2744 if (disc->fields & MNCC_F_CAUSE)
2745 encode_cause(msg, 1, &disc->cause);
2746 else
2747 encode_cause(msg, 1, &default_cause);
2748
2749 /* facility */
2750 if (disc->fields & MNCC_F_FACILITY)
2751 encode_facility(msg, 0, &disc->facility);
2752 /* progress */
2753 if (disc->fields & MNCC_F_PROGRESS)
2754 encode_progress(msg, 0, &disc->progress);
2755 /* user-user */
2756 if (disc->fields & MNCC_F_USERUSER)
2757 encode_useruser(msg, 0, &disc->useruser);
2758
2759 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002760 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002761
2762 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2763
Harald Welte39e2ead2009-07-23 21:13:03 +02002764 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002765}
2766
2767static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2768{
2769 struct gsm48_hdr *gh = msgb_l3(msg);
2770 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2771 struct tlv_parsed tp;
2772 struct gsm_mncc rel;
2773 int rc;
2774
2775 gsm48_stop_cc_timer(trans);
2776
2777 memset(&rel, 0, sizeof(struct gsm_mncc));
2778 rel.callref = trans->callref;
2779 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2780 /* cause */
2781 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2782 rel.fields |= MNCC_F_CAUSE;
2783 decode_cause(&rel.cause,
2784 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2785 }
2786 /* facility */
2787 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2788 rel.fields |= MNCC_F_FACILITY;
2789 decode_facility(&rel.facility,
2790 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2791 }
2792 /* user-user */
2793 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2794 rel.fields |= MNCC_F_USERUSER;
2795 decode_useruser(&rel.useruser,
2796 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2797 }
2798 /* ss-version */
2799 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2800 rel.fields |= MNCC_F_SSVERSION;
2801 decode_ssversion(&rel.ssversion,
2802 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2803 }
2804
Harald Weltedcaf5652009-07-23 18:56:43 +02002805 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002806 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002807 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002808 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002809 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002810 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002811 GSM48_MT_CC_RELEASE_COMPL);
2812 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002813 }
2814
2815 new_cc_state(trans, GSM_CSTATE_NULL);
2816
2817 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002818 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002819
2820 return rc;
2821}
2822
2823static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2824{
2825 struct gsm_mncc *rel = arg;
2826 struct msgb *msg = gsm48_msgb_alloc();
2827 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2828
Harald Welte4bfdfe72009-06-10 23:11:52 +08002829 gh->msg_type = GSM48_MT_CC_RELEASE;
2830
2831 trans->callref = 0;
2832
2833 gsm48_stop_cc_timer(trans);
2834 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2835
2836 /* cause */
2837 if (rel->fields & MNCC_F_CAUSE)
2838 encode_cause(msg, 0, &rel->cause);
2839 /* facility */
2840 if (rel->fields & MNCC_F_FACILITY)
2841 encode_facility(msg, 0, &rel->facility);
2842 /* user-user */
2843 if (rel->fields & MNCC_F_USERUSER)
2844 encode_useruser(msg, 0, &rel->useruser);
2845
Harald Weltedcaf5652009-07-23 18:56:43 +02002846 trans->cc.T308_second = 0;
2847 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002848
Harald Weltedcaf5652009-07-23 18:56:43 +02002849 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002850 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2851
Harald Welte39e2ead2009-07-23 21:13:03 +02002852 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002853}
2854
2855static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2856{
2857 struct gsm48_hdr *gh = msgb_l3(msg);
2858 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2859 struct tlv_parsed tp;
2860 struct gsm_mncc rel;
2861 int rc = 0;
2862
2863 gsm48_stop_cc_timer(trans);
2864
2865 memset(&rel, 0, sizeof(struct gsm_mncc));
2866 rel.callref = trans->callref;
2867 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2868 /* cause */
2869 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2870 rel.fields |= MNCC_F_CAUSE;
2871 decode_cause(&rel.cause,
2872 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2873 }
2874 /* facility */
2875 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2876 rel.fields |= MNCC_F_FACILITY;
2877 decode_facility(&rel.facility,
2878 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2879 }
2880 /* user-user */
2881 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2882 rel.fields |= MNCC_F_USERUSER;
2883 decode_useruser(&rel.useruser,
2884 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2885 }
2886 /* ss-version */
2887 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2888 rel.fields |= MNCC_F_SSVERSION;
2889 decode_ssversion(&rel.ssversion,
2890 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2891 }
2892
2893 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002894 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002895 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002896 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002897 MNCC_REJ_IND, &rel);
2898 break;
2899 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002900 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002901 MNCC_REL_CNF, &rel);
2902 break;
2903 default:
Harald Welte596fed42009-07-23 19:06:52 +02002904 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002905 MNCC_REL_IND, &rel);
2906 }
2907 }
2908
2909 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002910 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002911
2912 return rc;
2913}
2914
2915static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2916{
2917 struct gsm_mncc *rel = arg;
2918 struct msgb *msg = gsm48_msgb_alloc();
2919 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2920
Harald Welte4bfdfe72009-06-10 23:11:52 +08002921 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2922
2923 trans->callref = 0;
2924
2925 gsm48_stop_cc_timer(trans);
2926
2927 /* cause */
2928 if (rel->fields & MNCC_F_CAUSE)
2929 encode_cause(msg, 0, &rel->cause);
2930 /* facility */
2931 if (rel->fields & MNCC_F_FACILITY)
2932 encode_facility(msg, 0, &rel->facility);
2933 /* user-user */
2934 if (rel->fields & MNCC_F_USERUSER)
2935 encode_useruser(msg, 0, &rel->useruser);
2936
Harald Weltedcaf5652009-07-23 18:56:43 +02002937 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002938
Harald Welte39e2ead2009-07-23 21:13:03 +02002939 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002940}
2941
2942static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2943{
2944 struct gsm48_hdr *gh = msgb_l3(msg);
2945 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2946 struct tlv_parsed tp;
2947 struct gsm_mncc fac;
2948
2949 memset(&fac, 0, sizeof(struct gsm_mncc));
2950 fac.callref = trans->callref;
2951 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2952 /* facility */
2953 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2954 fac.fields |= MNCC_F_FACILITY;
2955 decode_facility(&fac.facility,
2956 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2957 }
2958 /* ss-version */
2959 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2960 fac.fields |= MNCC_F_SSVERSION;
2961 decode_ssversion(&fac.ssversion,
2962 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2963 }
2964
Harald Welte596fed42009-07-23 19:06:52 +02002965 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002966}
2967
2968static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2969{
2970 struct gsm_mncc *fac = arg;
2971 struct msgb *msg = gsm48_msgb_alloc();
2972 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2973
Harald Welte4bfdfe72009-06-10 23:11:52 +08002974 gh->msg_type = GSM48_MT_CC_FACILITY;
2975
2976 /* facility */
2977 encode_facility(msg, 1, &fac->facility);
2978
Harald Welte39e2ead2009-07-23 21:13:03 +02002979 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002980}
2981
2982static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2983{
2984 struct gsm_mncc hold;
2985
2986 memset(&hold, 0, sizeof(struct gsm_mncc));
2987 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002988 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002989}
2990
2991static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2992{
2993 struct msgb *msg = gsm48_msgb_alloc();
2994 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2995
Harald Welte4bfdfe72009-06-10 23:11:52 +08002996 gh->msg_type = GSM48_MT_CC_HOLD_ACK;
2997
Harald Welte39e2ead2009-07-23 21:13:03 +02002998 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002999}
3000
3001static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
3002{
3003 struct gsm_mncc *hold_rej = arg;
3004 struct msgb *msg = gsm48_msgb_alloc();
3005 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3006
Harald Welte4bfdfe72009-06-10 23:11:52 +08003007 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
3008
3009 /* cause */
3010 if (hold_rej->fields & MNCC_F_CAUSE)
3011 encode_cause(msg, 1, &hold_rej->cause);
3012 else
3013 encode_cause(msg, 1, &default_cause);
3014
Harald Welte39e2ead2009-07-23 21:13:03 +02003015 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003016}
3017
3018static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
3019{
3020 struct gsm_mncc retrieve;
3021
3022 memset(&retrieve, 0, sizeof(struct gsm_mncc));
3023 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003024 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
3025 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003026}
3027
3028static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
3029{
3030 struct msgb *msg = gsm48_msgb_alloc();
3031 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3032
Harald Welte4bfdfe72009-06-10 23:11:52 +08003033 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3034
Harald Welte39e2ead2009-07-23 21:13:03 +02003035 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003036}
3037
3038static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3039{
3040 struct gsm_mncc *retrieve_rej = arg;
3041 struct msgb *msg = gsm48_msgb_alloc();
3042 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3043
Harald Welte4bfdfe72009-06-10 23:11:52 +08003044 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3045
3046 /* cause */
3047 if (retrieve_rej->fields & MNCC_F_CAUSE)
3048 encode_cause(msg, 1, &retrieve_rej->cause);
3049 else
3050 encode_cause(msg, 1, &default_cause);
3051
Harald Welte39e2ead2009-07-23 21:13:03 +02003052 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003053}
3054
3055static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3056{
3057 struct gsm48_hdr *gh = msgb_l3(msg);
3058 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3059 struct tlv_parsed tp;
3060 struct gsm_mncc dtmf;
3061
3062 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3063 dtmf.callref = trans->callref;
3064 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3065 /* keypad facility */
3066 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3067 dtmf.fields |= MNCC_F_KEYPAD;
3068 decode_keypad(&dtmf.keypad,
3069 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3070 }
3071
Harald Welte596fed42009-07-23 19:06:52 +02003072 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003073}
3074
3075static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3076{
3077 struct gsm_mncc *dtmf = arg;
3078 struct msgb *msg = gsm48_msgb_alloc();
3079 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3080
Harald Welte4bfdfe72009-06-10 23:11:52 +08003081 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3082
3083 /* keypad */
3084 if (dtmf->fields & MNCC_F_KEYPAD)
3085 encode_keypad(msg, dtmf->keypad);
3086
Harald Welte39e2ead2009-07-23 21:13:03 +02003087 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003088}
3089
3090static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3091{
3092 struct gsm_mncc *dtmf = arg;
3093 struct msgb *msg = gsm48_msgb_alloc();
3094 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3095
Harald Welte4bfdfe72009-06-10 23:11:52 +08003096 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3097
3098 /* cause */
3099 if (dtmf->fields & MNCC_F_CAUSE)
3100 encode_cause(msg, 1, &dtmf->cause);
3101 else
3102 encode_cause(msg, 1, &default_cause);
3103
Harald Welte39e2ead2009-07-23 21:13:03 +02003104 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003105}
3106
3107static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3108{
3109 struct msgb *msg = gsm48_msgb_alloc();
3110 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3111
Harald Welte4bfdfe72009-06-10 23:11:52 +08003112 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3113
Harald Welte39e2ead2009-07-23 21:13:03 +02003114 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003115}
3116
3117static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3118{
3119 struct gsm_mncc dtmf;
3120
3121 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3122 dtmf.callref = trans->callref;
3123
Harald Welte596fed42009-07-23 19:06:52 +02003124 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003125}
3126
3127static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3128{
3129 struct gsm48_hdr *gh = msgb_l3(msg);
3130 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3131 struct tlv_parsed tp;
3132 struct gsm_mncc modify;
3133
3134 memset(&modify, 0, sizeof(struct gsm_mncc));
3135 modify.callref = trans->callref;
3136 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3137 /* bearer capability */
3138 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3139 modify.fields |= MNCC_F_BEARER_CAP;
3140 decode_bearer_cap(&modify.bearer_cap,
3141 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3142 }
3143
3144 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3145
Harald Welte596fed42009-07-23 19:06:52 +02003146 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003147}
3148
3149static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3150{
3151 struct gsm_mncc *modify = arg;
3152 struct msgb *msg = gsm48_msgb_alloc();
3153 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3154
Harald Welte4bfdfe72009-06-10 23:11:52 +08003155 gh->msg_type = GSM48_MT_CC_MODIFY;
3156
3157 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3158
3159 /* bearer capability */
3160 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3161
3162 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3163
Harald Welte39e2ead2009-07-23 21:13:03 +02003164 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003165}
3166
3167static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3168{
3169 struct gsm48_hdr *gh = msgb_l3(msg);
3170 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3171 struct tlv_parsed tp;
3172 struct gsm_mncc modify;
3173
3174 gsm48_stop_cc_timer(trans);
3175
3176 memset(&modify, 0, sizeof(struct gsm_mncc));
3177 modify.callref = trans->callref;
3178 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3179 /* bearer capability */
3180 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3181 modify.fields |= MNCC_F_BEARER_CAP;
3182 decode_bearer_cap(&modify.bearer_cap,
3183 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3184 }
3185
3186 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3187
Harald Welte596fed42009-07-23 19:06:52 +02003188 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003189}
3190
3191static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3192{
3193 struct gsm_mncc *modify = arg;
3194 struct msgb *msg = gsm48_msgb_alloc();
3195 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3196
Harald Welte4bfdfe72009-06-10 23:11:52 +08003197 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3198
3199 /* bearer capability */
3200 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3201
3202 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3203
Harald Welte39e2ead2009-07-23 21:13:03 +02003204 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003205}
3206
3207static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3208{
3209 struct gsm48_hdr *gh = msgb_l3(msg);
3210 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3211 struct tlv_parsed tp;
3212 struct gsm_mncc modify;
3213
3214 gsm48_stop_cc_timer(trans);
3215
3216 memset(&modify, 0, sizeof(struct gsm_mncc));
3217 modify.callref = trans->callref;
3218 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3219 /* bearer capability */
3220 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3221 modify.fields |= GSM48_IE_BEARER_CAP;
3222 decode_bearer_cap(&modify.bearer_cap,
3223 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3224 }
3225 /* cause */
3226 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3227 modify.fields |= MNCC_F_CAUSE;
3228 decode_cause(&modify.cause,
3229 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3230 }
3231
3232 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3233
Harald Welte596fed42009-07-23 19:06:52 +02003234 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003235}
3236
3237static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3238{
3239 struct gsm_mncc *modify = arg;
3240 struct msgb *msg = gsm48_msgb_alloc();
3241 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3242
Harald Welte4bfdfe72009-06-10 23:11:52 +08003243 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3244
3245 /* bearer capability */
3246 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3247 /* cause */
3248 encode_cause(msg, 1, &modify->cause);
3249
3250 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3251
Harald Welte39e2ead2009-07-23 21:13:03 +02003252 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003253}
3254
3255static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3256{
3257 struct gsm_mncc *notify = arg;
3258 struct msgb *msg = gsm48_msgb_alloc();
3259 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3260
Harald Welte4bfdfe72009-06-10 23:11:52 +08003261 gh->msg_type = GSM48_MT_CC_NOTIFY;
3262
3263 /* notify */
3264 encode_notify(msg, notify->notify);
3265
Harald Welte39e2ead2009-07-23 21:13:03 +02003266 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003267}
3268
3269static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3270{
3271 struct gsm48_hdr *gh = msgb_l3(msg);
3272 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3273// struct tlv_parsed tp;
3274 struct gsm_mncc notify;
3275
3276 memset(&notify, 0, sizeof(struct gsm_mncc));
3277 notify.callref = trans->callref;
3278// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3279 if (payload_len >= 1)
3280 decode_notify(&notify.notify, gh->data);
3281
Harald Welte596fed42009-07-23 19:06:52 +02003282 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003283}
3284
3285static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3286{
3287 struct gsm_mncc *user = arg;
3288 struct msgb *msg = gsm48_msgb_alloc();
3289 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3290
Harald Welte4bfdfe72009-06-10 23:11:52 +08003291 gh->msg_type = GSM48_MT_CC_USER_INFO;
3292
3293 /* user-user */
3294 if (user->fields & MNCC_F_USERUSER)
3295 encode_useruser(msg, 1, &user->useruser);
3296 /* more data */
3297 if (user->more)
3298 encode_more(msg);
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_userinfo(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 user;
3309
3310 memset(&user, 0, sizeof(struct gsm_mncc));
3311 user.callref = trans->callref;
3312 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3313 /* user-user */
3314 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3315 user.fields |= MNCC_F_USERUSER;
3316 decode_useruser(&user.useruser,
3317 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3318 }
3319 /* more data */
3320 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3321 user.more = 1;
3322
Harald Welte596fed42009-07-23 19:06:52 +02003323 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003324}
3325
3326static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3327{
3328 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003329 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003330
Harald Welte13cac662009-07-29 12:10:35 +02003331 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3332 if (rc < 0)
3333 return rc;
3334
3335 /* FIXME: we not only need to do this after mode modify, but
3336 * also after channel activation */
3337 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3338 mode->lchan_mode != GSM48_CMODE_SIGN)
3339 rc = rsl_ipacc_bind(trans->lchan);
3340
3341 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003342}
3343
3344static struct downstate {
3345 u_int32_t states;
3346 int type;
3347 int (*rout) (struct gsm_trans *trans, void *arg);
3348} downstatelist[] = {
3349 /* mobile originating call establishment */
3350 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3351 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3352 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3353 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3354 {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 */
3355 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3356 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3357 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3358 /* mobile terminating call establishment */
3359 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3360 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3361 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3362 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3363 /* signalling during call */
3364 {SBIT(GSM_CSTATE_ACTIVE),
3365 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3366 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3367 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3368 {ALL_STATES,
3369 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3370 {ALL_STATES,
3371 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3372 {ALL_STATES,
3373 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3374 {SBIT(GSM_CSTATE_ACTIVE),
3375 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3376 {SBIT(GSM_CSTATE_ACTIVE),
3377 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3378 {SBIT(GSM_CSTATE_ACTIVE),
3379 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3380 {SBIT(GSM_CSTATE_ACTIVE),
3381 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3382 {SBIT(GSM_CSTATE_ACTIVE),
3383 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3384 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3385 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3386 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3387 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3388 {SBIT(GSM_CSTATE_ACTIVE),
3389 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3390 /* clearing */
3391 {SBIT(GSM_CSTATE_INITIATED),
3392 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3393 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3394 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3395 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3396 MNCC_REL_REQ, gsm48_cc_tx_release},
3397 /* special */
3398 {ALL_STATES,
3399 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3400};
3401
3402#define DOWNSLLEN \
3403 (sizeof(downstatelist) / sizeof(struct downstate))
3404
3405
3406int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3407{
Harald Welte1a6f7982009-08-09 18:52:33 +02003408 int i, rc = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003409 struct gsm_trans *trans = NULL, *transt;
3410 struct gsm_subscriber *subscr;
Harald Welte1a6f7982009-08-09 18:52:33 +02003411 struct gsm_lchan *lchan = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003412 struct gsm_bts *bts = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003413 struct gsm_mncc *data = arg, rel;
3414
3415 /* handle special messages */
3416 switch(msg_type) {
3417 case MNCC_BRIDGE:
3418 return tch_bridge(net, arg);
3419 case MNCC_FRAME_DROP:
3420 return tch_recv(net, arg, 0);
3421 case MNCC_FRAME_RECV:
3422 return tch_recv(net, arg, 1);
3423 case GSM_TRAU_FRAME:
3424 return tch_frame(net, arg);
3425 }
3426
3427 memset(&rel, 0, sizeof(struct gsm_mncc));
3428 rel.callref = data->callref;
3429
3430 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003431 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003432
3433 /* Callref unknown */
3434 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003435 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003436 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3437 "Received '%s' from MNCC with "
3438 "unknown callref %d\n", data->called.number,
3439 get_mncc_name(msg_type), data->callref);
3440 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003441 return mncc_release_ind(net, NULL, data->callref,
3442 GSM48_CAUSE_LOC_PRN_S_LU,
3443 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003444 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003445 if (!data->called.number[0] && !data->imsi[0]) {
3446 DEBUGP(DCC, "(bts - trx - ts - ti) "
3447 "Received '%s' from MNCC with "
3448 "no number or IMSI\n", get_mncc_name(msg_type));
3449 /* Invalid number */
3450 return mncc_release_ind(net, NULL, data->callref,
3451 GSM48_CAUSE_LOC_PRN_S_LU,
3452 GSM48_CC_CAUSE_INV_NR_FORMAT);
3453 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003454 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003455 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003456 subscr = subscr_get_by_extension(net,
3457 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003458 else
Harald Welte9176bd42009-07-23 18:46:00 +02003459 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003460 /* If subscriber is not found */
3461 if (!subscr) {
3462 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3463 "Received '%s' from MNCC with "
3464 "unknown subscriber %s\n", data->called.number,
3465 get_mncc_name(msg_type), data->called.number);
3466 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003467 return mncc_release_ind(net, NULL, data->callref,
3468 GSM48_CAUSE_LOC_PRN_S_LU,
3469 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003470 }
3471 /* If subscriber is not "attached" */
3472 if (!subscr->lac) {
3473 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3474 "Received '%s' from MNCC with "
3475 "detached subscriber %s\n", data->called.number,
3476 get_mncc_name(msg_type), data->called.number);
3477 subscr_put(subscr);
3478 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003479 return mncc_release_ind(net, NULL, data->callref,
3480 GSM48_CAUSE_LOC_PRN_S_LU,
3481 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003482 }
3483 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003484 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3485 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003486 DEBUGP(DCC, "No memory for trans.\n");
3487 subscr_put(subscr);
3488 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003489 mncc_release_ind(net, NULL, data->callref,
3490 GSM48_CAUSE_LOC_PRN_S_LU,
3491 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003492 return -ENOMEM;
3493 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003494 /* Find lchan */
Harald Welte1a6f7982009-08-09 18:52:33 +02003495 lchan = lchan_for_subscr(subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003496 /* If subscriber has no lchan */
3497 if (!lchan) {
3498 /* find transaction with this subscriber already paging */
3499 llist_for_each_entry(transt, &net->trans_list, entry) {
3500 /* Transaction of our lchan? */
3501 if (transt == trans ||
3502 transt->subscr != subscr)
3503 continue;
3504 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3505 "Received '%s' from MNCC with "
3506 "unallocated channel, paging already "
3507 "started.\n", bts->nr,
3508 data->called.number,
3509 get_mncc_name(msg_type));
3510 return 0;
3511 }
3512 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003513 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003514 /* Trigger paging */
3515 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3516 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003517 return 0;
3518 }
3519 /* Assign lchan */
3520 trans->lchan = lchan;
3521 use_lchan(lchan);
3522 }
3523 lchan = trans->lchan;
3524
3525 /* if paging did not respond yet */
3526 if (!lchan) {
3527 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3528 "Received '%s' from MNCC in paging state\n",
3529 (trans->subscr)?(trans->subscr->extension):"-",
3530 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003531 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3532 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003533 if (msg_type == MNCC_REL_REQ)
3534 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3535 else
3536 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3537 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003538 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003539 return rc;
3540 }
3541
3542 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3543 "Received '%s' from MNCC in state %d (%s)\n",
3544 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3545 trans->transaction_id,
3546 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003547 get_mncc_name(msg_type), trans->cc.state,
3548 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003549
3550 /* Find function for current state and message */
3551 for (i = 0; i < DOWNSLLEN; i++)
3552 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003553 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003554 break;
3555 if (i == DOWNSLLEN) {
3556 DEBUGP(DCC, "Message unhandled at this state.\n");
3557 return 0;
3558 }
3559
3560 rc = downstatelist[i].rout(trans, arg);
3561
3562 return rc;
3563}
3564
3565
3566static struct datastate {
3567 u_int32_t states;
3568 int type;
3569 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3570} datastatelist[] = {
3571 /* mobile originating call establishment */
3572 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3573 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3574 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3575 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3576 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3577 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3578 /* mobile terminating call establishment */
3579 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3580 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3581 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3582 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3583 {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 */
3584 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3585 /* signalling during call */
3586 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3587 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3588 {SBIT(GSM_CSTATE_ACTIVE),
3589 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3590 {ALL_STATES,
3591 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3592 {ALL_STATES,
3593 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3594 {ALL_STATES,
3595 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3596 {SBIT(GSM_CSTATE_ACTIVE),
3597 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3598 {SBIT(GSM_CSTATE_ACTIVE),
3599 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3600 {SBIT(GSM_CSTATE_ACTIVE),
3601 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3602 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3603 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3604 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3605 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3606 {SBIT(GSM_CSTATE_ACTIVE),
3607 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3608 /* clearing */
3609 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3610 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3611 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3612 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3613 {ALL_STATES, /* 5.4.3.4 */
3614 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3615};
3616
3617#define DATASLLEN \
3618 (sizeof(datastatelist) / sizeof(struct datastate))
3619
Harald Welte4bc90a12008-12-27 16:32:52 +00003620static int gsm0408_rcv_cc(struct msgb *msg)
3621{
3622 struct gsm48_hdr *gh = msgb_l3(msg);
3623 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003624 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003625 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003626 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003627 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003628
Harald Welte4bfdfe72009-06-10 23:11:52 +08003629 if (msg_type & 0x80) {
3630 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3631 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003632 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003633
3634 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003635 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003636
Harald Welte6f5aee02009-07-23 21:21:14 +02003637 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003638 "Received '%s' from MS in state %d (%s)\n",
3639 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3640 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003641 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3642 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003643
3644 /* Create transaction */
3645 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003646 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003647 "creating new trans.\n", transaction_id);
3648 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003649 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3650 transaction_id, new_callref++);
3651 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003652 DEBUGP(DCC, "No memory for trans.\n");
3653 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003654 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003655 GSM48_MT_CC_RELEASE_COMPL);
3656 return -ENOMEM;
3657 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003658 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003659 trans->lchan = lchan;
3660 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003661 }
3662
3663 /* find function for current state and message */
3664 for (i = 0; i < DATASLLEN; i++)
3665 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003666 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003667 break;
3668 if (i == DATASLLEN) {
3669 DEBUGP(DCC, "Message unhandled at this state.\n");
3670 return 0;
3671 }
3672
3673 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003674
3675 return rc;
3676}
3677
Harald Welte52b1f982008-12-23 20:25:15 +00003678/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3679int gsm0408_rcvmsg(struct msgb *msg)
3680{
3681 struct gsm48_hdr *gh = msgb_l3(msg);
3682 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003683 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003684
3685 switch (pdisc) {
3686 case GSM48_PDISC_CC:
3687 rc = gsm0408_rcv_cc(msg);
3688 break;
3689 case GSM48_PDISC_MM:
3690 rc = gsm0408_rcv_mm(msg);
3691 break;
3692 case GSM48_PDISC_RR:
3693 rc = gsm0408_rcv_rr(msg);
3694 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003695 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003696 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003697 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003698 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003699 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003700 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3701 pdisc);
3702 break;
3703 default:
3704 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3705 pdisc);
3706 break;
3707 }
3708
3709 return rc;
3710}
Harald Welte8470bf22008-12-25 23:28:35 +00003711
Harald Welte8470bf22008-12-25 23:28:35 +00003712/* Section 9.1.8 / Table 9.9 */
3713struct chreq {
3714 u_int8_t val;
3715 u_int8_t mask;
3716 enum chreq_type type;
3717};
3718
3719/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3720static const struct chreq chreq_type_neci1[] = {
3721 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3722 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3723 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3724 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3725 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3726 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3727 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3728 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3729 { 0x10, 0xf0, CHREQ_T_SDCCH },
3730 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3731 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3732 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3733};
3734
3735/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3736static const struct chreq chreq_type_neci0[] = {
3737 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3738 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3739 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3740 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3741 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3742 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3743 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3744 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3745};
3746
3747static const enum gsm_chan_t ctype_by_chreq[] = {
3748 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3749 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3750 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3751 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3752 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3753 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3754 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3755 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3756 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3757 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3758 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3759 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3760};
3761
Harald Weltee14a57c2008-12-29 04:08:28 +00003762static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3763 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3764 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3765 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3766 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3767 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3768 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3769 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3770 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3771 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3772 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3773 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3774 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3775};
3776
Harald Welte8470bf22008-12-25 23:28:35 +00003777enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3778{
3779 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003780 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Welte8470bf22008-12-25 23:28:35 +00003781
Harald Weltee58ca7c2009-08-10 02:14:46 +02003782 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3783 const struct chreq *chr = &chreq_type_neci0[i];
Harald Welte8470bf22008-12-25 23:28:35 +00003784 if ((ra & chr->mask) == chr->val)
3785 return ctype_by_chreq[chr->type];
3786 }
3787 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3788 return GSM_LCHAN_SDCCH;
3789}
Harald Weltee14a57c2008-12-29 04:08:28 +00003790
3791enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3792{
3793 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003794 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Weltee14a57c2008-12-29 04:08:28 +00003795
Harald Weltee58ca7c2009-08-10 02:14:46 +02003796 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3797 const struct chreq *chr = &chreq_type_neci0[i];
Harald Weltee14a57c2008-12-29 04:08:28 +00003798 if ((ra & chr->mask) == chr->val)
3799 return reason_by_chreq[chr->type];
3800 }
3801 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3802 return GSM_CHREQ_REASON_OTHER;
3803}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003804
3805/* dequeue messages to layer 4 */
3806int bsc_upqueue(struct gsm_network *net)
3807{
3808 struct gsm_mncc *mncc;
3809 struct msgb *msg;
3810 int work = 0;
3811
3812 if (net)
3813 while ((msg = msgb_dequeue(&net->upqueue))) {
3814 mncc = (struct gsm_mncc *)msg->data;
3815 if (net->mncc_recv)
3816 net->mncc_recv(net, mncc->msg_type, mncc);
3817 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003818 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003819 }
3820
3821 return work;
3822}
Harald Weltedcaf5652009-07-23 18:56:43 +02003823
Harald Welte805f6442009-07-28 18:25:29 +02003824/*
3825 * This will be ran by the linker when loading the DSO. We use it to
3826 * do system initialization, e.g. registration of signal handlers.
3827 */
3828static __attribute__((constructor)) void on_dso_load_0408(void)
3829{
3830 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3831 "loc_updating_oper");
3832 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3833 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3834}