blob: 9b4af1aacec6f539dddd7d7a8fa2fca436266e93 [file] [log] [blame]
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001/* 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
7 * 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
9 * (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
14 * GNU Affero General Public License for more details.
15 *
16 * 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/>.
18 *
19 */
20
21#include <openbsc/transaction.h>
22#include <openbsc/gsm_data.h>
23#include <openbsc/mncc.h>
24#include <openbsc/debug.h>
25#include <osmocore/talloc.h>
26#include <openbsc/gsm_subscriber.h>
27#include <openbsc/gsm_04_08.h>
28#include <openbsc/mncc.h>
29#include <openbsc/paging.h>
30#include <openbsc/osmo_msc.h>
31
32void *tall_trans_ctx;
33
34void _gsm48_cc_trans_free(struct gsm_trans *trans);
35
36struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
37 u_int8_t proto, u_int8_t trans_id)
38{
39 struct gsm_trans *trans;
40 struct gsm_network *net = subscr->net;
41
42 llist_for_each_entry(trans, &net->trans_list, entry) {
43 if (trans->subscr == subscr &&
44 trans->protocol == proto &&
45 trans->transaction_id == trans_id)
46 return trans;
47 }
48 return NULL;
49}
50
51struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
52 u_int32_t callref)
53{
54 struct gsm_trans *trans;
55
56 llist_for_each_entry(trans, &net->trans_list, entry) {
57 if (trans->callref == callref)
58 return trans;
59 }
60 return NULL;
61}
62
63struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
64 u_int8_t protocol, u_int8_t trans_id,
65 u_int32_t callref)
66{
67 struct gsm_trans *trans;
68
69 DEBUGP(DCC, "subscr=%p, subscr->net=%p\n", subscr, subscr->net);
70
71 trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
72 if (!trans)
73 return NULL;
74
75 trans->subscr = subscr;
76 subscr_get(trans->subscr);
77
78 trans->protocol = protocol;
79 trans->transaction_id = trans_id;
80 trans->callref = callref;
81
82 llist_add_tail(&trans->entry, &subscr->net->trans_list);
83
84 return trans;
85}
86
87void trans_free(struct gsm_trans *trans)
88{
89 switch (trans->protocol) {
90 case GSM48_PDISC_CC:
91 _gsm48_cc_trans_free(trans);
92 break;
93 case GSM48_PDISC_SMS:
94 _gsm411_sms_trans_free(trans);
95 break;
96 }
97
98 /* FIXME: implement a sane way to stop this. */
99 if (!trans->conn && trans->paging_request) {
100 LOGP(DNM, LOGL_ERROR,
101 "Transaction freed while paging for sub: %llu\n",
102 trans->subscr->id);
103 trans->paging_request = NULL;
104 }
105
106 if (trans->subscr)
107 subscr_put(trans->subscr);
108
109 llist_del(&trans->entry);
110
111 if (trans->conn)
112 msc_release_connection(trans->conn);
113
114
115 talloc_free(trans);
116}
117
118/* allocate an unused transaction ID for the given subscriber
119 * in the given protocol using the ti_flag specified */
120int trans_assign_trans_id(struct gsm_subscriber *subscr,
121 u_int8_t protocol, u_int8_t ti_flag)
122{
123 struct gsm_network *net = subscr->net;
124 struct gsm_trans *trans;
125 unsigned int used_tid_bitmask = 0;
126 int i, j, h;
127
128 if (ti_flag)
129 ti_flag = 0x8;
130
131 /* generate bitmask of already-used TIDs for this (subscr,proto) */
132 llist_for_each_entry(trans, &net->trans_list, entry) {
133 if (trans->subscr != subscr ||
134 trans->protocol != protocol ||
135 trans->transaction_id == 0xff)
136 continue;
137 used_tid_bitmask |= (1 << trans->transaction_id);
138 }
139
140 /* find a new one, trying to go in a 'circular' pattern */
141 for (h = 6; h > 0; h--)
142 if (used_tid_bitmask & (1 << (h | ti_flag)))
143 break;
144 for (i = 0; i < 7; i++) {
145 j = ((h + i) % 7) | ti_flag;
146 if ((used_tid_bitmask & (1 << j)) == 0)
147 return j;
148 }
149
150 return -1;
151}
152