blob: 7289a8f1174d7e630e970df9bdc77bf9a1f6b2c5 [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
21#include <openbsc/transaction.h>
22#include <openbsc/gsm_data.h>
23#include <openbsc/mncc.h>
24#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010025#include <osmocom/core/talloc.h>
Harald Welte9ee48252009-07-23 21:25:08 +020026#include <openbsc/gsm_04_08.h>
27#include <openbsc/mncc.h>
28#include <openbsc/paging.h>
Holger Hans Peter Freyther88519ea2010-06-30 12:44:07 +080029#include <openbsc/osmo_msc.h>
Harald Welte7b423ed2016-06-19 18:06:02 +020030#include <openbsc/vlr.h>
Harald Welte9ee48252009-07-23 21:25:08 +020031
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020032void *tall_trans_ctx;
Harald Welte9ee48252009-07-23 21:25:08 +020033
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020034void _gsm48_cc_trans_free(struct gsm_trans *trans);
35
Harald Welte7b423ed2016-06-19 18:06:02 +020036/*! Find a transaction in connection for given protocol + transaction ID
37 * \param[in] conn Connection in whihc we want to find transaction
38 * \param[in] proto Protocol of transaction
39 * \param[in] trans_id Transaction ID of transaction
40 * \returns Matching transaction, if any
41 */
Jacob Erlbeckdae1f642014-12-02 14:22:53 +010042struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020043 uint8_t proto, uint8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020044{
45 struct gsm_trans *trans;
Neels Hofmeyra9f2bb52016-05-09 21:09:47 +020046 struct gsm_network *net = conn->network;
Harald Welte7b423ed2016-06-19 18:06:02 +020047 struct vlr_subscr *vsub = conn->vsub;
Harald Welte9ee48252009-07-23 21:25:08 +020048
49 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welte7b423ed2016-06-19 18:06:02 +020050 if (trans->vsub == vsub &&
Harald Welteb8b40732009-07-23 21:58:40 +020051 trans->protocol == proto &&
52 trans->transaction_id == trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020053 return trans;
54 }
55 return NULL;
56}
57
Harald Welte7b423ed2016-06-19 18:06:02 +020058/*! Find a transaction by call reference
59 * \param[in] net Network in which we should search
60 * \param[in] callref Call Reference of transaction
61 * \returns Matching transaction, if any
62 */
Harald Welte9ee48252009-07-23 21:25:08 +020063struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020064 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +020065{
66 struct gsm_trans *trans;
67
68 llist_for_each_entry(trans, &net->trans_list, entry) {
69 if (trans->callref == callref)
70 return trans;
71 }
72 return NULL;
73}
74
Harald Welte7b423ed2016-06-19 18:06:02 +020075/*! Allocate a new transaction and add it to network list
76 * \param[in] net Netwokr in which we allocate transaction
77 * \param[in] subscr Subscriber for which we allocate transaction
78 * \param[in] protocol Protocol (CC/SMS/...)
79 * \param[in] callref Call Reference
80 * \returns Transaction
81 */
Jacob Erlbeckaf792d62014-12-02 14:22:53 +010082struct gsm_trans *trans_alloc(struct gsm_network *net,
Harald Welte7b423ed2016-06-19 18:06:02 +020083 struct vlr_subscr *vsub,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020084 uint8_t protocol, uint8_t trans_id,
85 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +020086{
87 struct gsm_trans *trans;
88
Harald Welte7b423ed2016-06-19 18:06:02 +020089 DEBUGP(DCC, "subscr=%p, net=%p\n", vsub, net);
Harald Welte9ee48252009-07-23 21:25:08 +020090
91 trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
92 if (!trans)
93 return NULL;
94
Harald Welte7b423ed2016-06-19 18:06:02 +020095 trans->vsub = vlr_subscr_get(vsub);
Harald Welte9ee48252009-07-23 21:25:08 +020096
97 trans->protocol = protocol;
98 trans->transaction_id = trans_id;
99 trans->callref = callref;
100
Jacob Erlbeckf07c6052014-12-02 11:58:00 +0100101 trans->net = net;
102 llist_add_tail(&trans->entry, &net->trans_list);
Harald Welte9ee48252009-07-23 21:25:08 +0200103
104 return trans;
105}
106
Harald Welte7b423ed2016-06-19 18:06:02 +0200107/*! Release a transaction
108 * \param[in] trans Transaction to be released
109 */
Harald Welte9ee48252009-07-23 21:25:08 +0200110void trans_free(struct gsm_trans *trans)
111{
Harald Welte9ee48252009-07-23 21:25:08 +0200112 switch (trans->protocol) {
113 case GSM48_PDISC_CC:
114 _gsm48_cc_trans_free(trans);
115 break;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200116 case GSM48_PDISC_SMS:
117 _gsm411_sms_trans_free(trans);
118 break;
Harald Welte9ee48252009-07-23 21:25:08 +0200119 }
120
Holger Hans Peter Freytherd6d7aff2015-04-06 12:03:45 +0200121 if (trans->paging_request) {
122 subscr_remove_request(trans->paging_request);
Holger Hans Peter Freyther49b3ed22010-12-29 17:09:07 +0100123 trans->paging_request = NULL;
Harald Welte9ee48252009-07-23 21:25:08 +0200124 }
125
Harald Welte7b423ed2016-06-19 18:06:02 +0200126 if (trans->vsub) {
127 vlr_subscr_put(trans->vsub);
128 trans->vsub = NULL;
Holger Hans Peter Freyther405824c2012-12-22 18:16:47 +0100129 }
Harald Welte9ee48252009-07-23 21:25:08 +0200130
131 llist_del(&trans->entry);
132
Holger Hans Peter Freyther40494552010-06-28 17:09:29 +0800133 if (trans->conn)
Harald Welte7b423ed2016-06-19 18:06:02 +0200134 msc_subscr_conn_put(trans->conn);
Holger Hans Peter Freyther40494552010-06-28 17:09:29 +0800135
Holger Hans Peter Freyther8effcb72013-12-27 18:07:23 +0100136 trans->conn = NULL;
Harald Welte9ee48252009-07-23 21:25:08 +0200137 talloc_free(trans);
138}
139
Harald Welte7b423ed2016-06-19 18:06:02 +0200140/*! allocate an unused transaction ID for the given subscriber
141 * in the given protocol using the ti_flag specified
142 * \param[in] net GSM network
143 * \param[in] subscr Subscriber for which to find ID
144 * \param[in] protocol Protocol for whihc to find ID
145 * \param[in] ti_flag FIXME
146 */
147int trans_assign_trans_id(struct gsm_network *net, struct vlr_subscr *vsub,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200148 uint8_t protocol, uint8_t ti_flag)
Harald Welte9ee48252009-07-23 21:25:08 +0200149{
Harald Welte9ee48252009-07-23 21:25:08 +0200150 struct gsm_trans *trans;
151 unsigned int used_tid_bitmask = 0;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100152 int i, j, h;
Harald Welte78283ef2009-07-23 21:36:44 +0200153
154 if (ti_flag)
155 ti_flag = 0x8;
Harald Welte9ee48252009-07-23 21:25:08 +0200156
157 /* generate bitmask of already-used TIDs for this (subscr,proto) */
158 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welte7b423ed2016-06-19 18:06:02 +0200159 if (trans->vsub != vsub ||
Harald Welte9ee48252009-07-23 21:25:08 +0200160 trans->protocol != protocol ||
161 trans->transaction_id == 0xff)
162 continue;
163 used_tid_bitmask |= (1 << trans->transaction_id);
164 }
165
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100166 /* find a new one, trying to go in a 'circular' pattern */
167 for (h = 6; h > 0; h--)
168 if (used_tid_bitmask & (1 << (h | ti_flag)))
169 break;
Sylvain Munautb9f3dce2009-12-18 18:28:11 +0100170 for (i = 0; i < 7; i++) {
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100171 j = ((h + i) % 7) | ti_flag;
172 if ((used_tid_bitmask & (1 << j)) == 0)
173 return j;
Harald Welte78283ef2009-07-23 21:36:44 +0200174 }
175
176 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200177}
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100178
Harald Welte7b423ed2016-06-19 18:06:02 +0200179/*! Check if we have any transaction for given connection
180 * \param[in] conn Connection to check
181 * \returns 1 in case there is a transaction, 0 otherwise
182 */
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200183struct gsm_trans *trans_has_conn(const struct gsm_subscriber_connection *conn)
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100184{
185 struct gsm_trans *trans;
186
Neels Hofmeyra9f2bb52016-05-09 21:09:47 +0200187 llist_for_each_entry(trans, &conn->network->trans_list, entry)
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100188 if (trans->conn == conn)
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200189 return trans;
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100190
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200191 return NULL;
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100192}
Harald Welte7b423ed2016-06-19 18:06:02 +0200193
194/*! Free all transactions associated with a connection, presumably when the
195 * conn is being closed. The transaction code will inform the CC or SMS
196 * facilities, which will then send the necessary release indications.
197 * \param[in] conn Connection that is going to be closed.
198 */
199void trans_conn_closed(struct gsm_subscriber_connection *conn)
200{
201 struct gsm_trans *trans;
202
203 /* As part of the CC REL_IND the remote leg might be released and this
204 * will trigger another call to trans_free. This is something the llist
205 * macro can not handle and we need to re-iterate the list every time.
206 */
207restart:
208 llist_for_each_entry(trans, &conn->network->trans_list, entry) {
209 if (trans->conn == conn) {
210 trans_free(trans);
211 goto restart;
212 }
213 }
214}