blob: d6f8c3b17f0cf15cb25ac8397a3e092512199103 [file] [log] [blame]
Harald Welte9ee48252009-07-23 21:25:08 +02001/* GSM 04.07 Transaction handling */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
Harald Welte9ee48252009-07-23 21:25:08 +02009 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte9ee48252009-07-23 21:25:08 +020015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte9ee48252009-07-23 21:25:08 +020018 *
19 */
20
Neels Hofmeyr90843962017-09-04 15:04:35 +020021#include <osmocom/msc/transaction.h>
22#include <osmocom/msc/gsm_data.h>
23#include <osmocom/msc/mncc.h>
24#include <osmocom/msc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010025#include <osmocom/core/talloc.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020026#include <osmocom/msc/gsm_04_08.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020027#include <osmocom/msc/vlr.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010028#include <osmocom/msc/msc_a.h>
29#include <osmocom/msc/msub.h>
30#include <osmocom/msc/paging.h>
31#include <osmocom/msc/silent_call.h>
Harald Welte9ee48252009-07-23 21:25:08 +020032
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020033void *tall_trans_ctx;
Harald Welte9ee48252009-07-23 21:25:08 +020034
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020035void _gsm48_cc_trans_free(struct gsm_trans *trans);
Vadim Yanitskiyc350c092018-11-21 20:51:51 +070036void _gsm411_sms_trans_free(struct gsm_trans *trans);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +070037void _gsm911_nc_ss_trans_free(struct gsm_trans *trans);
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020038
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010039struct gsm_trans *trans_find_by_type(const struct msc_a *msc_a, enum trans_type type)
40{
41 struct gsm_trans *trans;
42 struct gsm_network *net = msc_a_net(msc_a);
43 struct vlr_subscr *vsub = msc_a_vsub(msc_a);
44
45 llist_for_each_entry(trans, &net->trans_list, entry) {
46 if (trans->vsub == vsub && trans->type == type)
47 return trans;
48 }
49 return NULL;
50}
51
Harald Welte2483f1b2016-06-19 18:06:02 +020052/*! Find a transaction in connection for given protocol + transaction ID
Vadim Yanitskiy380b2192018-11-27 15:14:31 +070053 * \param[in] conn Connection in which we want to find transaction
Harald Welte2483f1b2016-06-19 18:06:02 +020054 * \param[in] proto Protocol of transaction
55 * \param[in] trans_id Transaction ID of transaction
56 * \returns Matching transaction, if any
57 */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010058struct gsm_trans *trans_find_by_id(const struct msc_a *msc_a,
59 enum trans_type type, uint8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020060{
61 struct gsm_trans *trans;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010062 struct gsm_network *net = msc_a_net(msc_a);
63 struct vlr_subscr *vsub = msc_a_vsub(msc_a);
Harald Welte9ee48252009-07-23 21:25:08 +020064
65 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welte2483f1b2016-06-19 18:06:02 +020066 if (trans->vsub == vsub &&
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010067 trans->type == type &&
Harald Welteb8b40732009-07-23 21:58:40 +020068 trans->transaction_id == trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020069 return trans;
70 }
71 return NULL;
72}
73
Harald Welte2483f1b2016-06-19 18:06:02 +020074/*! Find a transaction by call reference
75 * \param[in] net Network in which we should search
76 * \param[in] callref Call Reference of transaction
77 * \returns Matching transaction, if any
78 */
Max7916ca12019-01-02 11:48:14 +010079struct gsm_trans *trans_find_by_callref(const struct gsm_network *net,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020080 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +020081{
82 struct gsm_trans *trans;
83
84 llist_for_each_entry(trans, &net->trans_list, entry) {
85 if (trans->callref == callref)
86 return trans;
87 }
88 return NULL;
89}
90
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030091/*! Find a transaction by SM-RP-MR (RP Message Reference)
Vadim Yanitskiy36c44b22019-01-23 21:22:27 +070092 * \param[in] net Network in which we should search
93 * \param[in] vsub Subscriber for which we should search
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030094 * \param[in] sm_rp_mr RP Message Reference (see GSM TS 04.11, section 8.2.3)
95 * \returns Matching transaction, NULL otherwise
96 */
Vadim Yanitskiy36c44b22019-01-23 21:22:27 +070097struct gsm_trans *trans_find_by_sm_rp_mr(const struct gsm_network *net,
98 const struct vlr_subscr *vsub,
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030099 uint8_t sm_rp_mr)
100{
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +0300101 struct gsm_trans *trans;
102
103 llist_for_each_entry(trans, &net->trans_list, entry) {
104 if (trans->vsub == vsub &&
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100105 trans->type == TRANS_SMS &&
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +0300106 trans->sms.sm_rp_mr == sm_rp_mr)
107 return trans;
108 }
109
110 return NULL;
111}
112
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100113static const char *trans_vsub_use(enum trans_type type)
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100114{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100115 return get_value_string_or_null(trans_type_names, type) ? : "trans-type-unknown";
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100116}
117
Harald Welte2483f1b2016-06-19 18:06:02 +0200118/*! Allocate a new transaction and add it to network list
119 * \param[in] net Netwokr in which we allocate transaction
120 * \param[in] subscr Subscriber for which we allocate transaction
121 * \param[in] protocol Protocol (CC/SMS/...)
122 * \param[in] callref Call Reference
123 * \returns Transaction
124 */
Jacob Erlbeckaf792d62014-12-02 14:22:53 +0100125struct gsm_trans *trans_alloc(struct gsm_network *net,
Harald Welte2483f1b2016-06-19 18:06:02 +0200126 struct vlr_subscr *vsub,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100127 enum trans_type type, uint8_t trans_id,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200128 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +0200129{
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100130 struct gsm_trans *trans = NULL; /* (NULL for LOG_TRANS() before allocation) */
Harald Welte9ee48252009-07-23 21:25:08 +0200131
Benoit Bolseee7cf5e72017-07-05 12:34:18 +0200132 /* a valid subscriber is indispensable */
133 if (vsub == NULL) {
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100134 LOG_TRANS(trans, LOGL_ERROR, "unable to alloc transaction, invalid subscriber (NULL)\n");
Benoit Bolseee7cf5e72017-07-05 12:34:18 +0200135 return NULL;
136 }
137
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100138 trans = talloc(tall_trans_ctx, struct gsm_trans);
Harald Welte9ee48252009-07-23 21:25:08 +0200139 if (!trans)
140 return NULL;
141
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100142 *trans = (struct gsm_trans){
143 .vsub = vsub,
144 .type = type,
145 .transaction_id = trans_id,
146 .callref = callref,
147 .net = net,
148 };
Neels Hofmeyr7f85ace2019-05-09 15:12:34 +0200149 trans->log_subsys = trans_log_subsys(trans);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100150 vlr_subscr_get(vsub, trans_vsub_use(type));
Jacob Erlbeckf07c6052014-12-02 11:58:00 +0100151 llist_add_tail(&trans->entry, &net->trans_list);
Harald Welte9ee48252009-07-23 21:25:08 +0200152
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100153 LOG_TRANS(trans, LOGL_DEBUG, "New transaction\n");
Harald Welte9ee48252009-07-23 21:25:08 +0200154 return trans;
155}
156
Harald Welte2483f1b2016-06-19 18:06:02 +0200157/*! Release a transaction
158 * \param[in] trans Transaction to be released
159 */
Harald Welte9ee48252009-07-23 21:25:08 +0200160void trans_free(struct gsm_trans *trans)
161{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100162 const char *usage_token;
163 struct msc_a *msc_a;
Neels Hofmeyr6166f292017-11-22 14:33:12 +0100164
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100165 LOG_TRANS(trans, LOGL_DEBUG, "Freeing transaction\n");
166
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100167 switch (trans->type) {
168 case TRANS_CC:
Harald Welte9ee48252009-07-23 21:25:08 +0200169 _gsm48_cc_trans_free(trans);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100170 usage_token = MSC_A_USE_CC;
Harald Welte9ee48252009-07-23 21:25:08 +0200171 break;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100172 case TRANS_SMS:
Harald Welte (local)86b17172009-08-14 14:52:17 +0200173 _gsm411_sms_trans_free(trans);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100174 usage_token = MSC_A_USE_SMS;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200175 break;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100176 case TRANS_USSD:
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700177 _gsm911_nc_ss_trans_free(trans);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100178 usage_token = MSC_A_USE_NC_SS;
179 break;
180 case TRANS_SILENT_CALL:
181 trans_silent_call_free(trans);
182 usage_token = MSC_A_USE_SILENT_CALL;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700183 break;
Vadim Yanitskiye4574f02019-01-25 19:23:25 +0700184 default:
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100185 usage_token = NULL;
Vadim Yanitskiye4574f02019-01-25 19:23:25 +0700186 break;
Harald Welte9ee48252009-07-23 21:25:08 +0200187 }
188
Holger Hans Peter Freytherd6d7aff2015-04-06 12:03:45 +0200189 if (trans->paging_request) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100190 paging_request_remove(trans->paging_request);
Holger Hans Peter Freyther49b3ed22010-12-29 17:09:07 +0100191 trans->paging_request = NULL;
Harald Welte9ee48252009-07-23 21:25:08 +0200192 }
193
Harald Welte2483f1b2016-06-19 18:06:02 +0200194 if (trans->vsub) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100195 vlr_subscr_put(trans->vsub, trans_vsub_use(trans->type));
Harald Welte2483f1b2016-06-19 18:06:02 +0200196 trans->vsub = NULL;
Holger Hans Peter Freyther405824c2012-12-22 18:16:47 +0100197 }
Harald Welte9ee48252009-07-23 21:25:08 +0200198
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100199 msc_a = trans->msc_a;
200 trans->msc_a = NULL;
201
Neels Hofmeyre3d3dc62018-03-31 00:02:14 +0200202 llist_del(&trans->entry);
Harald Welte9ee48252009-07-23 21:25:08 +0200203 talloc_free(trans);
Neels Hofmeyrd6a769b2018-03-12 23:59:07 +0100204
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100205 if (msc_a && usage_token)
206 msc_a_put(msc_a, usage_token);
Harald Welte9ee48252009-07-23 21:25:08 +0200207}
208
Harald Welte2483f1b2016-06-19 18:06:02 +0200209/*! allocate an unused transaction ID for the given subscriber
Max30fb97a2019-01-10 17:25:33 +0100210 * in the given protocol using TI flag = 0 (allocated by us).
211 * See GSM 04.07, section 11.2.3.1.3 "Transaction identifier".
Harald Welte2483f1b2016-06-19 18:06:02 +0200212 * \param[in] net GSM network
Vadim Yanitskiybaeeb902019-02-14 16:41:30 +0700213 * \param[in] subscr Subscriber for which to assign a new TID
214 * \param[in] protocol Protocol of to be assigned TID
Harald Welte2483f1b2016-06-19 18:06:02 +0200215 */
Max7916ca12019-01-02 11:48:14 +0100216int trans_assign_trans_id(const struct gsm_network *net, const struct vlr_subscr *vsub,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100217 enum trans_type type)
Harald Welte9ee48252009-07-23 21:25:08 +0200218{
Harald Welte9ee48252009-07-23 21:25:08 +0200219 struct gsm_trans *trans;
220 unsigned int used_tid_bitmask = 0;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100221 int i, j, h;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100222 uint8_t proto = trans_type_to_gsm48_proto(type);
Harald Welte78283ef2009-07-23 21:36:44 +0200223
Harald Welte9ee48252009-07-23 21:25:08 +0200224 /* generate bitmask of already-used TIDs for this (subscr,proto) */
225 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welte2483f1b2016-06-19 18:06:02 +0200226 if (trans->vsub != vsub ||
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100227 proto != trans_type_to_gsm48_proto(trans->type) ||
Maxd8daaae2019-02-14 16:54:10 +0700228 trans->transaction_id == TRANS_ID_UNASSIGNED)
Harald Welte9ee48252009-07-23 21:25:08 +0200229 continue;
230 used_tid_bitmask |= (1 << trans->transaction_id);
231 }
232
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100233 /* find a new one, trying to go in a 'circular' pattern */
234 for (h = 6; h > 0; h--)
Max30fb97a2019-01-10 17:25:33 +0100235 if (used_tid_bitmask & (1 << h))
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100236 break;
Sylvain Munautb9f3dce2009-12-18 18:28:11 +0100237 for (i = 0; i < 7; i++) {
Max30fb97a2019-01-10 17:25:33 +0100238 j = (h + i) % 7;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100239 if ((used_tid_bitmask & (1 << j)) == 0)
240 return j;
Harald Welte78283ef2009-07-23 21:36:44 +0200241 }
242
243 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200244}
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100245
Harald Welte2483f1b2016-06-19 18:06:02 +0200246/*! Check if we have any transaction for given connection
247 * \param[in] conn Connection to check
Maxc065ca32019-01-14 11:51:28 +0100248 * \returns transaction pointer if found, NULL otherwise
Harald Welte2483f1b2016-06-19 18:06:02 +0200249 */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100250struct gsm_trans *trans_has_conn(const struct msc_a *msc_a)
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100251{
252 struct gsm_trans *trans;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100253 struct gsm_network *net = msc_a_net(msc_a);
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100254
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100255 llist_for_each_entry(trans, &net->trans_list, entry)
256 if (trans->msc_a == msc_a)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200257 return trans;
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100258
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200259 return NULL;
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100260}
Harald Welte2483f1b2016-06-19 18:06:02 +0200261
262/*! Free all transactions associated with a connection, presumably when the
263 * conn is being closed. The transaction code will inform the CC or SMS
264 * facilities, which will then send the necessary release indications.
265 * \param[in] conn Connection that is going to be closed.
266 */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100267void trans_conn_closed(const struct msc_a *msc_a)
Harald Welte2483f1b2016-06-19 18:06:02 +0200268{
Harald Welte2483f1b2016-06-19 18:06:02 +0200269 /* As part of the CC REL_IND the remote leg might be released and this
270 * will trigger another call to trans_free. This is something the llist
271 * macro can not handle and we need to re-iterate the list every time.
272 */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100273 struct gsm_trans *trans;
274 while ((trans = trans_has_conn(msc_a)))
275 trans_free(trans);
276}
277
278const struct value_string trans_type_names[] = {
279 { TRANS_CC, "CC" },
280 { TRANS_SMS, "SMS" },
281 { TRANS_USSD, "NCSS" },
282 { TRANS_SILENT_CALL, "silent-call" },
283 {}
284};
285
286uint8_t trans_type_to_gsm48_proto(enum trans_type type)
287{
288 switch (type) {
289 case TRANS_CC:
290 case TRANS_SILENT_CALL:
291 return GSM48_PDISC_CC;
292 case TRANS_SMS:
293 return GSM48_PDISC_SMS;
294 case TRANS_USSD:
295 return GSM48_PDISC_NC_SS;
296 default:
297 return GSM48_PDISC_TEST;
Harald Welte2483f1b2016-06-19 18:06:02 +0200298 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100299
Harald Welte2483f1b2016-06-19 18:06:02 +0200300}