blob: dba4bed1717877274dd3be87451ba48023887cae [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_subscriber.h>
27#include <openbsc/gsm_04_08.h>
28#include <openbsc/mncc.h>
29#include <openbsc/paging.h>
Holger Hans Peter Freyther88519ea2010-06-30 12:44:07 +080030#include <openbsc/osmo_msc.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
Jacob Erlbeckdae1f642014-12-02 14:22:53 +010036struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020037 uint8_t proto, uint8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020038{
39 struct gsm_trans *trans;
Neels Hofmeyra9f2bb52016-05-09 21:09:47 +020040 struct gsm_network *net = conn->network;
Jacob Erlbeckdae1f642014-12-02 14:22:53 +010041 struct gsm_subscriber *subscr = conn->subscr;
Harald Welte9ee48252009-07-23 21:25:08 +020042
43 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welteb8b40732009-07-23 21:58:40 +020044 if (trans->subscr == subscr &&
45 trans->protocol == proto &&
46 trans->transaction_id == trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020047 return trans;
48 }
49 return NULL;
50}
51
52struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020053 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +020054{
55 struct gsm_trans *trans;
56
57 llist_for_each_entry(trans, &net->trans_list, entry) {
58 if (trans->callref == callref)
59 return trans;
60 }
61 return NULL;
62}
63
Jacob Erlbeckaf792d62014-12-02 14:22:53 +010064struct gsm_trans *trans_alloc(struct gsm_network *net,
65 struct gsm_subscriber *subscr,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020066 uint8_t protocol, uint8_t trans_id,
67 uint32_t callref)
Harald Welte9ee48252009-07-23 21:25:08 +020068{
69 struct gsm_trans *trans;
70
Jacob Erlbeckf07c6052014-12-02 11:58:00 +010071 DEBUGP(DCC, "subscr=%p, net=%p\n", subscr, net);
Harald Welte9ee48252009-07-23 21:25:08 +020072
73 trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
74 if (!trans)
75 return NULL;
76
77 trans->subscr = subscr;
78 subscr_get(trans->subscr);
79
80 trans->protocol = protocol;
81 trans->transaction_id = trans_id;
82 trans->callref = callref;
83
Jacob Erlbeckf07c6052014-12-02 11:58:00 +010084 trans->net = net;
85 llist_add_tail(&trans->entry, &net->trans_list);
Harald Welte9ee48252009-07-23 21:25:08 +020086
87 return trans;
88}
89
90void trans_free(struct gsm_trans *trans)
91{
Harald Welte9ee48252009-07-23 21:25:08 +020092 switch (trans->protocol) {
93 case GSM48_PDISC_CC:
94 _gsm48_cc_trans_free(trans);
95 break;
Harald Welte (local)86b17172009-08-14 14:52:17 +020096 case GSM48_PDISC_SMS:
97 _gsm411_sms_trans_free(trans);
98 break;
Harald Welte9ee48252009-07-23 21:25:08 +020099 }
100
Holger Hans Peter Freytherd6d7aff2015-04-06 12:03:45 +0200101 if (trans->paging_request) {
102 subscr_remove_request(trans->paging_request);
Holger Hans Peter Freyther49b3ed22010-12-29 17:09:07 +0100103 trans->paging_request = NULL;
Harald Welte9ee48252009-07-23 21:25:08 +0200104 }
105
Holger Hans Peter Freyther405824c2012-12-22 18:16:47 +0100106 if (trans->subscr) {
Harald Welte9ee48252009-07-23 21:25:08 +0200107 subscr_put(trans->subscr);
Holger Hans Peter Freyther405824c2012-12-22 18:16:47 +0100108 trans->subscr = NULL;
109 }
Harald Welte9ee48252009-07-23 21:25:08 +0200110
111 llist_del(&trans->entry);
112
Holger Hans Peter Freyther40494552010-06-28 17:09:29 +0800113 if (trans->conn)
114 msc_release_connection(trans->conn);
115
Holger Hans Peter Freyther8effcb72013-12-27 18:07:23 +0100116 trans->conn = NULL;
Harald Welte9ee48252009-07-23 21:25:08 +0200117 talloc_free(trans);
118}
119
Harald Welte78283ef2009-07-23 21:36:44 +0200120/* allocate an unused transaction ID for the given subscriber
121 * in the given protocol using the ti_flag specified */
Jacob Erlbeckdae1f642014-12-02 14:22:53 +0100122int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200123 uint8_t protocol, uint8_t ti_flag)
Harald Welte9ee48252009-07-23 21:25:08 +0200124{
Harald Welte9ee48252009-07-23 21:25:08 +0200125 struct gsm_trans *trans;
126 unsigned int used_tid_bitmask = 0;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100127 int i, j, h;
Harald Welte78283ef2009-07-23 21:36:44 +0200128
129 if (ti_flag)
130 ti_flag = 0x8;
Harald Welte9ee48252009-07-23 21:25:08 +0200131
132 /* generate bitmask of already-used TIDs for this (subscr,proto) */
133 llist_for_each_entry(trans, &net->trans_list, entry) {
134 if (trans->subscr != subscr ||
135 trans->protocol != protocol ||
136 trans->transaction_id == 0xff)
137 continue;
138 used_tid_bitmask |= (1 << trans->transaction_id);
139 }
140
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100141 /* find a new one, trying to go in a 'circular' pattern */
142 for (h = 6; h > 0; h--)
143 if (used_tid_bitmask & (1 << (h | ti_flag)))
144 break;
Sylvain Munautb9f3dce2009-12-18 18:28:11 +0100145 for (i = 0; i < 7; i++) {
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100146 j = ((h + i) % 7) | ti_flag;
147 if ((used_tid_bitmask & (1 << j)) == 0)
148 return j;
Harald Welte78283ef2009-07-23 21:36:44 +0200149 }
150
151 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200152}
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100153
154int trans_has_conn(const struct gsm_subscriber_connection *conn)
155{
156 struct gsm_trans *trans;
157
Neels Hofmeyra9f2bb52016-05-09 21:09:47 +0200158 llist_for_each_entry(trans, &conn->network->trans_list, entry)
Holger Hans Peter Freyther70ae5d32012-11-23 21:33:15 +0100159 if (trans->conn == conn)
160 return 1;
161
162 return 0;
163}