blob: 026928876bbfc22541d6d84cc9b7200495440cd1 [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
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 Welteb8b40732009-07-23 21:58:40 +020036struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
37 u_int8_t proto, u_int8_t trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020038{
39 struct gsm_trans *trans;
Harald Welteb8b40732009-07-23 21:58:40 +020040 struct gsm_network *net = subscr->net;
Harald Welte9ee48252009-07-23 21:25:08 +020041
42 llist_for_each_entry(trans, &net->trans_list, entry) {
Harald Welteb8b40732009-07-23 21:58:40 +020043 if (trans->subscr == subscr &&
44 trans->protocol == proto &&
45 trans->transaction_id == trans_id)
Harald Welte9ee48252009-07-23 21:25:08 +020046 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{
Harald Welte9ee48252009-07-23 21:25:08 +020089 switch (trans->protocol) {
90 case GSM48_PDISC_CC:
91 _gsm48_cc_trans_free(trans);
92 break;
Harald Welte (local)86b17172009-08-14 14:52:17 +020093 case GSM48_PDISC_SMS:
94 _gsm411_sms_trans_free(trans);
95 break;
Harald Welte9ee48252009-07-23 21:25:08 +020096 }
97
98 if (trans->lchan)
99 put_lchan(trans->lchan);
100
101 if (!trans->lchan && trans->subscr && trans->subscr->net) {
102 /* Stop paging on all bts' */
Holger Hans Peter Freyther927f0562009-08-21 05:43:44 +0200103 paging_request_stop(NULL, trans->subscr, NULL);
Harald Welte9ee48252009-07-23 21:25:08 +0200104 }
105
106 if (trans->subscr)
107 subscr_put(trans->subscr);
108
109 llist_del(&trans->entry);
110
111 talloc_free(trans);
112}
113
Harald Welte78283ef2009-07-23 21:36:44 +0200114/* allocate an unused transaction ID for the given subscriber
115 * in the given protocol using the ti_flag specified */
Harald Welte9ee48252009-07-23 21:25:08 +0200116int trans_assign_trans_id(struct gsm_subscriber *subscr,
117 u_int8_t protocol, u_int8_t ti_flag)
118{
119 struct gsm_network *net = subscr->net;
120 struct gsm_trans *trans;
121 unsigned int used_tid_bitmask = 0;
Harald Welte78283ef2009-07-23 21:36:44 +0200122 int i;
123
124 if (ti_flag)
125 ti_flag = 0x8;
Harald Welte9ee48252009-07-23 21:25:08 +0200126
127 /* generate bitmask of already-used TIDs for this (subscr,proto) */
128 llist_for_each_entry(trans, &net->trans_list, entry) {
129 if (trans->subscr != subscr ||
130 trans->protocol != protocol ||
131 trans->transaction_id == 0xff)
132 continue;
133 used_tid_bitmask |= (1 << trans->transaction_id);
134 }
135
Harald Welte78283ef2009-07-23 21:36:44 +0200136 for (i = 0; i <= 7; i++) {
137 if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0)
138 return i | ti_flag;
139 }
140
141 return -1;
Harald Welte9ee48252009-07-23 21:25:08 +0200142}
Harald Weltecc9beb52009-12-17 17:13:28 +0100143
144/* update all transactions to use a different LCHAN, e.g.
145 * after handover has succeeded */
146int trans_lchan_change(struct gsm_lchan *lchan_old,
147 struct gsm_lchan *lchan_new)
148{
149 struct gsm_network *net = lchan_old->ts->trx->bts->network;
150 struct gsm_trans *trans;
151 int num = 0;
152
153 llist_for_each_entry(trans, &net->trans_list, entry) {
154 if (trans->lchan == lchan_old) {
Harald Welte18750cf2009-12-18 14:51:48 +0100155 /* drop old channel use cound */
156 put_lchan(trans->lchan);
157 /* assign new channel */
Harald Weltecc9beb52009-12-17 17:13:28 +0100158 trans->lchan = lchan_new;
Harald Welte18750cf2009-12-18 14:51:48 +0100159 /* bump new channel use count */
160 use_lchan(trans->lchan);
Harald Weltecc9beb52009-12-17 17:13:28 +0100161 num++;
162 }
163 }
164
165 return num;
166}