blob: 59414a4a0dcd7a2f7ffb297c98e5705516c22b29 [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
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <openbsc/transaction.h>
23#include <openbsc/gsm_data.h>
24#include <openbsc/mncc.h>
25#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010026#include <osmocore/talloc.h>
Harald Welte9ee48252009-07-23 21:25:08 +020027#include <openbsc/gsm_subscriber.h>
28#include <openbsc/gsm_04_08.h>
29#include <openbsc/mncc.h>
30#include <openbsc/paging.h>
Holger Hans Peter Freyther88519ea2010-06-30 12:44:07 +080031#include <openbsc/osmo_msc.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);
36
Harald Welteb8b40732009-07-23 21:58:40 +020037struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
38 u_int8_t proto, u_int8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020039{
40 struct gsm_trans *trans;
Harald Welteb8b40732009-07-23 21:58:40 +020041 struct gsm_network *net = subscr->net;
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,
53 u_int32_t callref)
54{
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
64struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
65 u_int8_t protocol, u_int8_t trans_id,
66 u_int32_t callref)
67{
68 struct gsm_trans *trans;
69
70 DEBUGP(DCC, "subscr=%p, subscr->net=%p\n", subscr, subscr->net);
71
72 trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
73 if (!trans)
74 return NULL;
75
76 trans->subscr = subscr;
77 subscr_get(trans->subscr);
78
79 trans->protocol = protocol;
80 trans->transaction_id = trans_id;
81 trans->callref = callref;
82
83 llist_add_tail(&trans->entry, &subscr->net->trans_list);
84
85 return trans;
86}
87
88void trans_free(struct gsm_trans *trans)
89{
Harald Welte9ee48252009-07-23 21:25:08 +020090 switch (trans->protocol) {
91 case GSM48_PDISC_CC:
92 _gsm48_cc_trans_free(trans);
93 break;
Harald Welte (local)86b17172009-08-14 14:52:17 +020094 case GSM48_PDISC_SMS:
95 _gsm411_sms_trans_free(trans);
96 break;
Harald Welte9ee48252009-07-23 21:25:08 +020097 }
98
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +010099 if (!trans->conn && trans->subscr && trans->subscr->net) {
Harald Welte9ee48252009-07-23 21:25:08 +0200100 /* Stop paging on all bts' */
Holger Hans Peter Freyther927f0562009-08-21 05:43:44 +0200101 paging_request_stop(NULL, trans->subscr, NULL);
Harald Welte9ee48252009-07-23 21:25:08 +0200102 }
103
104 if (trans->subscr)
105 subscr_put(trans->subscr);
106
107 llist_del(&trans->entry);
108
Holger Hans Peter Freyther40494552010-06-28 17:09:29 +0800109 if (trans->conn)
110 msc_release_connection(trans->conn);
111
112
Harald Welte9ee48252009-07-23 21:25:08 +0200113 talloc_free(trans);
114}
115
Harald Welte78283ef2009-07-23 21:36:44 +0200116/* allocate an unused transaction ID for the given subscriber
117 * in the given protocol using the ti_flag specified */
Harald Welte9ee48252009-07-23 21:25:08 +0200118int trans_assign_trans_id(struct gsm_subscriber *subscr,
119 u_int8_t protocol, u_int8_t ti_flag)
120{
121 struct gsm_network *net = subscr->net;
122 struct gsm_trans *trans;
123 unsigned int used_tid_bitmask = 0;
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100124 int i, j, h;
Harald Welte78283ef2009-07-23 21:36:44 +0200125
126 if (ti_flag)
127 ti_flag = 0x8;
Harald Welte9ee48252009-07-23 21:25:08 +0200128
129 /* generate bitmask of already-used TIDs for this (subscr,proto) */
130 llist_for_each_entry(trans, &net->trans_list, entry) {
131 if (trans->subscr != subscr ||
132 trans->protocol != protocol ||
133 trans->transaction_id == 0xff)
134 continue;
135 used_tid_bitmask |= (1 << trans->transaction_id);
136 }
137
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100138 /* find a new one, trying to go in a 'circular' pattern */
139 for (h = 6; h > 0; h--)
140 if (used_tid_bitmask & (1 << (h | ti_flag)))
141 break;
Sylvain Munautb9f3dce2009-12-18 18:28:11 +0100142 for (i = 0; i < 7; i++) {
Sylvain Munaut926fcec2009-12-24 13:26:17 +0100143 j = ((h + i) % 7) | ti_flag;
144 if ((used_tid_bitmask & (1 << j)) == 0)
145 return j;
Harald Welte78283ef2009-07-23 21:36:44 +0200146 }
147
148 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200149}
Harald Weltecc9beb52009-12-17 17:13:28 +0100150