blob: 9e7c7948f8ce57ca209f6a40e977e727c23a9c2a [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>
26#include <openbsc/talloc.h>
27#include <openbsc/gsm_subscriber.h>
28#include <openbsc/gsm_04_08.h>
29#include <openbsc/mncc.h>
30#include <openbsc/paging.h>
31
32static void *tall_trans_ctx;
33
Harald Welteb8b40732009-07-23 21:58:40 +020034struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
35 u_int8_t proto, u_int8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020036{
37 struct gsm_trans *trans;
Harald Welteb8b40732009-07-23 21:58:40 +020038 struct gsm_network *net = subscr->net;
Harald Welte9ee48252009-07-23 21:25:08 +020039
40 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welteb8b40732009-07-23 21:58:40 +020041 if (trans->subscr == subscr &&
42 trans->protocol == proto &&
43 trans->transaction_id == trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020044 return trans;
45 }
46 return NULL;
47}
48
49struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
50 u_int32_t callref)
51{
52 struct gsm_trans *trans;
53
54 llist_for_each_entry(trans, &net->trans_list, entry) {
55 if (trans->callref == callref)
56 return trans;
57 }
58 return NULL;
59}
60
61struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
62 u_int8_t protocol, u_int8_t trans_id,
63 u_int32_t callref)
64{
65 struct gsm_trans *trans;
66
67 DEBUGP(DCC, "subscr=%p, subscr->net=%p\n", subscr, subscr->net);
68
69 trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
70 if (!trans)
71 return NULL;
72
73 trans->subscr = subscr;
74 subscr_get(trans->subscr);
75
76 trans->protocol = protocol;
77 trans->transaction_id = trans_id;
78 trans->callref = callref;
79
80 llist_add_tail(&trans->entry, &subscr->net->trans_list);
81
82 return trans;
83}
84
85void trans_free(struct gsm_trans *trans)
86{
87 struct gsm_bts *bts;
88
89 switch (trans->protocol) {
90 case GSM48_PDISC_CC:
91 _gsm48_cc_trans_free(trans);
92 break;
93 }
94
95 if (trans->lchan)
96 put_lchan(trans->lchan);
97
98 if (!trans->lchan && trans->subscr && trans->subscr->net) {
99 /* Stop paging on all bts' */
100 bts = NULL;
101 do {
102 bts = gsm_bts_by_lac(trans->subscr->net,
103 trans->subscr->lac, bts);
104 if (!bts)
105 break;
106 /* Stop paging */
107 paging_request_stop(bts, trans->subscr, NULL);
108 } while (1);
109 }
110
111 if (trans->subscr)
112 subscr_put(trans->subscr);
113
114 llist_del(&trans->entry);
115
116 talloc_free(trans);
117}
118
Harald Welte78283ef2009-07-23 21:36:44 +0200119/* allocate an unused transaction ID for the given subscriber
120 * in the given protocol using the ti_flag specified */
Harald Welte9ee48252009-07-23 21:25:08 +0200121int trans_assign_trans_id(struct gsm_subscriber *subscr,
122 u_int8_t protocol, u_int8_t ti_flag)
123{
124 struct gsm_network *net = subscr->net;
125 struct gsm_trans *trans;
126 unsigned int used_tid_bitmask = 0;
Harald Welte78283ef2009-07-23 21:36:44 +0200127 int i;
128
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
Harald Welte78283ef2009-07-23 21:36:44 +0200141 for (i = 0; i <= 7; i++) {
142 if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0)
143 return i | ti_flag;
144 }
145
146 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200147}