blob: b38c15216dd863b2a9f9429fcaf47544131a26b6 [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>
Harald Welte9ee48252009-07-23 21:25:08 +020028
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020029void *tall_trans_ctx;
Harald Welte9ee48252009-07-23 21:25:08 +020030
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020031void _gsm48_cc_trans_free(struct gsm_trans *trans);
Vadim Yanitskiyc350c092018-11-21 20:51:51 +070032void _gsm411_sms_trans_free(struct gsm_trans *trans);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +070033void _gsm911_nc_ss_trans_free(struct gsm_trans *trans);
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020034
Harald Welte2483f1b2016-06-19 18:06:02 +020035/*! Find a transaction in connection for given protocol + transaction ID
Vadim Yanitskiy380b2192018-11-27 15:14:31 +070036 * \param[in] conn Connection in which we want to find transaction
Harald Welte2483f1b2016-06-19 18:06:02 +020037 * \param[in] proto Protocol of transaction
38 * \param[in] trans_id Transaction ID of transaction
39 * \returns Matching transaction, if any
40 */
Max7916ca12019-01-02 11:48:14 +010041struct gsm_trans *trans_find_by_id(const struct ran_conn *conn,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020042 uint8_t proto, uint8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020043{
44 struct gsm_trans *trans;
Neels Hofmeyra9f2bb52016-05-09 21:09:47 +020045 struct gsm_network *net = conn->network;
Harald Welte2483f1b2016-06-19 18:06:02 +020046 struct vlr_subscr *vsub = conn->vsub;
Harald Welte9ee48252009-07-23 21:25:08 +020047
48 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welte2483f1b2016-06-19 18:06:02 +020049 if (trans->vsub == vsub &&
Harald Welteb8b40732009-07-23 21:58:40 +020050 trans->protocol == proto &&
51 trans->transaction_id == trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020052 return trans;
53 }
54 return NULL;
55}
56
Harald Welte2483f1b2016-06-19 18:06:02 +020057/*! Find a transaction by call reference
58 * \param[in] net Network in which we should search
59 * \param[in] callref Call Reference of transaction
60 * \returns Matching transaction, if any
61 */
Max7916ca12019-01-02 11:48:14 +010062struct gsm_trans *trans_find_by_callref(const struct gsm_network *net,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020063 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +020064{
65 struct gsm_trans *trans;
66
67 llist_for_each_entry(trans, &net->trans_list, entry) {
68 if (trans->callref == callref)
69 return trans;
70 }
71 return NULL;
72}
73
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030074/*! Find a transaction by SM-RP-MR (RP Message Reference)
Vadim Yanitskiy36c44b22019-01-23 21:22:27 +070075 * \param[in] net Network in which we should search
76 * \param[in] vsub Subscriber for which we should search
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030077 * \param[in] sm_rp_mr RP Message Reference (see GSM TS 04.11, section 8.2.3)
78 * \returns Matching transaction, NULL otherwise
79 */
Vadim Yanitskiy36c44b22019-01-23 21:22:27 +070080struct gsm_trans *trans_find_by_sm_rp_mr(const struct gsm_network *net,
81 const struct vlr_subscr *vsub,
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030082 uint8_t sm_rp_mr)
83{
Ivan Kluchnikov9bd4fd62015-12-21 12:05:56 +030084 struct gsm_trans *trans;
85
86 llist_for_each_entry(trans, &net->trans_list, entry) {
87 if (trans->vsub == vsub &&
88 trans->protocol == GSM48_PDISC_SMS &&
89 trans->sms.sm_rp_mr == sm_rp_mr)
90 return trans;
91 }
92
93 return NULL;
94}
95
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +010096static const char *trans_vsub_use(uint8_t proto)
97{
98 return get_value_string_or_null(gsm48_pdisc_names, proto) ? : "trans-proto-unknown";
99}
100
Harald Welte2483f1b2016-06-19 18:06:02 +0200101/*! Allocate a new transaction and add it to network list
102 * \param[in] net Netwokr in which we allocate transaction
103 * \param[in] subscr Subscriber for which we allocate transaction
104 * \param[in] protocol Protocol (CC/SMS/...)
105 * \param[in] callref Call Reference
106 * \returns Transaction
107 */
Jacob Erlbeckaf792d62014-12-02 14:22:53 +0100108struct gsm_trans *trans_alloc(struct gsm_network *net,
Harald Welte2483f1b2016-06-19 18:06:02 +0200109 struct vlr_subscr *vsub,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200110 uint8_t protocol, uint8_t trans_id,
111 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +0200112{
113 struct gsm_trans *trans;
114
Benoit Bolseee7cf5e72017-07-05 12:34:18 +0200115 /* a valid subscriber is indispensable */
116 if (vsub == NULL) {
Max3614fd62019-01-17 13:38:10 +0100117 LOGP(DVLR, LOGL_ERROR,
Benoit Bolseee7cf5e72017-07-05 12:34:18 +0200118 "unable to alloc transaction, invalid subscriber (NULL)\n");
119 return NULL;
120 }
121
Neels Hofmeyrd1ec1112017-11-22 01:58:00 +0100122 DEBUGP(DCC, "(ti %02x sub %s callref %x) New transaction\n",
123 trans_id, vlr_subscr_name(vsub), callref);
124
Harald Welte9ee48252009-07-23 21:25:08 +0200125 trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
126 if (!trans)
127 return NULL;
128
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100129 vlr_subscr_get(vsub, trans_vsub_use(protocol));
130 trans->vsub = vsub;
Harald Welte9ee48252009-07-23 21:25:08 +0200131 trans->protocol = protocol;
132 trans->transaction_id = trans_id;
133 trans->callref = callref;
134
Jacob Erlbeckf07c6052014-12-02 11:58:00 +0100135 trans->net = net;
136 llist_add_tail(&trans->entry, &net->trans_list);
Harald Welte9ee48252009-07-23 21:25:08 +0200137
138 return trans;
139}
140
Harald Welte2483f1b2016-06-19 18:06:02 +0200141/*! Release a transaction
142 * \param[in] trans Transaction to be released
143 */
Harald Welte9ee48252009-07-23 21:25:08 +0200144void trans_free(struct gsm_trans *trans)
145{
Vadim Yanitskiye4574f02019-01-25 19:23:25 +0700146 enum ran_conn_use conn_usage_token;
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100147 struct ran_conn *conn;
Neels Hofmeyr6166f292017-11-22 14:33:12 +0100148
Harald Welte9ee48252009-07-23 21:25:08 +0200149 switch (trans->protocol) {
150 case GSM48_PDISC_CC:
151 _gsm48_cc_trans_free(trans);
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100152 conn_usage_token = RAN_CONN_USE_TRANS_CC;
Harald Welte9ee48252009-07-23 21:25:08 +0200153 break;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200154 case GSM48_PDISC_SMS:
155 _gsm411_sms_trans_free(trans);
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100156 conn_usage_token = RAN_CONN_USE_TRANS_SMS;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200157 break;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700158 case GSM48_PDISC_NC_SS:
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700159 _gsm911_nc_ss_trans_free(trans);
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100160 conn_usage_token = RAN_CONN_USE_TRANS_NC_SS;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700161 break;
Vadim Yanitskiye4574f02019-01-25 19:23:25 +0700162 default:
163 conn_usage_token = RAN_CONN_USE_UNTRACKED;
164 break;
Harald Welte9ee48252009-07-23 21:25:08 +0200165 }
166
Holger Hans Peter Freytherd6d7aff2015-04-06 12:03:45 +0200167 if (trans->paging_request) {
168 subscr_remove_request(trans->paging_request);
Holger Hans Peter Freyther49b3ed22010-12-29 17:09:07 +0100169 trans->paging_request = NULL;
Harald Welte9ee48252009-07-23 21:25:08 +0200170 }
171
Harald Welte2483f1b2016-06-19 18:06:02 +0200172 if (trans->vsub) {
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100173 vlr_subscr_put(trans->vsub, trans_vsub_use(trans->protocol));
Harald Welte2483f1b2016-06-19 18:06:02 +0200174 trans->vsub = NULL;
Holger Hans Peter Freyther405824c2012-12-22 18:16:47 +0100175 }
Harald Welte9ee48252009-07-23 21:25:08 +0200176
Neels Hofmeyrd6a769b2018-03-12 23:59:07 +0100177 conn = trans->conn;
Holger Hans Peter Freyther8effcb72013-12-27 18:07:23 +0100178 trans->conn = NULL;
Neels Hofmeyre3d3dc62018-03-31 00:02:14 +0200179 llist_del(&trans->entry);
Harald Welte9ee48252009-07-23 21:25:08 +0200180 talloc_free(trans);
Neels Hofmeyrd6a769b2018-03-12 23:59:07 +0100181
Neels Hofmeyre3d3dc62018-03-31 00:02:14 +0200182 if (conn)
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100183 ran_conn_put(conn, conn_usage_token);
Harald Welte9ee48252009-07-23 21:25:08 +0200184}
185
Harald Welte2483f1b2016-06-19 18:06:02 +0200186/*! allocate an unused transaction ID for the given subscriber
Max30fb97a2019-01-10 17:25:33 +0100187 * in the given protocol using TI flag = 0 (allocated by us).
188 * See GSM 04.07, section 11.2.3.1.3 "Transaction identifier".
Harald Welte2483f1b2016-06-19 18:06:02 +0200189 * \param[in] net GSM network
Vadim Yanitskiybaeeb902019-02-14 16:41:30 +0700190 * \param[in] subscr Subscriber for which to assign a new TID
191 * \param[in] protocol Protocol of to be assigned TID
Harald Welte2483f1b2016-06-19 18:06:02 +0200192 */
Max7916ca12019-01-02 11:48:14 +0100193int trans_assign_trans_id(const struct gsm_network *net, const struct vlr_subscr *vsub,
Max30fb97a2019-01-10 17:25:33 +0100194 uint8_t protocol)
Harald Welte9ee48252009-07-23 21:25:08 +0200195{
Harald Welte9ee48252009-07-23 21:25:08 +0200196 struct gsm_trans *trans;
197 unsigned int used_tid_bitmask = 0;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100198 int i, j, h;
Harald Welte78283ef2009-07-23 21:36:44 +0200199
Harald Welte9ee48252009-07-23 21:25:08 +0200200 /* generate bitmask of already-used TIDs for this (subscr,proto) */
201 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welte2483f1b2016-06-19 18:06:02 +0200202 if (trans->vsub != vsub ||
Harald Welte9ee48252009-07-23 21:25:08 +0200203 trans->protocol != protocol ||
Maxd8daaae2019-02-14 16:54:10 +0700204 trans->transaction_id == TRANS_ID_UNASSIGNED)
Harald Welte9ee48252009-07-23 21:25:08 +0200205 continue;
206 used_tid_bitmask |= (1 << trans->transaction_id);
207 }
208
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100209 /* find a new one, trying to go in a 'circular' pattern */
210 for (h = 6; h > 0; h--)
Max30fb97a2019-01-10 17:25:33 +0100211 if (used_tid_bitmask & (1 << h))
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100212 break;
Sylvain Munautb9f3dce2009-12-18 18:28:11 +0100213 for (i = 0; i < 7; i++) {
Max30fb97a2019-01-10 17:25:33 +0100214 j = (h + i) % 7;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100215 if ((used_tid_bitmask & (1 << j)) == 0)
216 return j;
Harald Welte78283ef2009-07-23 21:36:44 +0200217 }
218
219 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200220}
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100221
Harald Welte2483f1b2016-06-19 18:06:02 +0200222/*! Check if we have any transaction for given connection
223 * \param[in] conn Connection to check
Maxc065ca32019-01-14 11:51:28 +0100224 * \returns transaction pointer if found, NULL otherwise
Harald Welte2483f1b2016-06-19 18:06:02 +0200225 */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100226struct gsm_trans *trans_has_conn(const struct ran_conn *conn)
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100227{
228 struct gsm_trans *trans;
229
Neels Hofmeyra9f2bb52016-05-09 21:09:47 +0200230 llist_for_each_entry(trans, &conn->network->trans_list, entry)
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100231 if (trans->conn == conn)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200232 return trans;
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100233
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200234 return NULL;
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100235}
Harald Welte2483f1b2016-06-19 18:06:02 +0200236
237/*! Free all transactions associated with a connection, presumably when the
238 * conn is being closed. The transaction code will inform the CC or SMS
239 * facilities, which will then send the necessary release indications.
240 * \param[in] conn Connection that is going to be closed.
241 */
Max7916ca12019-01-02 11:48:14 +0100242void trans_conn_closed(const struct ran_conn *conn)
Harald Welte2483f1b2016-06-19 18:06:02 +0200243{
244 struct gsm_trans *trans;
245
246 /* As part of the CC REL_IND the remote leg might be released and this
247 * will trigger another call to trans_free. This is something the llist
248 * macro can not handle and we need to re-iterate the list every time.
249 */
250restart:
251 llist_for_each_entry(trans, &conn->network->trans_list, entry) {
252 if (trans->conn == conn) {
253 trans_free(trans);
254 goto restart;
255 }
256 }
257}