blob: 967e4ce589de5d8401efdb3f08f13581d3421386 [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 Welte4ed0e922009-01-10 03:17:30 +00001423
1424/*
1425 * Handle CM Service Requests
1426 * a) Verify that the packet is long enough to contain the information
1427 * we require otherwsie reject with INCORRECT_MESSAGE
1428 * b) Try to parse the TMSI. If we do not have one reject
1429 * c) Check that we know the subscriber with the TMSI otherwise reject
1430 * with a HLR cause
1431 * d) Set the subscriber on the gsm_lchan and accept
1432 */
Harald Welte4b634542008-12-27 01:55:51 +00001433static int gsm48_rx_mm_serv_req(struct msgb *msg)
1434{
Harald Welteba4cf162009-01-10 01:49:35 +00001435 u_int8_t mi_type;
Harald Welte4ed0e922009-01-10 03:17:30 +00001436 char mi_string[MI_SIZE];
Harald Welte4b634542008-12-27 01:55:51 +00001437
Harald Welte9176bd42009-07-23 18:46:00 +02001438 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welteba4cf162009-01-10 01:49:35 +00001439 struct gsm_subscriber *subscr;
1440 struct gsm48_hdr *gh = msgb_l3(msg);
1441 struct gsm48_service_request *req =
1442 (struct gsm48_service_request *)gh->data;
Harald Weltec9e02182009-05-01 19:07:53 +00001443 /* unfortunately in Phase1 the classmar2 length is variable */
1444 u_int8_t classmark2_len = gh->data[1];
1445 u_int8_t *classmark2 = gh->data+2;
1446 u_int8_t mi_len = *(classmark2 + classmark2_len);
1447 u_int8_t *mi = (classmark2 + classmark2_len + 1);
Harald Welteba4cf162009-01-10 01:49:35 +00001448
Harald Weltec9e02182009-05-01 19:07:53 +00001449 DEBUGP(DMM, "<- CM SERVICE REQUEST ");
Harald Welteba4cf162009-01-10 01:49:35 +00001450 if (msg->data_len < sizeof(struct gsm48_service_request*)) {
Harald Weltec9e02182009-05-01 19:07:53 +00001451 DEBUGPC(DMM, "wrong sized message\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001452 return gsm48_tx_mm_serv_rej(msg->lchan,
1453 GSM48_REJECT_INCORRECT_MESSAGE);
1454 }
1455
1456 if (msg->data_len < req->mi_len + 6) {
Harald Weltec9e02182009-05-01 19:07:53 +00001457 DEBUGPC(DMM, "does not fit in packet\n");
Harald Welteba4cf162009-01-10 01:49:35 +00001458 return gsm48_tx_mm_serv_rej(msg->lchan,
1459 GSM48_REJECT_INCORRECT_MESSAGE);
1460 }
1461
Harald Weltec9e02182009-05-01 19:07:53 +00001462 mi_type = mi[0] & GSM_MI_TYPE_MASK;
Harald Welteba4cf162009-01-10 01:49:35 +00001463 if (mi_type != GSM_MI_TYPE_TMSI) {
Harald Weltec9e02182009-05-01 19:07:53 +00001464 DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
Harald Welteba4cf162009-01-10 01:49:35 +00001465 return gsm48_tx_mm_serv_rej(msg->lchan,
1466 GSM48_REJECT_INCORRECT_MESSAGE);
1467 }
1468
Harald Weltec9e02182009-05-01 19:07:53 +00001469 mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
Harald Weltec9e02182009-05-01 19:07:53 +00001470 DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
Harald Welte4ed0e922009-01-10 03:17:30 +00001471 req->cm_service_type, mi_type, mi_string);
Harald Weltebcae43f2008-12-27 21:45:37 +00001472
Harald Welte9176bd42009-07-23 18:46:00 +02001473 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Holger Freythereb443982009-06-04 13:58:42 +00001474
Harald Welte2a139372009-02-22 21:14:55 +00001475 /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
Harald Welte4ed0e922009-01-10 03:17:30 +00001476 if (!subscr)
1477 return gsm48_tx_mm_serv_rej(msg->lchan,
1478 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
1479
1480 if (!msg->lchan->subscr)
1481 msg->lchan->subscr = subscr;
Harald Welte9bb7c702009-01-10 03:21:41 +00001482 else if (msg->lchan->subscr != subscr) {
1483 DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
1484 subscr_put(subscr);
1485 }
1486
Harald Weltec2e302d2009-07-05 14:08:13 +02001487 subscr->equipment.classmark2_len = classmark2_len;
1488 memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
1489 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001490
Harald Welte4b634542008-12-27 01:55:51 +00001491 return gsm48_tx_mm_serv_ack(msg->lchan);
1492}
1493
Harald Welte2a139372009-02-22 21:14:55 +00001494static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
1495{
Harald Welte9176bd42009-07-23 18:46:00 +02001496 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2a139372009-02-22 21:14:55 +00001497 struct gsm48_hdr *gh = msgb_l3(msg);
1498 struct gsm48_imsi_detach_ind *idi =
1499 (struct gsm48_imsi_detach_ind *) gh->data;
1500 u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
1501 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001502 struct gsm_subscriber *subscr = NULL;
Harald Welte2a139372009-02-22 21:14:55 +00001503
1504 mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
1505 DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
1506 mi_type, mi_string);
1507
1508 switch (mi_type) {
1509 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001510 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001511 break;
1512 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001513 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Welte2a139372009-02-22 21:14:55 +00001514 break;
1515 case GSM_MI_TYPE_IMEI:
1516 case GSM_MI_TYPE_IMEISV:
1517 /* no sim card... FIXME: what to do ? */
Holger Freyther79f4ae62009-06-02 03:25:04 +00001518 DEBUGPC(DMM, "unimplemented mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001519 break;
1520 default:
Holger Freyther79f4ae62009-06-02 03:25:04 +00001521 DEBUGPC(DMM, "unknown mobile identity type\n");
Harald Welte2a139372009-02-22 21:14:55 +00001522 break;
1523 }
1524
Holger Freyther4a49e772009-04-12 05:37:29 +00001525 if (subscr) {
1526 subscr_update(subscr, msg->trx->bts,
1527 GSM_SUBSCRIBER_UPDATE_DETACHED);
Harald Welte2a139372009-02-22 21:14:55 +00001528 DEBUGP(DMM, "Subscriber: %s\n",
1529 subscr->name ? subscr->name : subscr->imsi);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001530 subscr_put(subscr);
Holger Freyther4a49e772009-04-12 05:37:29 +00001531 } else
Harald Welte2a139372009-02-22 21:14:55 +00001532 DEBUGP(DMM, "Unknown Subscriber ?!?\n");
1533
Harald Welte2a139372009-02-22 21:14:55 +00001534 return 0;
1535}
1536
Harald Welted2a7f5a2009-06-05 20:08:20 +00001537static int gsm48_rx_mm_status(struct msgb *msg)
1538{
1539 struct gsm48_hdr *gh = msgb_l3(msg);
1540
1541 DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
1542
1543 return 0;
1544}
1545
Harald Weltebf5e8df2009-02-03 12:59:45 +00001546/* Receive a GSM 04.08 Mobility Management (MM) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001547static int gsm0408_rcv_mm(struct msgb *msg)
1548{
1549 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001550 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001551
1552 switch (gh->msg_type & 0xbf) {
1553 case GSM48_MT_MM_LOC_UPD_REQUEST:
Harald Weltea0368542009-06-27 02:58:43 +02001554 DEBUGP(DMM, "LOCATION UPDATING REQUEST: ");
Harald Welte231ad4f2008-12-27 11:15:38 +00001555 rc = mm_rx_loc_upd_req(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001556 break;
1557 case GSM48_MT_MM_ID_RESP:
Harald Welte231ad4f2008-12-27 11:15:38 +00001558 rc = mm_rx_id_resp(msg);
1559 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001560 case GSM48_MT_MM_CM_SERV_REQ:
Harald Welte4b634542008-12-27 01:55:51 +00001561 rc = gsm48_rx_mm_serv_req(msg);
1562 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001563 case GSM48_MT_MM_STATUS:
Harald Welted2a7f5a2009-06-05 20:08:20 +00001564 rc = gsm48_rx_mm_status(msg);
Harald Welte231ad4f2008-12-27 11:15:38 +00001565 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001566 case GSM48_MT_MM_TMSI_REALL_COMPL:
Harald Welte69b2af22009-01-06 19:47:00 +00001567 DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
1568 msg->lchan->subscr ?
1569 msg->lchan->subscr->imsi :
1570 "unknown subscriber");
1571 break;
Harald Welte231ad4f2008-12-27 11:15:38 +00001572 case GSM48_MT_MM_IMSI_DETACH_IND:
Harald Welte2a139372009-02-22 21:14:55 +00001573 rc = gsm48_rx_mm_imsi_detach_ind(msg);
1574 break;
1575 case GSM48_MT_MM_CM_REEST_REQ:
1576 DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
1577 break;
1578 case GSM48_MT_MM_AUTH_RESP:
1579 DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
Harald Welte52b1f982008-12-23 20:25:15 +00001580 break;
1581 default:
1582 fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
1583 gh->msg_type);
1584 break;
1585 }
1586
1587 return rc;
1588}
Harald Weltebf5e8df2009-02-03 12:59:45 +00001589
Harald Welte2d35ae62009-02-06 12:02:13 +00001590/* Receive a PAGING RESPONSE message from the MS */
1591static int gsm48_rr_rx_pag_resp(struct msgb *msg)
1592{
Harald Welte9176bd42009-07-23 18:46:00 +02001593 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Harald Welte2d35ae62009-02-06 12:02:13 +00001594 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte61548982009-02-22 21:26:29 +00001595 u_int8_t *classmark2_lv = gh->data + 1;
1596 u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
1597 u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
Harald Welte2d35ae62009-02-06 12:02:13 +00001598 char mi_string[MI_SIZE];
Harald Welte4bfdfe72009-06-10 23:11:52 +08001599 struct gsm_subscriber *subscr = NULL;
Harald Welte595ad7b2009-02-16 22:05:44 +00001600 struct paging_signal_data sig_data;
Harald Welte2d35ae62009-02-06 12:02:13 +00001601 int rc = 0;
1602
Harald Welte61548982009-02-22 21:26:29 +00001603 mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
Harald Welte2d35ae62009-02-06 12:02:13 +00001604 DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
1605 mi_type, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001606 switch (mi_type) {
1607 case GSM_MI_TYPE_TMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001608 subscr = subscr_get_by_tmsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001609 break;
1610 case GSM_MI_TYPE_IMSI:
Harald Welte9176bd42009-07-23 18:46:00 +02001611 subscr = subscr_get_by_imsi(bts->network, mi_string);
Harald Weltefe18d8f2009-02-22 21:14:24 +00001612 break;
1613 }
Harald Welte2d35ae62009-02-06 12:02:13 +00001614
1615 if (!subscr) {
1616 DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
Harald Welte09e38af2009-02-16 22:52:23 +00001617 /* FIXME: request id? close channel? */
Harald Welte2d35ae62009-02-06 12:02:13 +00001618 return -EINVAL;
1619 }
1620 DEBUGP(DRR, "<- Channel was requested by %s\n",
Harald Welte76042182009-08-08 16:03:15 +02001621 subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
Holger Freyther053e09d2009-02-14 22:51:06 +00001622
Harald Weltec2e302d2009-07-05 14:08:13 +02001623 subscr->equipment.classmark2_len = *classmark2_lv;
1624 memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
1625 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001626
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001627 if (!msg->lchan->subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001628 msg->lchan->subscr = subscr;
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001629 } else if (msg->lchan->subscr != subscr) {
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001630 DEBUGP(DRR, "<- Channel already owned by someone else?\n");
1631 subscr_put(subscr);
Holger Freytherc21cfbc2009-06-02 02:54:57 +00001632 return -EINVAL;
1633 } else {
1634 DEBUGP(DRR, "<- Channel already owned by us\n");
1635 subscr_put(subscr);
1636 subscr = msg->lchan->subscr;
Holger Freyther2fa4cb52009-02-14 23:53:15 +00001637 }
1638
Harald Welte595ad7b2009-02-16 22:05:44 +00001639 sig_data.subscr = subscr;
1640 sig_data.bts = msg->lchan->ts->trx->bts;
1641 sig_data.lchan = msg->lchan;
1642
1643 dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
Harald Weltebe143102009-06-10 11:21:55 +08001644
1645 /* Stop paging on the bts we received the paging response */
Harald Welte7ccf7782009-02-17 01:43:01 +00001646 paging_request_stop(msg->trx->bts, subscr, msg->lchan);
Harald Welte2d35ae62009-02-06 12:02:13 +00001647
Harald Welte7584aea2009-02-11 11:44:12 +00001648 /* FIXME: somehow signal the completion of the PAGING to
1649 * the entity that requested the paging */
1650
Harald Welte2d35ae62009-02-06 12:02:13 +00001651 return rc;
1652}
1653
Harald Weltef7c43522009-06-09 20:24:21 +00001654static int gsm48_rx_rr_classmark(struct msgb *msg)
1655{
1656 struct gsm48_hdr *gh = msgb_l3(msg);
1657 struct gsm_subscriber *subscr = msg->lchan->subscr;
1658 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1659 u_int8_t cm2_len, cm3_len = 0;
1660 u_int8_t *cm2, *cm3 = NULL;
1661
1662 DEBUGP(DRR, "CLASSMARK CHANGE ");
1663
1664 /* classmark 2 */
1665 cm2_len = gh->data[0];
1666 cm2 = &gh->data[1];
1667 DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
1668
1669 if (payload_len > cm2_len + 1) {
1670 /* we must have a classmark3 */
1671 if (gh->data[cm2_len+1] != 0x20) {
1672 DEBUGPC(DRR, "ERR CM3 TAG\n");
1673 return -EINVAL;
1674 }
1675 if (cm2_len > 3) {
1676 DEBUGPC(DRR, "CM2 too long!\n");
1677 return -EINVAL;
1678 }
1679
1680 cm3_len = gh->data[cm2_len+2];
1681 cm3 = &gh->data[cm2_len+3];
1682 if (cm3_len > 14) {
1683 DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
1684 return -EINVAL;
1685 }
1686 DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
1687 }
1688 if (subscr) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001689 subscr->equipment.classmark2_len = cm2_len;
1690 memcpy(subscr->equipment.classmark2, cm2, cm2_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001691 if (cm3) {
Harald Weltec2e302d2009-07-05 14:08:13 +02001692 subscr->equipment.classmark3_len = cm3_len;
1693 memcpy(subscr->equipment.classmark3, cm3, cm3_len);
Harald Weltef7c43522009-06-09 20:24:21 +00001694 }
Harald Weltec2e302d2009-07-05 14:08:13 +02001695 db_sync_equipment(&subscr->equipment);
Harald Weltef7c43522009-06-09 20:24:21 +00001696 }
1697
Harald Weltef7c43522009-06-09 20:24:21 +00001698 return 0;
1699}
1700
Harald Weltecf5b3592009-05-01 18:28:42 +00001701static int gsm48_rx_rr_status(struct msgb *msg)
1702{
1703 struct gsm48_hdr *gh = msgb_l3(msg);
1704
1705 DEBUGP(DRR, "STATUS rr_cause = %s\n",
1706 rr_cause_name(gh->data[0]));
1707
1708 return 0;
1709}
1710
Harald Weltef7c43522009-06-09 20:24:21 +00001711static int gsm48_rx_rr_meas_rep(struct msgb *msg)
1712{
1713 struct gsm48_hdr *gh = msgb_l3(msg);
1714 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
1715 static struct gsm_meas_rep meas_rep;
1716
Harald Welte10d0e672009-06-27 02:53:10 +02001717 DEBUGP(DMEAS, "MEASUREMENT REPORT ");
Harald Weltef7c43522009-06-09 20:24:21 +00001718 parse_meas_rep(&meas_rep, gh->data, payload_len);
1719 if (meas_rep.flags & MEAS_REP_F_DTX)
Harald Welte10d0e672009-06-27 02:53:10 +02001720 DEBUGPC(DMEAS, "DTX ");
Harald Weltef7c43522009-06-09 20:24:21 +00001721 if (meas_rep.flags & MEAS_REP_F_BA1)
Harald Welte10d0e672009-06-27 02:53:10 +02001722 DEBUGPC(DMEAS, "BA1 ");
Harald Weltef7c43522009-06-09 20:24:21 +00001723 if (!(meas_rep.flags & MEAS_REP_F_VALID))
Harald Welte10d0e672009-06-27 02:53:10 +02001724 DEBUGPC(DMEAS, "NOT VALID ");
Harald Weltef7c43522009-06-09 20:24:21 +00001725 else
Harald Welte10d0e672009-06-27 02:53:10 +02001726 DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
Harald Weltef7c43522009-06-09 20:24:21 +00001727 meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
1728 meas_rep.rxqual_sub);
1729
Harald Welte10d0e672009-06-27 02:53:10 +02001730 DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell);
Harald Weltef7c43522009-06-09 20:24:21 +00001731
1732 /* FIXME: put the results somwhere */
1733
1734 return 0;
1735}
1736
Harald Weltebf5e8df2009-02-03 12:59:45 +00001737/* Receive a GSM 04.08 Radio Resource (RR) message */
Harald Welte52b1f982008-12-23 20:25:15 +00001738static int gsm0408_rcv_rr(struct msgb *msg)
1739{
1740 struct gsm48_hdr *gh = msgb_l3(msg);
Harald Welte2d35ae62009-02-06 12:02:13 +00001741 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001742
1743 switch (gh->msg_type) {
1744 case GSM48_MT_RR_CLSM_CHG:
Harald Weltef7c43522009-06-09 20:24:21 +00001745 rc = gsm48_rx_rr_classmark(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001746 break;
Harald Weltefc977a82008-12-27 10:19:37 +00001747 case GSM48_MT_RR_GPRS_SUSP_REQ:
1748 DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
1749 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001750 case GSM48_MT_RR_PAG_RESP:
Harald Welte2d35ae62009-02-06 12:02:13 +00001751 rc = gsm48_rr_rx_pag_resp(msg);
1752 break;
Harald Welte7ccf7782009-02-17 01:43:01 +00001753 case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
1754 DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
Harald Welte13cac662009-07-29 12:10:35 +02001755 /* We've successfully modified the MS side of the channel,
1756 * now go on to modify the BTS side of the channel */
Harald Welte9943c5b2009-07-29 15:41:29 +02001757 msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
Harald Welte2c38aa82009-02-18 03:44:24 +00001758 rc = rsl_chan_mode_modify_req(msg->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00001759 break;
Harald Weltecf5b3592009-05-01 18:28:42 +00001760 case GSM48_MT_RR_STATUS:
1761 rc = gsm48_rx_rr_status(msg);
1762 break;
Harald Weltef7c43522009-06-09 20:24:21 +00001763 case GSM48_MT_RR_MEAS_REP:
1764 rc = gsm48_rx_rr_meas_rep(msg);
1765 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001766 default:
Harald Welte2d35ae62009-02-06 12:02:13 +00001767 fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001768 gh->msg_type);
1769 break;
1770 }
1771
Harald Welte2d35ae62009-02-06 12:02:13 +00001772 return rc;
Harald Welte52b1f982008-12-23 20:25:15 +00001773}
1774
Holger Freythere64a7a32009-02-06 21:55:37 +00001775/* 7.1.7 and 9.1.7 Channel release*/
1776int gsm48_send_rr_release(struct gsm_lchan *lchan)
1777{
1778 struct msgb *msg = gsm48_msgb_alloc();
1779 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1780 u_int8_t *cause;
1781
1782 msg->lchan = lchan;
1783 gh->proto_discr = GSM48_PDISC_RR;
1784 gh->msg_type = GSM48_MT_RR_CHAN_REL;
1785
1786 cause = msgb_put(msg, 1);
1787 cause[0] = GSM48_RR_CAUSE_NORMAL;
1788
1789 DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
1790 lchan->nr, lchan->type);
1791
Harald Welteae0f2362009-07-19 18:36:49 +02001792 /* Send actual release request to MS */
Harald Welte39e2ead2009-07-23 21:13:03 +02001793 gsm48_sendmsg(msg, NULL);
Harald Welte76042182009-08-08 16:03:15 +02001794 /* FIXME: Start Timer T3109 */
Harald Welteae0f2362009-07-19 18:36:49 +02001795
1796 /* Deactivate the SACCH on the BTS side */
1797 return rsl_deact_sacch(lchan);
Holger Freythere64a7a32009-02-06 21:55:37 +00001798}
1799
Harald Welte4bc90a12008-12-27 16:32:52 +00001800/* Call Control */
1801
Harald Welte7584aea2009-02-11 11:44:12 +00001802/* The entire call control code is written in accordance with Figure 7.10c
1803 * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
1804 * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
1805 * it for voice */
1806
Harald Welte4bfdfe72009-06-10 23:11:52 +08001807static void new_cc_state(struct gsm_trans *trans, int state)
1808{
1809 if (state > 31 || state < 0)
1810 return;
1811
1812 DEBUGP(DCC, "new state %s -> %s\n",
Harald Weltedcaf5652009-07-23 18:56:43 +02001813 cc_state_names[trans->cc.state], cc_state_names[state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001814
Harald Weltedcaf5652009-07-23 18:56:43 +02001815 trans->cc.state = state;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001816}
1817
1818static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
Harald Welte4bc90a12008-12-27 16:32:52 +00001819{
1820 struct msgb *msg = gsm48_msgb_alloc();
1821 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1822 u_int8_t *cause, *call_state;
1823
Harald Welte4bc90a12008-12-27 16:32:52 +00001824 gh->msg_type = GSM48_MT_CC_STATUS;
1825
1826 cause = msgb_put(msg, 3);
1827 cause[0] = 2;
1828 cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
1829 cause[2] = 0x80 | 30; /* response to status inquiry */
1830
1831 call_state = msgb_put(msg, 1);
1832 call_state[0] = 0xc0 | 0x00;
1833
Harald Welte39e2ead2009-07-23 21:13:03 +02001834 return gsm48_sendmsg(msg, trans);
Harald Welte4bc90a12008-12-27 16:32:52 +00001835}
1836
Harald Welte6f4b7532008-12-29 00:39:37 +00001837static int gsm48_tx_simple(struct gsm_lchan *lchan,
1838 u_int8_t pdisc, u_int8_t msg_type)
Harald Welte4bc90a12008-12-27 16:32:52 +00001839{
1840 struct msgb *msg = gsm48_msgb_alloc();
1841 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
1842
1843 msg->lchan = lchan;
1844
Harald Welte6f4b7532008-12-29 00:39:37 +00001845 gh->proto_discr = pdisc;
Harald Welte4bc90a12008-12-27 16:32:52 +00001846 gh->msg_type = msg_type;
1847
Harald Welte39e2ead2009-07-23 21:13:03 +02001848 return gsm48_sendmsg(msg, NULL);
Harald Welte4bc90a12008-12-27 16:32:52 +00001849}
1850
Harald Welte4bfdfe72009-06-10 23:11:52 +08001851static void gsm48_stop_cc_timer(struct gsm_trans *trans)
1852{
Harald Weltedcaf5652009-07-23 18:56:43 +02001853 if (bsc_timer_pending(&trans->cc.timer)) {
1854 DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
1855 bsc_del_timer(&trans->cc.timer);
1856 trans->cc.Tcurrent = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001857 }
1858}
1859
1860static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
1861 int msg_type, struct gsm_mncc *mncc)
1862{
1863 struct msgb *msg;
1864
1865 if (trans)
1866 if (trans->lchan)
Harald Welte6f5aee02009-07-23 21:21:14 +02001867 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08001868 "Sending '%s' to MNCC.\n",
1869 trans->lchan->ts->trx->bts->nr,
1870 trans->lchan->ts->trx->nr,
1871 trans->lchan->ts->nr, trans->transaction_id,
1872 (trans->subscr)?(trans->subscr->extension):"-",
1873 get_mncc_name(msg_type));
1874 else
1875 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
1876 "Sending '%s' to MNCC.\n",
1877 (trans->subscr)?(trans->subscr->extension):"-",
1878 get_mncc_name(msg_type));
1879 else
1880 DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
1881 "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
1882
1883 mncc->msg_type = msg_type;
1884
Harald Welte966636f2009-06-26 19:39:35 +02001885 msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
Harald Welte4bfdfe72009-06-10 23:11:52 +08001886 if (!msg)
1887 return -ENOMEM;
1888 memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
1889 msgb_enqueue(&net->upqueue, msg);
1890
1891 return 0;
1892}
1893
1894int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
1895 u_int32_t callref, int location, int value)
1896{
1897 struct gsm_mncc rel;
1898
Harald Welte92f70c52009-06-12 01:54:08 +08001899 memset(&rel, 0, sizeof(rel));
Harald Welte4bfdfe72009-06-10 23:11:52 +08001900 rel.callref = callref;
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001901 mncc_set_cause(&rel, location, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001902 return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
1903}
1904
Harald Weltedcaf5652009-07-23 18:56:43 +02001905/* Call Control Specific transaction release.
1906 * gets called by trans_free, DO NOT CALL YOURSELF! */
1907void _gsm48_cc_trans_free(struct gsm_trans *trans)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001908{
Harald Welte4bfdfe72009-06-10 23:11:52 +08001909 gsm48_stop_cc_timer(trans);
1910
1911 /* send release to L4, if callref still exists */
1912 if (trans->callref) {
1913 /* Ressource unavailable */
Harald Welte596fed42009-07-23 19:06:52 +02001914 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001915 GSM48_CAUSE_LOC_PRN_S_LU,
1916 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001917 }
Harald Weltedcaf5652009-07-23 18:56:43 +02001918 if (trans->cc.state != GSM_CSTATE_NULL)
Harald Welte4bfdfe72009-06-10 23:11:52 +08001919 new_cc_state(trans, GSM_CSTATE_NULL);
Harald Weltedcaf5652009-07-23 18:56:43 +02001920 if (trans->lchan)
1921 trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001922}
1923
1924static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
1925
Harald Welte09e38af2009-02-16 22:52:23 +00001926/* call-back from paging the B-end of the connection */
1927static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
Harald Welte7ccf7782009-02-17 01:43:01 +00001928 struct msgb *msg, void *_lchan, void *param)
Harald Welte09e38af2009-02-16 22:52:23 +00001929{
Harald Welte7ccf7782009-02-17 01:43:01 +00001930 struct gsm_lchan *lchan = _lchan;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001931 struct gsm_subscriber *subscr = param;
1932 struct gsm_trans *transt, *tmp;
1933 struct gsm_network *net;
Harald Weltec05677b2009-06-26 20:17:06 +02001934
Harald Welte09e38af2009-02-16 22:52:23 +00001935 if (hooknum != GSM_HOOK_RR_PAGING)
1936 return -EINVAL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08001937
1938 if (!subscr)
1939 return -EINVAL;
1940 net = subscr->net;
1941 if (!net) {
1942 DEBUGP(DCC, "Error Network not set!\n");
1943 return -EINVAL;
Harald Welte5a065df2009-02-22 21:13:18 +00001944 }
Harald Welte7584aea2009-02-11 11:44:12 +00001945
Harald Welte4bfdfe72009-06-10 23:11:52 +08001946 /* check all tranactions (without lchan) for subscriber */
1947 llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
1948 if (transt->subscr != subscr || transt->lchan)
1949 continue;
1950 switch (event) {
1951 case GSM_PAGING_SUCCEEDED:
1952 if (!lchan) // paranoid
1953 break;
1954 DEBUGP(DCC, "Paging subscr %s succeeded!\n",
1955 subscr->extension);
1956 /* Assign lchan */
1957 if (!transt->lchan) {
1958 transt->lchan = lchan;
1959 use_lchan(lchan);
1960 }
1961 /* send SETUP request to called party */
Harald Weltedcaf5652009-07-23 18:56:43 +02001962 gsm48_cc_tx_setup(transt, &transt->cc.msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001963 break;
1964 case GSM_PAGING_EXPIRED:
1965 DEBUGP(DCC, "Paging subscr %s expired!\n",
1966 subscr->extension);
1967 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02001968 mncc_release_ind(transt->subscr->net, transt,
1969 transt->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08001970 GSM48_CAUSE_LOC_PRN_S_LU,
1971 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001972 transt->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02001973 trans_free(transt);
Harald Welte4bfdfe72009-06-10 23:11:52 +08001974 break;
1975 }
1976 }
Harald Welte09e38af2009-02-16 22:52:23 +00001977 return 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00001978}
Harald Welte7584aea2009-02-11 11:44:12 +00001979
Harald Welte805f6442009-07-28 18:25:29 +02001980/* some other part of the code sends us a signal */
1981static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
1982 void *handler_data, void *signal_data)
1983{
1984 struct gsm_lchan *lchan = signal_data;
1985 struct gsm_bts_trx_ts *ts;
1986 int rc;
1987
1988 if (subsys != SS_ABISIP)
1989 return 0;
1990
1991 /* in case we use direct BTS-to-BTS RTP */
1992 if (ipacc_rtp_direct)
1993 return 0;
1994
1995 ts = lchan->ts;
1996
1997 switch (signal) {
1998 case S_ABISIP_BIND_ACK:
1999 /* the BTS has successfully bound a TCH to a local ip/port,
2000 * which means we can connect our UDP socket to it */
2001 if (ts->abis_ip.rtp_socket) {
2002 rtp_socket_free(ts->abis_ip.rtp_socket);
2003 ts->abis_ip.rtp_socket = NULL;
2004 }
2005
2006 ts->abis_ip.rtp_socket = rtp_socket_create();
2007 if (!ts->abis_ip.rtp_socket)
2008 goto out_err;
2009
2010 rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
2011 ts->abis_ip.bound_ip,
2012 ts->abis_ip.bound_port);
2013 if (rc < 0)
2014 goto out_err;
2015 break;
2016 case S_ABISIP_DISC_IND:
2017 /* the BTS tells us a RTP stream has been disconnected */
2018 if (ts->abis_ip.rtp_socket) {
2019 rtp_socket_free(ts->abis_ip.rtp_socket);
2020 ts->abis_ip.rtp_socket = NULL;
2021 }
2022 break;
2023 }
2024
2025 return 0;
2026out_err:
2027 /* FIXME: do something */
2028 return 0;
2029}
2030
2031/* bind rtp proxy to local IP/port and tell BTS to connect to it */
2032static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
2033{
2034 struct gsm_bts_trx_ts *ts = lchan->ts;
2035 struct rtp_socket *rs = ts->abis_ip.rtp_socket;
2036 int rc;
2037
2038 rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
2039 ntohs(rs->rtp.sin_local.sin_port),
2040 ts->abis_ip.conn_id,
2041 /* FIXME: use RTP payload of bound socket, not BTS*/
2042 ts->abis_ip.rtp_payload2);
2043
2044 return rc;
2045}
2046
Harald Welte49f48b82009-02-17 15:29:33 +00002047/* map two ipaccess RTP streams onto each other */
Harald Welte11fa29c2009-02-19 17:24:39 +00002048static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
Harald Welte49f48b82009-02-17 15:29:33 +00002049{
Harald Welte11fa29c2009-02-19 17:24:39 +00002050 struct gsm_bts *bts = lchan->ts->trx->bts;
2051 struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
Harald Welte49f48b82009-02-17 15:29:33 +00002052 struct gsm_bts_trx_ts *ts;
Harald Welte805f6442009-07-28 18:25:29 +02002053 int rc;
Harald Welte49f48b82009-02-17 15:29:33 +00002054
Harald Welte11fa29c2009-02-19 17:24:39 +00002055 DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
2056 bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
2057 remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
2058
2059 if (bts->type != remote_bts->type) {
2060 DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
2061 return -EINVAL;
2062 }
Harald Welte49f48b82009-02-17 15:29:33 +00002063
Harald Welte11fa29c2009-02-19 17:24:39 +00002064 switch (bts->type) {
2065 case GSM_BTS_TYPE_NANOBTS_900:
2066 case GSM_BTS_TYPE_NANOBTS_1800:
Harald Welte805f6442009-07-28 18:25:29 +02002067 if (!ipacc_rtp_direct) {
2068 /* connect the TCH's to our RTP proxy */
2069 rc = ipacc_connect_proxy_bind(lchan);
2070 if (rc < 0)
2071 return rc;
2072 rc = ipacc_connect_proxy_bind(remote_lchan);
2073
2074 /* connect them with each other */
2075 rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
2076 remote_lchan->ts->abis_ip.rtp_socket);
2077 } else {
2078 /* directly connect TCH RTP streams to each other */
2079 ts = remote_lchan->ts;
2080 rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
2081 ts->abis_ip.bound_port,
2082 lchan->ts->abis_ip.conn_id,
2083 ts->abis_ip.rtp_payload2);
2084 if (rc < 0)
2085 return rc;
2086 ts = lchan->ts;
2087 rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
2088 ts->abis_ip.bound_port,
2089 remote_lchan->ts->abis_ip.conn_id,
2090 ts->abis_ip.rtp_payload2);
2091 }
Harald Welte11fa29c2009-02-19 17:24:39 +00002092 break;
2093 case GSM_BTS_TYPE_BS11:
2094 trau_mux_map_lchan(lchan, remote_lchan);
2095 break;
2096 default:
2097 DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
Harald Welte805f6442009-07-28 18:25:29 +02002098 rc = -EINVAL;
Harald Welte11fa29c2009-02-19 17:24:39 +00002099 break;
2100 }
Harald Welte49f48b82009-02-17 15:29:33 +00002101
2102 return 0;
2103}
2104
Harald Welte4bfdfe72009-06-10 23:11:52 +08002105/* bridge channels of two transactions */
2106static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
Harald Welte7ccf7782009-02-17 01:43:01 +00002107{
Harald Weltedcaf5652009-07-23 18:56:43 +02002108 struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
2109 struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
Harald Welte7ccf7782009-02-17 01:43:01 +00002110
Harald Welte4bfdfe72009-06-10 23:11:52 +08002111 if (!trans1 || !trans2)
Harald Welte7ccf7782009-02-17 01:43:01 +00002112 return -EIO;
2113
Harald Welte4bfdfe72009-06-10 23:11:52 +08002114 if (!trans1->lchan || !trans2->lchan)
2115 return -EIO;
2116
2117 /* through-connect channel */
2118 return tch_map(trans1->lchan, trans2->lchan);
Harald Welte7ccf7782009-02-17 01:43:01 +00002119}
2120
Harald Welte4bfdfe72009-06-10 23:11:52 +08002121/* enable receive of channels to upqueue */
2122static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
2123{
2124 struct gsm_trans *trans;
Harald Welte7ccf7782009-02-17 01:43:01 +00002125
Harald Welte4bfdfe72009-06-10 23:11:52 +08002126 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002127 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002128 if (!trans)
2129 return -EIO;
2130 if (!trans->lchan)
2131 return 0;
2132
2133 // todo IPACCESS
2134 if (enable)
2135 return trau_recv_lchan(trans->lchan, data->callref);
2136 return trau_mux_unmap(NULL, data->callref);
2137}
2138
2139/* send a frame to channel */
2140static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
2141{
2142 struct gsm_trans *trans;
2143
2144 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02002145 trans = trans_find_by_callref(net, frame->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002146 if (!trans)
2147 return -EIO;
2148 if (!trans->lchan)
2149 return 0;
2150 if (trans->lchan->type != GSM_LCHAN_TCH_F &&
2151 trans->lchan->type != GSM_LCHAN_TCH_H)
2152 return 0;
2153
2154 // todo IPACCESS
2155 return trau_send_lchan(trans->lchan,
2156 (struct decoded_trau_frame *)frame->data);
2157}
2158
2159
2160static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
2161{
2162 DEBUGP(DCC, "-> STATUS ENQ\n");
2163 return gsm48_cc_tx_status(trans, msg);
2164}
2165
2166static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
2167static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
2168
2169static void gsm48_cc_timeout(void *arg)
2170{
2171 struct gsm_trans *trans = arg;
2172 int disconnect = 0, release = 0;
Harald Weltec66b71c2009-06-11 14:23:20 +08002173 int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
2174 int mo_location = GSM48_CAUSE_LOC_USER;
2175 int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
2176 int l4_location = GSM48_CAUSE_LOC_PRN_S_LU;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002177 struct gsm_mncc mo_rel, l4_rel;
2178
2179 memset(&mo_rel, 0, sizeof(struct gsm_mncc));
2180 mo_rel.callref = trans->callref;
2181 memset(&l4_rel, 0, sizeof(struct gsm_mncc));
2182 l4_rel.callref = trans->callref;
2183
Harald Weltedcaf5652009-07-23 18:56:43 +02002184 switch(trans->cc.Tcurrent) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002185 case 0x303:
2186 release = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002187 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002188 break;
2189 case 0x310:
2190 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002191 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002192 break;
2193 case 0x313:
2194 disconnect = 1;
2195 /* unknown, did not find it in the specs */
2196 break;
2197 case 0x301:
2198 disconnect = 1;
Harald Weltec66b71c2009-06-11 14:23:20 +08002199 l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002200 break;
2201 case 0x308:
Harald Weltedcaf5652009-07-23 18:56:43 +02002202 if (!trans->cc.T308_second) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002203 /* restart T308 a second time */
Harald Weltedcaf5652009-07-23 18:56:43 +02002204 gsm48_cc_tx_release(trans, &trans->cc.msg);
2205 trans->cc.T308_second = 1;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002206 break; /* stay in release state */
2207 }
Harald Weltedcaf5652009-07-23 18:56:43 +02002208 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002209 return;
2210// release = 1;
2211// l4_cause = 14;
2212// break;
2213 case 0x306:
2214 release = 1;
Harald Weltedcaf5652009-07-23 18:56:43 +02002215 mo_cause = trans->cc.msg.cause.value;
2216 mo_location = trans->cc.msg.cause.location;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002217 break;
2218 case 0x323:
2219 disconnect = 1;
2220 break;
2221 default:
2222 release = 1;
2223 }
2224
2225 if (release && trans->callref) {
2226 /* process release towards layer 4 */
Harald Welte596fed42009-07-23 19:06:52 +02002227 mncc_release_ind(trans->subscr->net, trans, trans->callref,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002228 l4_location, l4_cause);
2229 trans->callref = 0;
2230 }
2231
2232 if (disconnect && trans->callref) {
2233 /* process disconnect towards layer 4 */
2234 mncc_set_cause(&l4_rel, l4_location, l4_cause);
Harald Welte596fed42009-07-23 19:06:52 +02002235 mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002236 }
2237
2238 /* process disconnect towards mobile station */
2239 if (disconnect || release) {
2240 mncc_set_cause(&mo_rel, mo_location, mo_cause);
Harald Weltedcaf5652009-07-23 18:56:43 +02002241 mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
2242 mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
2243 mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
Harald Welte4bfdfe72009-06-10 23:11:52 +08002244 mo_rel.cause.diag_len = 3;
2245
2246 if (disconnect)
2247 gsm48_cc_tx_disconnect(trans, &mo_rel);
2248 if (release)
2249 gsm48_cc_tx_release(trans, &mo_rel);
2250 }
2251
2252}
2253
2254static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
2255 int sec, int micro)
2256{
2257 DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
Harald Weltedcaf5652009-07-23 18:56:43 +02002258 trans->cc.timer.cb = gsm48_cc_timeout;
2259 trans->cc.timer.data = trans;
2260 bsc_schedule_timer(&trans->cc.timer, sec, micro);
2261 trans->cc.Tcurrent = current;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002262}
2263
2264static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
2265{
2266 struct gsm48_hdr *gh = msgb_l3(msg);
2267 u_int8_t msg_type = gh->msg_type & 0xbf;
2268 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2269 struct tlv_parsed tp;
2270 struct gsm_mncc setup;
2271
2272 memset(&setup, 0, sizeof(struct gsm_mncc));
2273 setup.callref = trans->callref;
2274 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2275 /* emergency setup is identified by msg_type */
2276 if (msg_type == GSM48_MT_CC_EMERG_SETUP)
2277 setup.emergency = 1;
2278
2279 /* use subscriber as calling party number */
2280 if (trans->subscr) {
2281 setup.fields |= MNCC_F_CALLING;
2282 strncpy(setup.calling.number, trans->subscr->extension,
2283 sizeof(setup.calling.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002284 strncpy(setup.imsi, trans->subscr->imsi,
2285 sizeof(setup.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002286 }
2287 /* bearer capability */
2288 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2289 setup.fields |= MNCC_F_BEARER_CAP;
2290 decode_bearer_cap(&setup.bearer_cap,
2291 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2292 }
2293 /* facility */
2294 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2295 setup.fields |= MNCC_F_FACILITY;
2296 decode_facility(&setup.facility,
2297 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2298 }
2299 /* called party bcd number */
2300 if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
2301 setup.fields |= MNCC_F_CALLED;
2302 decode_called(&setup.called,
2303 TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
2304 }
2305 /* user-user */
2306 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2307 setup.fields |= MNCC_F_USERUSER;
2308 decode_useruser(&setup.useruser,
2309 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2310 }
2311 /* ss-version */
2312 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2313 setup.fields |= MNCC_F_SSVERSION;
2314 decode_ssversion(&setup.ssversion,
2315 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2316 }
2317 /* CLIR suppression */
2318 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
2319 setup.clir.sup = 1;
2320 /* CLIR invocation */
2321 if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
2322 setup.clir.inv = 1;
2323 /* cc cap */
2324 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2325 setup.fields |= MNCC_F_CCCAP;
2326 decode_cccap(&setup.cccap,
2327 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2328 }
2329
Harald Welte4bfdfe72009-06-10 23:11:52 +08002330 new_cc_state(trans, GSM_CSTATE_INITIATED);
2331
2332 /* indicate setup to MNCC */
Harald Welte596fed42009-07-23 19:06:52 +02002333 mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002334
Harald Welte13cac662009-07-29 12:10:35 +02002335 /* MNCC code will modify the channel asynchronously, we should
2336 * ipaccess-bind only after the modification has been made to the
2337 * lchan->tch_mode */
Harald Welte4bfdfe72009-06-10 23:11:52 +08002338 return 0;
2339}
2340
2341static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
Harald Welte65e74cc2008-12-29 01:55:35 +00002342{
2343 struct msgb *msg = gsm48_msgb_alloc();
2344 struct gsm48_hdr *gh;
Harald Welte4bfdfe72009-06-10 23:11:52 +08002345 struct gsm_mncc *setup = arg;
Harald Welte78283ef2009-07-23 21:36:44 +02002346 int rc, trans_id;
Harald Welte65e74cc2008-12-29 01:55:35 +00002347
Harald Welte7ccf7782009-02-17 01:43:01 +00002348 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Harald Welte65e74cc2008-12-29 01:55:35 +00002349
Harald Welte4bfdfe72009-06-10 23:11:52 +08002350 /* transaction id must not be assigned */
2351 if (trans->transaction_id != 0xff) { /* unasssigned */
2352 DEBUGP(DCC, "TX Setup with assigned transaction. "
2353 "This is not allowed!\n");
2354 /* Temporarily out of order */
Harald Welte596fed42009-07-23 19:06:52 +02002355 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002356 GSM48_CAUSE_LOC_PRN_S_LU,
2357 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002358 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002359 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002360 return rc;
2361 }
2362
2363 /* Get free transaction_id */
Harald Welte78283ef2009-07-23 21:36:44 +02002364 trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0);
2365 if (trans_id < 0) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002366 /* no free transaction ID */
Harald Welte596fed42009-07-23 19:06:52 +02002367 rc = mncc_release_ind(trans->subscr->net, trans, trans->callref,
Andreas Eversberg7563ac92009-06-14 22:14:12 +08002368 GSM48_CAUSE_LOC_PRN_S_LU,
2369 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002370 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002371 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002372 return rc;
2373 }
Harald Welte78283ef2009-07-23 21:36:44 +02002374 trans->transaction_id = trans_id;
Harald Welte49f48b82009-02-17 15:29:33 +00002375
Harald Welte65e74cc2008-12-29 01:55:35 +00002376 gh->msg_type = GSM48_MT_CC_SETUP;
Harald Welte09e38af2009-02-16 22:52:23 +00002377
Harald Welte4bfdfe72009-06-10 23:11:52 +08002378 gsm48_start_cc_timer(trans, 0x303, GSM48_T303);
Harald Welte65e74cc2008-12-29 01:55:35 +00002379
Harald Welte4bfdfe72009-06-10 23:11:52 +08002380 /* bearer capability */
2381 if (setup->fields & MNCC_F_BEARER_CAP)
2382 encode_bearer_cap(msg, 0, &setup->bearer_cap);
2383 /* facility */
2384 if (setup->fields & MNCC_F_FACILITY)
2385 encode_facility(msg, 0, &setup->facility);
2386 /* progress */
2387 if (setup->fields & MNCC_F_PROGRESS)
2388 encode_progress(msg, 0, &setup->progress);
2389 /* calling party BCD number */
2390 if (setup->fields & MNCC_F_CALLING)
2391 encode_calling(msg, &setup->calling);
2392 /* called party BCD number */
2393 if (setup->fields & MNCC_F_CALLED)
2394 encode_called(msg, &setup->called);
2395 /* user-user */
2396 if (setup->fields & MNCC_F_USERUSER)
2397 encode_useruser(msg, 0, &setup->useruser);
2398 /* redirecting party BCD number */
2399 if (setup->fields & MNCC_F_REDIRECTING)
2400 encode_redirecting(msg, &setup->redirecting);
2401 /* signal */
2402 if (setup->fields & MNCC_F_SIGNAL)
2403 encode_signal(msg, setup->signal);
2404
2405 new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
Harald Welte65e74cc2008-12-29 01:55:35 +00002406
Harald Welte39e2ead2009-07-23 21:13:03 +02002407 return gsm48_sendmsg(msg, trans);
Harald Welte65e74cc2008-12-29 01:55:35 +00002408}
2409
Harald Welte4bfdfe72009-06-10 23:11:52 +08002410static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
2411{
2412 struct gsm48_hdr *gh = msgb_l3(msg);
2413 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2414 struct tlv_parsed tp;
2415 struct gsm_mncc call_conf;
2416
2417 gsm48_stop_cc_timer(trans);
2418 gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
2419
2420 memset(&call_conf, 0, sizeof(struct gsm_mncc));
2421 call_conf.callref = trans->callref;
2422 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2423#if 0
2424 /* repeat */
2425 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
2426 call_conf.repeat = 1;
2427 if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
2428 call_conf.repeat = 2;
2429#endif
2430 /* bearer capability */
2431 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
2432 call_conf.fields |= MNCC_F_BEARER_CAP;
2433 decode_bearer_cap(&call_conf.bearer_cap,
2434 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
2435 }
2436 /* cause */
2437 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2438 call_conf.fields |= MNCC_F_CAUSE;
2439 decode_cause(&call_conf.cause,
2440 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2441 }
2442 /* cc cap */
2443 if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
2444 call_conf.fields |= MNCC_F_CCCAP;
2445 decode_cccap(&call_conf.cccap,
2446 TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
2447 }
2448
2449 new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
2450
Harald Welte596fed42009-07-23 19:06:52 +02002451 return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND,
2452 &call_conf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002453}
2454
2455static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
2456{
2457 struct gsm_mncc *proceeding = arg;
2458 struct msgb *msg = gsm48_msgb_alloc();
2459 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2460
Harald Welte4bfdfe72009-06-10 23:11:52 +08002461 gh->msg_type = GSM48_MT_CC_CALL_PROC;
2462
2463 new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
2464
2465 /* bearer capability */
2466 if (proceeding->fields & MNCC_F_BEARER_CAP)
2467 encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
2468 /* facility */
2469 if (proceeding->fields & MNCC_F_FACILITY)
2470 encode_facility(msg, 0, &proceeding->facility);
2471 /* progress */
2472 if (proceeding->fields & MNCC_F_PROGRESS)
2473 encode_progress(msg, 0, &proceeding->progress);
2474
Harald Welte39e2ead2009-07-23 21:13:03 +02002475 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002476}
2477
2478static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
2479{
2480 struct gsm48_hdr *gh = msgb_l3(msg);
2481 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2482 struct tlv_parsed tp;
2483 struct gsm_mncc alerting;
2484
2485 gsm48_stop_cc_timer(trans);
2486 gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
2487
2488 memset(&alerting, 0, sizeof(struct gsm_mncc));
2489 alerting.callref = trans->callref;
2490 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2491 /* facility */
2492 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2493 alerting.fields |= MNCC_F_FACILITY;
2494 decode_facility(&alerting.facility,
2495 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2496 }
2497
2498 /* progress */
2499 if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
2500 alerting.fields |= MNCC_F_PROGRESS;
2501 decode_progress(&alerting.progress,
2502 TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
2503 }
2504 /* ss-version */
2505 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2506 alerting.fields |= MNCC_F_SSVERSION;
2507 decode_ssversion(&alerting.ssversion,
2508 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2509 }
2510
2511 new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
2512
Harald Welte596fed42009-07-23 19:06:52 +02002513 return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND,
2514 &alerting);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002515}
2516
2517static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
2518{
2519 struct gsm_mncc *alerting = arg;
2520 struct msgb *msg = gsm48_msgb_alloc();
2521 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2522
Harald Welte4bfdfe72009-06-10 23:11:52 +08002523 gh->msg_type = GSM48_MT_CC_ALERTING;
2524
2525 /* facility */
2526 if (alerting->fields & MNCC_F_FACILITY)
2527 encode_facility(msg, 0, &alerting->facility);
2528 /* progress */
2529 if (alerting->fields & MNCC_F_PROGRESS)
2530 encode_progress(msg, 0, &alerting->progress);
2531 /* user-user */
2532 if (alerting->fields & MNCC_F_USERUSER)
2533 encode_useruser(msg, 0, &alerting->useruser);
2534
2535 new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
2536
Harald Welte39e2ead2009-07-23 21:13:03 +02002537 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002538}
2539
2540static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
2541{
2542 struct gsm_mncc *progress = arg;
2543 struct msgb *msg = gsm48_msgb_alloc();
2544 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2545
Harald Welte4bfdfe72009-06-10 23:11:52 +08002546 gh->msg_type = GSM48_MT_CC_PROGRESS;
2547
2548 /* progress */
2549 encode_progress(msg, 1, &progress->progress);
2550 /* user-user */
2551 if (progress->fields & MNCC_F_USERUSER)
2552 encode_useruser(msg, 0, &progress->useruser);
2553
Harald Welte39e2ead2009-07-23 21:13:03 +02002554 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002555}
2556
2557static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
2558{
2559 struct gsm_mncc *connect = arg;
2560 struct msgb *msg = gsm48_msgb_alloc();
2561 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2562
Harald Welte4bfdfe72009-06-10 23:11:52 +08002563 gh->msg_type = GSM48_MT_CC_CONNECT;
2564
2565 gsm48_stop_cc_timer(trans);
2566 gsm48_start_cc_timer(trans, 0x313, GSM48_T313);
2567
2568 /* facility */
2569 if (connect->fields & MNCC_F_FACILITY)
2570 encode_facility(msg, 0, &connect->facility);
2571 /* progress */
2572 if (connect->fields & MNCC_F_PROGRESS)
2573 encode_progress(msg, 0, &connect->progress);
2574 /* connected number */
2575 if (connect->fields & MNCC_F_CONNECTED)
2576 encode_connected(msg, &connect->connected);
2577 /* user-user */
2578 if (connect->fields & MNCC_F_USERUSER)
2579 encode_useruser(msg, 0, &connect->useruser);
2580
2581 new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
2582
Harald Welte39e2ead2009-07-23 21:13:03 +02002583 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002584}
2585
2586static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
2587{
2588 struct gsm48_hdr *gh = msgb_l3(msg);
2589 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2590 struct tlv_parsed tp;
2591 struct gsm_mncc connect;
2592
2593 gsm48_stop_cc_timer(trans);
2594
2595 memset(&connect, 0, sizeof(struct gsm_mncc));
2596 connect.callref = trans->callref;
2597 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2598 /* use subscriber as connected party number */
2599 if (trans->subscr) {
2600 connect.fields |= MNCC_F_CONNECTED;
2601 strncpy(connect.connected.number, trans->subscr->extension,
2602 sizeof(connect.connected.number)-1);
Andreas Eversbergc079be42009-06-15 23:22:09 +02002603 strncpy(connect.imsi, trans->subscr->imsi,
2604 sizeof(connect.imsi)-1);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002605 }
2606 /* facility */
2607 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2608 connect.fields |= MNCC_F_FACILITY;
2609 decode_facility(&connect.facility,
2610 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2611 }
2612 /* user-user */
2613 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2614 connect.fields |= MNCC_F_USERUSER;
2615 decode_useruser(&connect.useruser,
2616 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2617 }
2618 /* ss-version */
2619 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2620 connect.fields |= MNCC_F_SSVERSION;
2621 decode_ssversion(&connect.ssversion,
2622 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2623 }
2624
2625 new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
2626
Harald Welte596fed42009-07-23 19:06:52 +02002627 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002628}
2629
2630
2631static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
2632{
2633 struct gsm_mncc connect_ack;
2634
2635 gsm48_stop_cc_timer(trans);
2636
2637 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2638
2639 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
2640 connect_ack.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002641 return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002642 &connect_ack);
2643}
2644
2645static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
2646{
2647 struct msgb *msg = gsm48_msgb_alloc();
2648 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2649
Harald Welte4bfdfe72009-06-10 23:11:52 +08002650 gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
2651
2652 new_cc_state(trans, GSM_CSTATE_ACTIVE);
2653
Harald Welte39e2ead2009-07-23 21:13:03 +02002654 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002655}
2656
2657static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
2658{
2659 struct gsm48_hdr *gh = msgb_l3(msg);
2660 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2661 struct tlv_parsed tp;
2662 struct gsm_mncc disc;
2663
2664 gsm48_stop_cc_timer(trans);
2665
2666 new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
2667
2668 memset(&disc, 0, sizeof(struct gsm_mncc));
2669 disc.callref = trans->callref;
2670 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
2671 /* cause */
2672 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2673 disc.fields |= MNCC_F_CAUSE;
2674 decode_cause(&disc.cause,
2675 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2676 }
2677 /* facility */
2678 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2679 disc.fields |= MNCC_F_FACILITY;
2680 decode_facility(&disc.facility,
2681 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2682 }
2683 /* user-user */
2684 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2685 disc.fields |= MNCC_F_USERUSER;
2686 decode_useruser(&disc.useruser,
2687 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2688 }
2689 /* ss-version */
2690 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2691 disc.fields |= MNCC_F_SSVERSION;
2692 decode_ssversion(&disc.ssversion,
2693 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2694 }
2695
Harald Welte596fed42009-07-23 19:06:52 +02002696 return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002697
2698}
2699
Harald Weltec66b71c2009-06-11 14:23:20 +08002700static struct gsm_mncc_cause default_cause = {
2701 .location = GSM48_CAUSE_LOC_PRN_S_LU,
2702 .coding = 0,
2703 .rec = 0,
2704 .rec_val = 0,
2705 .value = GSM48_CC_CAUSE_NORMAL_UNSPEC,
2706 .diag_len = 0,
2707 .diag = { 0 },
2708};
Harald Welte4bfdfe72009-06-10 23:11:52 +08002709
2710static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
2711{
2712 struct gsm_mncc *disc = arg;
2713 struct msgb *msg = gsm48_msgb_alloc();
2714 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2715
Harald Welte4bfdfe72009-06-10 23:11:52 +08002716 gh->msg_type = GSM48_MT_CC_DISCONNECT;
2717
2718 gsm48_stop_cc_timer(trans);
2719 gsm48_start_cc_timer(trans, 0x306, GSM48_T306);
2720
2721 /* cause */
2722 if (disc->fields & MNCC_F_CAUSE)
2723 encode_cause(msg, 1, &disc->cause);
2724 else
2725 encode_cause(msg, 1, &default_cause);
2726
2727 /* facility */
2728 if (disc->fields & MNCC_F_FACILITY)
2729 encode_facility(msg, 0, &disc->facility);
2730 /* progress */
2731 if (disc->fields & MNCC_F_PROGRESS)
2732 encode_progress(msg, 0, &disc->progress);
2733 /* user-user */
2734 if (disc->fields & MNCC_F_USERUSER)
2735 encode_useruser(msg, 0, &disc->useruser);
2736
2737 /* store disconnect cause for T306 expiry */
Harald Weltedcaf5652009-07-23 18:56:43 +02002738 memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002739
2740 new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
2741
Harald Welte39e2ead2009-07-23 21:13:03 +02002742 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002743}
2744
2745static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
2746{
2747 struct gsm48_hdr *gh = msgb_l3(msg);
2748 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2749 struct tlv_parsed tp;
2750 struct gsm_mncc rel;
2751 int rc;
2752
2753 gsm48_stop_cc_timer(trans);
2754
2755 memset(&rel, 0, sizeof(struct gsm_mncc));
2756 rel.callref = trans->callref;
2757 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2758 /* cause */
2759 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2760 rel.fields |= MNCC_F_CAUSE;
2761 decode_cause(&rel.cause,
2762 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2763 }
2764 /* facility */
2765 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2766 rel.fields |= MNCC_F_FACILITY;
2767 decode_facility(&rel.facility,
2768 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2769 }
2770 /* user-user */
2771 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2772 rel.fields |= MNCC_F_USERUSER;
2773 decode_useruser(&rel.useruser,
2774 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2775 }
2776 /* ss-version */
2777 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2778 rel.fields |= MNCC_F_SSVERSION;
2779 decode_ssversion(&rel.ssversion,
2780 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2781 }
2782
Harald Weltedcaf5652009-07-23 18:56:43 +02002783 if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002784 /* release collision 5.4.5 */
Harald Welte596fed42009-07-23 19:06:52 +02002785 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002786 } else {
Harald Welte596fed42009-07-23 19:06:52 +02002787 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02002788 GSM48_PDISC_CC | (trans->transaction_id << 4),
Harald Welte596fed42009-07-23 19:06:52 +02002789 GSM48_MT_CC_RELEASE_COMPL);
2790 rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002791 }
2792
2793 new_cc_state(trans, GSM_CSTATE_NULL);
2794
2795 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002796 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002797
2798 return rc;
2799}
2800
2801static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
2802{
2803 struct gsm_mncc *rel = arg;
2804 struct msgb *msg = gsm48_msgb_alloc();
2805 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2806
Harald Welte4bfdfe72009-06-10 23:11:52 +08002807 gh->msg_type = GSM48_MT_CC_RELEASE;
2808
2809 trans->callref = 0;
2810
2811 gsm48_stop_cc_timer(trans);
2812 gsm48_start_cc_timer(trans, 0x308, GSM48_T308);
2813
2814 /* cause */
2815 if (rel->fields & MNCC_F_CAUSE)
2816 encode_cause(msg, 0, &rel->cause);
2817 /* facility */
2818 if (rel->fields & MNCC_F_FACILITY)
2819 encode_facility(msg, 0, &rel->facility);
2820 /* user-user */
2821 if (rel->fields & MNCC_F_USERUSER)
2822 encode_useruser(msg, 0, &rel->useruser);
2823
Harald Weltedcaf5652009-07-23 18:56:43 +02002824 trans->cc.T308_second = 0;
2825 memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
Harald Welte4bfdfe72009-06-10 23:11:52 +08002826
Harald Weltedcaf5652009-07-23 18:56:43 +02002827 if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
Harald Welte4bfdfe72009-06-10 23:11:52 +08002828 new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
2829
Harald Welte39e2ead2009-07-23 21:13:03 +02002830 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002831}
2832
2833static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
2834{
2835 struct gsm48_hdr *gh = msgb_l3(msg);
2836 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2837 struct tlv_parsed tp;
2838 struct gsm_mncc rel;
2839 int rc = 0;
2840
2841 gsm48_stop_cc_timer(trans);
2842
2843 memset(&rel, 0, sizeof(struct gsm_mncc));
2844 rel.callref = trans->callref;
2845 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
2846 /* cause */
2847 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
2848 rel.fields |= MNCC_F_CAUSE;
2849 decode_cause(&rel.cause,
2850 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
2851 }
2852 /* facility */
2853 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2854 rel.fields |= MNCC_F_FACILITY;
2855 decode_facility(&rel.facility,
2856 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2857 }
2858 /* user-user */
2859 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
2860 rel.fields |= MNCC_F_USERUSER;
2861 decode_useruser(&rel.useruser,
2862 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
2863 }
2864 /* ss-version */
2865 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2866 rel.fields |= MNCC_F_SSVERSION;
2867 decode_ssversion(&rel.ssversion,
2868 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2869 }
2870
2871 if (trans->callref) {
Harald Weltedcaf5652009-07-23 18:56:43 +02002872 switch (trans->cc.state) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08002873 case GSM_CSTATE_CALL_PRESENT:
Harald Welte596fed42009-07-23 19:06:52 +02002874 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002875 MNCC_REJ_IND, &rel);
2876 break;
2877 case GSM_CSTATE_RELEASE_REQ:
Harald Welte596fed42009-07-23 19:06:52 +02002878 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002879 MNCC_REL_CNF, &rel);
2880 break;
2881 default:
Harald Welte596fed42009-07-23 19:06:52 +02002882 rc = mncc_recvmsg(trans->subscr->net, trans,
Harald Welte4bfdfe72009-06-10 23:11:52 +08002883 MNCC_REL_IND, &rel);
2884 }
2885 }
2886
2887 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02002888 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002889
2890 return rc;
2891}
2892
2893static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
2894{
2895 struct gsm_mncc *rel = arg;
2896 struct msgb *msg = gsm48_msgb_alloc();
2897 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2898
Harald Welte4bfdfe72009-06-10 23:11:52 +08002899 gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
2900
2901 trans->callref = 0;
2902
2903 gsm48_stop_cc_timer(trans);
2904
2905 /* cause */
2906 if (rel->fields & MNCC_F_CAUSE)
2907 encode_cause(msg, 0, &rel->cause);
2908 /* facility */
2909 if (rel->fields & MNCC_F_FACILITY)
2910 encode_facility(msg, 0, &rel->facility);
2911 /* user-user */
2912 if (rel->fields & MNCC_F_USERUSER)
2913 encode_useruser(msg, 0, &rel->useruser);
2914
Harald Weltedcaf5652009-07-23 18:56:43 +02002915 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002916
Harald Welte39e2ead2009-07-23 21:13:03 +02002917 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002918}
2919
2920static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
2921{
2922 struct gsm48_hdr *gh = msgb_l3(msg);
2923 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
2924 struct tlv_parsed tp;
2925 struct gsm_mncc fac;
2926
2927 memset(&fac, 0, sizeof(struct gsm_mncc));
2928 fac.callref = trans->callref;
2929 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
2930 /* facility */
2931 if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
2932 fac.fields |= MNCC_F_FACILITY;
2933 decode_facility(&fac.facility,
2934 TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
2935 }
2936 /* ss-version */
2937 if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
2938 fac.fields |= MNCC_F_SSVERSION;
2939 decode_ssversion(&fac.ssversion,
2940 TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
2941 }
2942
Harald Welte596fed42009-07-23 19:06:52 +02002943 return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002944}
2945
2946static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
2947{
2948 struct gsm_mncc *fac = arg;
2949 struct msgb *msg = gsm48_msgb_alloc();
2950 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2951
Harald Welte4bfdfe72009-06-10 23:11:52 +08002952 gh->msg_type = GSM48_MT_CC_FACILITY;
2953
2954 /* facility */
2955 encode_facility(msg, 1, &fac->facility);
2956
Harald Welte39e2ead2009-07-23 21:13:03 +02002957 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002958}
2959
2960static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
2961{
2962 struct gsm_mncc hold;
2963
2964 memset(&hold, 0, sizeof(struct gsm_mncc));
2965 hold.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02002966 return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002967}
2968
2969static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg)
2970{
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_HOLD_ACK;
2975
Harald Welte39e2ead2009-07-23 21:13:03 +02002976 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002977}
2978
2979static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
2980{
2981 struct gsm_mncc *hold_rej = arg;
2982 struct msgb *msg = gsm48_msgb_alloc();
2983 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
2984
Harald Welte4bfdfe72009-06-10 23:11:52 +08002985 gh->msg_type = GSM48_MT_CC_HOLD_REJ;
2986
2987 /* cause */
2988 if (hold_rej->fields & MNCC_F_CAUSE)
2989 encode_cause(msg, 1, &hold_rej->cause);
2990 else
2991 encode_cause(msg, 1, &default_cause);
2992
Harald Welte39e2ead2009-07-23 21:13:03 +02002993 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08002994}
2995
2996static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
2997{
2998 struct gsm_mncc retrieve;
2999
3000 memset(&retrieve, 0, sizeof(struct gsm_mncc));
3001 retrieve.callref = trans->callref;
Harald Welte596fed42009-07-23 19:06:52 +02003002 return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND,
3003 &retrieve);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003004}
3005
3006static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg)
3007{
3008 struct msgb *msg = gsm48_msgb_alloc();
3009 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3010
Harald Welte4bfdfe72009-06-10 23:11:52 +08003011 gh->msg_type = GSM48_MT_CC_RETR_ACK;
3012
Harald Welte39e2ead2009-07-23 21:13:03 +02003013 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003014}
3015
3016static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
3017{
3018 struct gsm_mncc *retrieve_rej = arg;
3019 struct msgb *msg = gsm48_msgb_alloc();
3020 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3021
Harald Welte4bfdfe72009-06-10 23:11:52 +08003022 gh->msg_type = GSM48_MT_CC_RETR_REJ;
3023
3024 /* cause */
3025 if (retrieve_rej->fields & MNCC_F_CAUSE)
3026 encode_cause(msg, 1, &retrieve_rej->cause);
3027 else
3028 encode_cause(msg, 1, &default_cause);
3029
Harald Welte39e2ead2009-07-23 21:13:03 +02003030 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003031}
3032
3033static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
3034{
3035 struct gsm48_hdr *gh = msgb_l3(msg);
3036 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3037 struct tlv_parsed tp;
3038 struct gsm_mncc dtmf;
3039
3040 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3041 dtmf.callref = trans->callref;
3042 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
3043 /* keypad facility */
3044 if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
3045 dtmf.fields |= MNCC_F_KEYPAD;
3046 decode_keypad(&dtmf.keypad,
3047 TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
3048 }
3049
Harald Welte596fed42009-07-23 19:06:52 +02003050 return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003051}
3052
3053static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
3054{
3055 struct gsm_mncc *dtmf = arg;
3056 struct msgb *msg = gsm48_msgb_alloc();
3057 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3058
Harald Welte4bfdfe72009-06-10 23:11:52 +08003059 gh->msg_type = GSM48_MT_CC_START_DTMF_ACK;
3060
3061 /* keypad */
3062 if (dtmf->fields & MNCC_F_KEYPAD)
3063 encode_keypad(msg, dtmf->keypad);
3064
Harald Welte39e2ead2009-07-23 21:13:03 +02003065 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003066}
3067
3068static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
3069{
3070 struct gsm_mncc *dtmf = arg;
3071 struct msgb *msg = gsm48_msgb_alloc();
3072 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3073
Harald Welte4bfdfe72009-06-10 23:11:52 +08003074 gh->msg_type = GSM48_MT_CC_START_DTMF_REJ;
3075
3076 /* cause */
3077 if (dtmf->fields & MNCC_F_CAUSE)
3078 encode_cause(msg, 1, &dtmf->cause);
3079 else
3080 encode_cause(msg, 1, &default_cause);
3081
Harald Welte39e2ead2009-07-23 21:13:03 +02003082 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003083}
3084
3085static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
3086{
3087 struct msgb *msg = gsm48_msgb_alloc();
3088 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3089
Harald Welte4bfdfe72009-06-10 23:11:52 +08003090 gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
3091
Harald Welte39e2ead2009-07-23 21:13:03 +02003092 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003093}
3094
3095static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
3096{
3097 struct gsm_mncc dtmf;
3098
3099 memset(&dtmf, 0, sizeof(struct gsm_mncc));
3100 dtmf.callref = trans->callref;
3101
Harald Welte596fed42009-07-23 19:06:52 +02003102 return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003103}
3104
3105static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
3106{
3107 struct gsm48_hdr *gh = msgb_l3(msg);
3108 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3109 struct tlv_parsed tp;
3110 struct gsm_mncc modify;
3111
3112 memset(&modify, 0, sizeof(struct gsm_mncc));
3113 modify.callref = trans->callref;
3114 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3115 /* bearer capability */
3116 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3117 modify.fields |= MNCC_F_BEARER_CAP;
3118 decode_bearer_cap(&modify.bearer_cap,
3119 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3120 }
3121
3122 new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
3123
Harald Welte596fed42009-07-23 19:06:52 +02003124 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003125}
3126
3127static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
3128{
3129 struct gsm_mncc *modify = arg;
3130 struct msgb *msg = gsm48_msgb_alloc();
3131 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3132
Harald Welte4bfdfe72009-06-10 23:11:52 +08003133 gh->msg_type = GSM48_MT_CC_MODIFY;
3134
3135 gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
3136
3137 /* bearer capability */
3138 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3139
3140 new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
3141
Harald Welte39e2ead2009-07-23 21:13:03 +02003142 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003143}
3144
3145static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
3146{
3147 struct gsm48_hdr *gh = msgb_l3(msg);
3148 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3149 struct tlv_parsed tp;
3150 struct gsm_mncc modify;
3151
3152 gsm48_stop_cc_timer(trans);
3153
3154 memset(&modify, 0, sizeof(struct gsm_mncc));
3155 modify.callref = trans->callref;
3156 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
3157 /* bearer capability */
3158 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3159 modify.fields |= MNCC_F_BEARER_CAP;
3160 decode_bearer_cap(&modify.bearer_cap,
3161 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3162 }
3163
3164 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3165
Harald Welte596fed42009-07-23 19:06:52 +02003166 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003167}
3168
3169static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
3170{
3171 struct gsm_mncc *modify = arg;
3172 struct msgb *msg = gsm48_msgb_alloc();
3173 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3174
Harald Welte4bfdfe72009-06-10 23:11:52 +08003175 gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
3176
3177 /* bearer capability */
3178 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3179
3180 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3181
Harald Welte39e2ead2009-07-23 21:13:03 +02003182 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003183}
3184
3185static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
3186{
3187 struct gsm48_hdr *gh = msgb_l3(msg);
3188 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3189 struct tlv_parsed tp;
3190 struct gsm_mncc modify;
3191
3192 gsm48_stop_cc_timer(trans);
3193
3194 memset(&modify, 0, sizeof(struct gsm_mncc));
3195 modify.callref = trans->callref;
3196 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
3197 /* bearer capability */
3198 if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
3199 modify.fields |= GSM48_IE_BEARER_CAP;
3200 decode_bearer_cap(&modify.bearer_cap,
3201 TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
3202 }
3203 /* cause */
3204 if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
3205 modify.fields |= MNCC_F_CAUSE;
3206 decode_cause(&modify.cause,
3207 TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
3208 }
3209
3210 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3211
Harald Welte596fed42009-07-23 19:06:52 +02003212 return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003213}
3214
3215static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
3216{
3217 struct gsm_mncc *modify = arg;
3218 struct msgb *msg = gsm48_msgb_alloc();
3219 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3220
Harald Welte4bfdfe72009-06-10 23:11:52 +08003221 gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
3222
3223 /* bearer capability */
3224 encode_bearer_cap(msg, 1, &modify->bearer_cap);
3225 /* cause */
3226 encode_cause(msg, 1, &modify->cause);
3227
3228 new_cc_state(trans, GSM_CSTATE_ACTIVE);
3229
Harald Welte39e2ead2009-07-23 21:13:03 +02003230 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003231}
3232
3233static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
3234{
3235 struct gsm_mncc *notify = arg;
3236 struct msgb *msg = gsm48_msgb_alloc();
3237 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3238
Harald Welte4bfdfe72009-06-10 23:11:52 +08003239 gh->msg_type = GSM48_MT_CC_NOTIFY;
3240
3241 /* notify */
3242 encode_notify(msg, notify->notify);
3243
Harald Welte39e2ead2009-07-23 21:13:03 +02003244 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003245}
3246
3247static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
3248{
3249 struct gsm48_hdr *gh = msgb_l3(msg);
3250 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3251// struct tlv_parsed tp;
3252 struct gsm_mncc notify;
3253
3254 memset(&notify, 0, sizeof(struct gsm_mncc));
3255 notify.callref = trans->callref;
3256// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
3257 if (payload_len >= 1)
3258 decode_notify(&notify.notify, gh->data);
3259
Harald Welte596fed42009-07-23 19:06:52 +02003260 return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003261}
3262
3263static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
3264{
3265 struct gsm_mncc *user = arg;
3266 struct msgb *msg = gsm48_msgb_alloc();
3267 struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
3268
Harald Welte4bfdfe72009-06-10 23:11:52 +08003269 gh->msg_type = GSM48_MT_CC_USER_INFO;
3270
3271 /* user-user */
3272 if (user->fields & MNCC_F_USERUSER)
3273 encode_useruser(msg, 1, &user->useruser);
3274 /* more data */
3275 if (user->more)
3276 encode_more(msg);
3277
Harald Welte39e2ead2009-07-23 21:13:03 +02003278 return gsm48_sendmsg(msg, trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003279}
3280
3281static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
3282{
3283 struct gsm48_hdr *gh = msgb_l3(msg);
3284 unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
3285 struct tlv_parsed tp;
3286 struct gsm_mncc user;
3287
3288 memset(&user, 0, sizeof(struct gsm_mncc));
3289 user.callref = trans->callref;
3290 tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
3291 /* user-user */
3292 if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
3293 user.fields |= MNCC_F_USERUSER;
3294 decode_useruser(&user.useruser,
3295 TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
3296 }
3297 /* more data */
3298 if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
3299 user.more = 1;
3300
Harald Welte596fed42009-07-23 19:06:52 +02003301 return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003302}
3303
3304static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
3305{
3306 struct gsm_mncc *mode = arg;
Harald Welte13cac662009-07-29 12:10:35 +02003307 int rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003308
Harald Welte13cac662009-07-29 12:10:35 +02003309 rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
3310 if (rc < 0)
3311 return rc;
3312
3313 /* FIXME: we not only need to do this after mode modify, but
3314 * also after channel activation */
3315 if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
3316 mode->lchan_mode != GSM48_CMODE_SIGN)
3317 rc = rsl_ipacc_bind(trans->lchan);
3318
3319 return rc;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003320}
3321
3322static struct downstate {
3323 u_int32_t states;
3324 int type;
3325 int (*rout) (struct gsm_trans *trans, void *arg);
3326} downstatelist[] = {
3327 /* mobile originating call establishment */
3328 {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
3329 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
3330 {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
3331 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
3332 {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 */
3333 MNCC_SETUP_RSP, gsm48_cc_tx_connect},
3334 {SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.4.2 */
3335 MNCC_PROGRESS_REQ, gsm48_cc_tx_progress},
3336 /* mobile terminating call establishment */
3337 {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
3338 MNCC_SETUP_REQ, gsm48_cc_tx_setup},
3339 {SBIT(GSM_CSTATE_CONNECT_REQUEST),
3340 MNCC_SETUP_COMPL_REQ, gsm48_cc_tx_connect_ack},
3341 /* signalling during call */
3342 {SBIT(GSM_CSTATE_ACTIVE),
3343 MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
3344 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
3345 MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
3346 {ALL_STATES,
3347 MNCC_START_DTMF_RSP, gsm48_cc_tx_start_dtmf_ack},
3348 {ALL_STATES,
3349 MNCC_START_DTMF_REJ, gsm48_cc_tx_start_dtmf_rej},
3350 {ALL_STATES,
3351 MNCC_STOP_DTMF_RSP, gsm48_cc_tx_stop_dtmf_ack},
3352 {SBIT(GSM_CSTATE_ACTIVE),
3353 MNCC_HOLD_CNF, gsm48_cc_tx_hold_ack},
3354 {SBIT(GSM_CSTATE_ACTIVE),
3355 MNCC_HOLD_REJ, gsm48_cc_tx_hold_rej},
3356 {SBIT(GSM_CSTATE_ACTIVE),
3357 MNCC_RETRIEVE_CNF, gsm48_cc_tx_retrieve_ack},
3358 {SBIT(GSM_CSTATE_ACTIVE),
3359 MNCC_RETRIEVE_REJ, gsm48_cc_tx_retrieve_rej},
3360 {SBIT(GSM_CSTATE_ACTIVE),
3361 MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
3362 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3363 MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
3364 {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
3365 MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
3366 {SBIT(GSM_CSTATE_ACTIVE),
3367 MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
3368 /* clearing */
3369 {SBIT(GSM_CSTATE_INITIATED),
3370 MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
3371 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.4 */
3372 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
3373 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3374 MNCC_REL_REQ, gsm48_cc_tx_release},
3375 /* special */
3376 {ALL_STATES,
3377 MNCC_LCHAN_MODIFY, gsm48_lchan_modify},
3378};
3379
3380#define DOWNSLLEN \
3381 (sizeof(downstatelist) / sizeof(struct downstate))
3382
3383
3384int mncc_send(struct gsm_network *net, int msg_type, void *arg)
3385{
Harald Welte1a6f7982009-08-09 18:52:33 +02003386 int i, rc = 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003387 struct gsm_trans *trans = NULL, *transt;
3388 struct gsm_subscriber *subscr;
Harald Welte1a6f7982009-08-09 18:52:33 +02003389 struct gsm_lchan *lchan = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003390 struct gsm_bts *bts = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003391 struct gsm_mncc *data = arg, rel;
3392
3393 /* handle special messages */
3394 switch(msg_type) {
3395 case MNCC_BRIDGE:
3396 return tch_bridge(net, arg);
3397 case MNCC_FRAME_DROP:
3398 return tch_recv(net, arg, 0);
3399 case MNCC_FRAME_RECV:
3400 return tch_recv(net, arg, 1);
3401 case GSM_TRAU_FRAME:
3402 return tch_frame(net, arg);
3403 }
3404
3405 memset(&rel, 0, sizeof(struct gsm_mncc));
3406 rel.callref = data->callref;
3407
3408 /* Find callref */
Harald Weltedcaf5652009-07-23 18:56:43 +02003409 trans = trans_find_by_callref(net, data->callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003410
3411 /* Callref unknown */
3412 if (!trans) {
Harald Welte4a3464c2009-07-04 10:11:24 +02003413 if (msg_type != MNCC_SETUP_REQ) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003414 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3415 "Received '%s' from MNCC with "
3416 "unknown callref %d\n", data->called.number,
3417 get_mncc_name(msg_type), data->callref);
3418 /* Invalid call reference */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003419 return mncc_release_ind(net, NULL, data->callref,
3420 GSM48_CAUSE_LOC_PRN_S_LU,
3421 GSM48_CC_CAUSE_INVAL_TRANS_ID);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003422 }
Andreas Eversbergc079be42009-06-15 23:22:09 +02003423 if (!data->called.number[0] && !data->imsi[0]) {
3424 DEBUGP(DCC, "(bts - trx - ts - ti) "
3425 "Received '%s' from MNCC with "
3426 "no number or IMSI\n", get_mncc_name(msg_type));
3427 /* Invalid number */
3428 return mncc_release_ind(net, NULL, data->callref,
3429 GSM48_CAUSE_LOC_PRN_S_LU,
3430 GSM48_CC_CAUSE_INV_NR_FORMAT);
3431 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003432 /* New transaction due to setup, find subscriber */
Andreas Eversbergc079be42009-06-15 23:22:09 +02003433 if (data->called.number[0])
Harald Welte9176bd42009-07-23 18:46:00 +02003434 subscr = subscr_get_by_extension(net,
3435 data->called.number);
Andreas Eversbergc079be42009-06-15 23:22:09 +02003436 else
Harald Welte9176bd42009-07-23 18:46:00 +02003437 subscr = subscr_get_by_imsi(net, data->imsi);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003438 /* If subscriber is not found */
3439 if (!subscr) {
3440 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3441 "Received '%s' from MNCC with "
3442 "unknown subscriber %s\n", data->called.number,
3443 get_mncc_name(msg_type), data->called.number);
3444 /* Unknown subscriber */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003445 return mncc_release_ind(net, NULL, data->callref,
3446 GSM48_CAUSE_LOC_PRN_S_LU,
3447 GSM48_CC_CAUSE_UNASSIGNED_NR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003448 }
3449 /* If subscriber is not "attached" */
3450 if (!subscr->lac) {
3451 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3452 "Received '%s' from MNCC with "
3453 "detached subscriber %s\n", data->called.number,
3454 get_mncc_name(msg_type), data->called.number);
3455 subscr_put(subscr);
3456 /* Temporarily out of order */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003457 return mncc_release_ind(net, NULL, data->callref,
3458 GSM48_CAUSE_LOC_PRN_S_LU,
3459 GSM48_CC_CAUSE_DEST_OOO);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003460 }
3461 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003462 trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
3463 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003464 DEBUGP(DCC, "No memory for trans.\n");
3465 subscr_put(subscr);
3466 /* Ressource unavailable */
Andreas Eversberg7563ac92009-06-14 22:14:12 +08003467 mncc_release_ind(net, NULL, data->callref,
3468 GSM48_CAUSE_LOC_PRN_S_LU,
3469 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003470 return -ENOMEM;
3471 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003472 /* Find lchan */
Harald Welte1a6f7982009-08-09 18:52:33 +02003473 lchan = lchan_for_subscr(subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003474 /* If subscriber has no lchan */
3475 if (!lchan) {
3476 /* find transaction with this subscriber already paging */
3477 llist_for_each_entry(transt, &net->trans_list, entry) {
3478 /* Transaction of our lchan? */
3479 if (transt == trans ||
3480 transt->subscr != subscr)
3481 continue;
3482 DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
3483 "Received '%s' from MNCC with "
3484 "unallocated channel, paging already "
3485 "started.\n", bts->nr,
3486 data->called.number,
3487 get_mncc_name(msg_type));
3488 return 0;
3489 }
3490 /* store setup informations until paging was successfull */
Harald Weltedcaf5652009-07-23 18:56:43 +02003491 memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
Harald Weltea1b28582009-08-01 19:31:47 +02003492 /* Trigger paging */
3493 paging_request(net, subscr, RSL_CHANNEED_TCH_F,
3494 setup_trig_pag_evt, subscr);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003495 return 0;
3496 }
3497 /* Assign lchan */
3498 trans->lchan = lchan;
3499 use_lchan(lchan);
3500 }
3501 lchan = trans->lchan;
3502
3503 /* if paging did not respond yet */
3504 if (!lchan) {
3505 DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
3506 "Received '%s' from MNCC in paging state\n",
3507 (trans->subscr)?(trans->subscr->extension):"-",
3508 get_mncc_name(msg_type));
Harald Weltec66b71c2009-06-11 14:23:20 +08003509 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
3510 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003511 if (msg_type == MNCC_REL_REQ)
3512 rc = mncc_recvmsg(net, trans, MNCC_REL_CNF, &rel);
3513 else
3514 rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
3515 trans->callref = 0;
Harald Weltedcaf5652009-07-23 18:56:43 +02003516 trans_free(trans);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003517 return rc;
3518 }
3519
3520 DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
3521 "Received '%s' from MNCC in state %d (%s)\n",
3522 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3523 trans->transaction_id,
3524 (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003525 get_mncc_name(msg_type), trans->cc.state,
3526 cc_state_names[trans->cc.state]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003527
3528 /* Find function for current state and message */
3529 for (i = 0; i < DOWNSLLEN; i++)
3530 if ((msg_type == downstatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003531 && ((1 << trans->cc.state) & downstatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003532 break;
3533 if (i == DOWNSLLEN) {
3534 DEBUGP(DCC, "Message unhandled at this state.\n");
3535 return 0;
3536 }
3537
3538 rc = downstatelist[i].rout(trans, arg);
3539
3540 return rc;
3541}
3542
3543
3544static struct datastate {
3545 u_int32_t states;
3546 int type;
3547 int (*rout) (struct gsm_trans *trans, struct msgb *msg);
3548} datastatelist[] = {
3549 /* mobile originating call establishment */
3550 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3551 GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
3552 {SBIT(GSM_CSTATE_NULL), /* 5.2.1.2 */
3553 GSM48_MT_CC_EMERG_SETUP, gsm48_cc_rx_setup},
3554 {SBIT(GSM_CSTATE_CONNECT_IND), /* 5.2.1.2 */
3555 GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
3556 /* mobile terminating call establishment */
3557 {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.2 */
3558 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
3559 {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
3560 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
3561 {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 */
3562 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
3563 /* signalling during call */
3564 {ALL_STATES - SBIT(GSM_CSTATE_NULL),
3565 GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
3566 {SBIT(GSM_CSTATE_ACTIVE),
3567 GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
3568 {ALL_STATES,
3569 GSM48_MT_CC_START_DTMF, gsm48_cc_rx_start_dtmf},
3570 {ALL_STATES,
3571 GSM48_MT_CC_STOP_DTMF, gsm48_cc_rx_stop_dtmf},
3572 {ALL_STATES,
3573 GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
3574 {SBIT(GSM_CSTATE_ACTIVE),
3575 GSM48_MT_CC_HOLD, gsm48_cc_rx_hold},
3576 {SBIT(GSM_CSTATE_ACTIVE),
3577 GSM48_MT_CC_RETR, gsm48_cc_rx_retrieve},
3578 {SBIT(GSM_CSTATE_ACTIVE),
3579 GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
3580 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3581 GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
3582 {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
3583 GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
3584 {SBIT(GSM_CSTATE_ACTIVE),
3585 GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
3586 /* clearing */
3587 {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
3588 GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
3589 {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.4.1.2.2 */
3590 GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
3591 {ALL_STATES, /* 5.4.3.4 */
3592 GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
3593};
3594
3595#define DATASLLEN \
3596 (sizeof(datastatelist) / sizeof(struct datastate))
3597
Harald Welte4bc90a12008-12-27 16:32:52 +00003598static int gsm0408_rcv_cc(struct msgb *msg)
3599{
3600 struct gsm48_hdr *gh = msgb_l3(msg);
3601 u_int8_t msg_type = gh->msg_type & 0xbf;
Harald Welte6f5aee02009-07-23 21:21:14 +02003602 u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003603 struct gsm_lchan *lchan = msg->lchan;
Harald Weltedcaf5652009-07-23 18:56:43 +02003604 struct gsm_trans *trans = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +08003605 int i, rc = 0;
Harald Welte4bc90a12008-12-27 16:32:52 +00003606
Harald Welte4bfdfe72009-06-10 23:11:52 +08003607 if (msg_type & 0x80) {
3608 DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
3609 return -EINVAL;
Harald Welte4bc90a12008-12-27 16:32:52 +00003610 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003611
3612 /* Find transaction */
Harald Welteb8b40732009-07-23 21:58:40 +02003613 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
Harald Weltedcaf5652009-07-23 18:56:43 +02003614
Harald Welte6f5aee02009-07-23 21:21:14 +02003615 DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003616 "Received '%s' from MS in state %d (%s)\n",
3617 lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
3618 transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
Harald Weltedcaf5652009-07-23 18:56:43 +02003619 cc_msg_names[msg_type], trans?(trans->cc.state):0,
3620 cc_state_names[trans?(trans->cc.state):0]);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003621
3622 /* Create transaction */
3623 if (!trans) {
Harald Welte6f5aee02009-07-23 21:21:14 +02003624 DEBUGP(DCC, "Unknown transaction ID %x, "
Harald Welte4bfdfe72009-06-10 23:11:52 +08003625 "creating new trans.\n", transaction_id);
3626 /* Create transaction */
Harald Weltedcaf5652009-07-23 18:56:43 +02003627 trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
3628 transaction_id, new_callref++);
3629 if (!trans) {
Harald Welte4bfdfe72009-06-10 23:11:52 +08003630 DEBUGP(DCC, "No memory for trans.\n");
3631 rc = gsm48_tx_simple(msg->lchan,
Harald Welte6f5aee02009-07-23 21:21:14 +02003632 GSM48_PDISC_CC | (transaction_id << 4),
Harald Welte4bfdfe72009-06-10 23:11:52 +08003633 GSM48_MT_CC_RELEASE_COMPL);
3634 return -ENOMEM;
3635 }
Harald Welte4bfdfe72009-06-10 23:11:52 +08003636 /* Assign transaction */
Harald Welte4bfdfe72009-06-10 23:11:52 +08003637 trans->lchan = lchan;
3638 use_lchan(lchan);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003639 }
3640
3641 /* find function for current state and message */
3642 for (i = 0; i < DATASLLEN; i++)
3643 if ((msg_type == datastatelist[i].type)
Harald Weltedcaf5652009-07-23 18:56:43 +02003644 && ((1 << trans->cc.state) & datastatelist[i].states))
Harald Welte4bfdfe72009-06-10 23:11:52 +08003645 break;
3646 if (i == DATASLLEN) {
3647 DEBUGP(DCC, "Message unhandled at this state.\n");
3648 return 0;
3649 }
3650
3651 rc = datastatelist[i].rout(trans, msg);
Harald Welte4bc90a12008-12-27 16:32:52 +00003652
3653 return rc;
3654}
3655
Harald Welte52b1f982008-12-23 20:25:15 +00003656/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
3657int gsm0408_rcvmsg(struct msgb *msg)
3658{
3659 struct gsm48_hdr *gh = msgb_l3(msg);
3660 u_int8_t pdisc = gh->proto_discr & 0x0f;
Harald Welte8470bf22008-12-25 23:28:35 +00003661 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00003662
3663 switch (pdisc) {
3664 case GSM48_PDISC_CC:
3665 rc = gsm0408_rcv_cc(msg);
3666 break;
3667 case GSM48_PDISC_MM:
3668 rc = gsm0408_rcv_mm(msg);
3669 break;
3670 case GSM48_PDISC_RR:
3671 rc = gsm0408_rcv_rr(msg);
3672 break;
Harald Weltebcae43f2008-12-27 21:45:37 +00003673 case GSM48_PDISC_SMS:
Daniel Willmann8b3390e2008-12-28 00:31:09 +00003674 rc = gsm0411_rcv_sms(msg);
Harald Weltebcae43f2008-12-27 21:45:37 +00003675 break;
Harald Welte52b1f982008-12-23 20:25:15 +00003676 case GSM48_PDISC_MM_GPRS:
Harald Weltebcae43f2008-12-27 21:45:37 +00003677 case GSM48_PDISC_SM_GPRS:
Harald Welte52b1f982008-12-23 20:25:15 +00003678 fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
3679 pdisc);
3680 break;
3681 default:
3682 fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
3683 pdisc);
3684 break;
3685 }
3686
3687 return rc;
3688}
Harald Welte8470bf22008-12-25 23:28:35 +00003689
Harald Welte8470bf22008-12-25 23:28:35 +00003690/* Section 9.1.8 / Table 9.9 */
3691struct chreq {
3692 u_int8_t val;
3693 u_int8_t mask;
3694 enum chreq_type type;
3695};
3696
3697/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
3698static const struct chreq chreq_type_neci1[] = {
3699 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3700 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
3701 { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
3702 { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
3703 { 0xe0, 0xe0, CHREQ_T_SDCCH },
3704 { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
3705 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3706 { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
3707 { 0x10, 0xf0, CHREQ_T_SDCCH },
3708 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3709 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3710 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3711};
3712
3713/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
3714static const struct chreq chreq_type_neci0[] = {
3715 { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
3716 { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
3717 { 0xe0, 0xe0, CHREQ_T_TCH_F },
3718 { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
3719 { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
3720 { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
3721 { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
3722 { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
3723};
3724
3725static const enum gsm_chan_t ctype_by_chreq[] = {
3726 [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
3727 [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
3728 [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
3729 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
3730 [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
3731 [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
3732 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3733 [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
3734 [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
3735 [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
3736 [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
3737 [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
3738};
3739
Harald Weltee14a57c2008-12-29 04:08:28 +00003740static const enum gsm_chreq_reason_t reason_by_chreq[] = {
3741 [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
3742 [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
3743 [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
3744 [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
3745 [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
3746 [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
3747 [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3748 [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
3749 [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
3750 [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
3751 [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
3752 [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
3753};
3754
Harald Welte8470bf22008-12-25 23:28:35 +00003755enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3756{
3757 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003758 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Welte8470bf22008-12-25 23:28:35 +00003759
Harald Weltee58ca7c2009-08-10 02:14:46 +02003760 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3761 const struct chreq *chr = &chreq_type_neci0[i];
Harald Welte8470bf22008-12-25 23:28:35 +00003762 if ((ra & chr->mask) == chr->val)
3763 return ctype_by_chreq[chr->type];
3764 }
3765 fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
3766 return GSM_LCHAN_SDCCH;
3767}
Harald Weltee14a57c2008-12-29 04:08:28 +00003768
3769enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
3770{
3771 int i;
Harald Weltee58ca7c2009-08-10 02:14:46 +02003772 /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
Harald Weltee14a57c2008-12-29 04:08:28 +00003773
Harald Weltee58ca7c2009-08-10 02:14:46 +02003774 for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
3775 const struct chreq *chr = &chreq_type_neci0[i];
Harald Weltee14a57c2008-12-29 04:08:28 +00003776 if ((ra & chr->mask) == chr->val)
3777 return reason_by_chreq[chr->type];
3778 }
3779 fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
3780 return GSM_CHREQ_REASON_OTHER;
3781}
Harald Welte4bfdfe72009-06-10 23:11:52 +08003782
3783/* dequeue messages to layer 4 */
3784int bsc_upqueue(struct gsm_network *net)
3785{
3786 struct gsm_mncc *mncc;
3787 struct msgb *msg;
3788 int work = 0;
3789
3790 if (net)
3791 while ((msg = msgb_dequeue(&net->upqueue))) {
3792 mncc = (struct gsm_mncc *)msg->data;
3793 if (net->mncc_recv)
3794 net->mncc_recv(net, mncc->msg_type, mncc);
3795 work = 1; /* work done */
Harald Welte316c8252009-06-26 19:40:48 +02003796 talloc_free(msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +08003797 }
3798
3799 return work;
3800}
Harald Weltedcaf5652009-07-23 18:56:43 +02003801
Harald Welte805f6442009-07-28 18:25:29 +02003802/*
3803 * This will be ran by the linker when loading the DSO. We use it to
3804 * do system initialization, e.g. registration of signal handlers.
3805 */
3806static __attribute__((constructor)) void on_dso_load_0408(void)
3807{
3808 tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
3809 "loc_updating_oper");
3810 register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
3811 register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
3812}