blob: d6520c313c6db1b38a47b91bc24a7e2f11c69678 [file] [log] [blame]
Jacob Erlbecke04e0b02015-05-06 18:30:48 +02001/* gprs_ms.cpp
2 *
3 * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
4 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21
22#include "gprs_ms.h"
23
24#include "tbf.h"
25#include "gprs_debug.h"
26
27extern "C" {
28 #include <osmocom/core/talloc.h>
29 #include <osmocom/core/utils.h>
30}
31
32extern void *tall_pcu_ctx;
33
34struct GprsMsDefaultCallback: public GprsMs::Callback {
35 virtual void ms_idle(class GprsMs *ms) {
36 delete ms;
37 }
38 virtual void ms_active(class GprsMs *) {}
39};
40
41static GprsMsDefaultCallback gprs_default_cb;
42
43
44GprsMs::Guard::Guard(GprsMs *ms) : m_ms(ms)
45{
46 if (m_ms)
47 m_ms->ref();
48}
49
50GprsMs::Guard::~Guard()
51{
52 if (m_ms)
53 m_ms->unref();
54}
55
56GprsMs::GprsMs(uint32_t tlli) :
57 m_cb(&gprs_default_cb),
58 m_ul_tbf(NULL),
59 m_dl_tbf(NULL),
60 m_tlli(tlli),
Jacob Erlbeck93990462015-05-15 15:50:43 +020061 m_new_ul_tlli(0),
62 m_new_dl_tlli(0),
Jacob Erlbeck9200ce62015-05-22 17:48:04 +020063 m_ta(0),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020064 m_is_idle(true),
Jacob Erlbeck53670862015-05-12 17:54:33 +020065 m_ref(0),
66 m_list(this)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020067{
68 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +020069
70 m_imsi[0] = 0;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020071}
72
73GprsMs::~GprsMs()
74{
75 LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());
Jacob Erlbeckfecece02015-05-08 12:13:08 +020076
77 if (m_ul_tbf) {
78 m_ul_tbf->set_ms(NULL);
79 m_ul_tbf = NULL;
80 }
81
82 if (m_dl_tbf) {
83 m_dl_tbf->set_ms(NULL);
84 m_dl_tbf = NULL;
85 }
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020086}
87
88void* GprsMs::operator new(size_t size)
89{
90 static void *tall_ms_ctx = NULL;
91 if (!tall_ms_ctx)
92 tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);
93
94 return talloc_size(tall_ms_ctx, size);
95}
96
97void GprsMs::operator delete(void* p)
98{
99 talloc_free(p);
100}
101
102void GprsMs::ref()
103{
104 m_ref += 1;
105}
106
107void GprsMs::unref()
108{
109 OSMO_ASSERT(m_ref >= 0);
110 m_ref -= 1;
111 if (m_ref == 0)
112 update_status();
113}
114
115void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
116{
117 if (tbf->direction == GPRS_RLCMAC_DL_TBF)
118 attach_dl_tbf(static_cast<gprs_rlcmac_dl_tbf *>(tbf));
119 else
120 attach_ul_tbf(static_cast<gprs_rlcmac_ul_tbf *>(tbf));
121}
122
123void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
124{
125 if (m_ul_tbf == tbf)
126 return;
127
128 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
129 tlli(), tbf->name());
130
131 Guard guard(this);
132
133 if (m_ul_tbf)
134 detach_tbf(m_ul_tbf);
135
136 m_ul_tbf = tbf;
137}
138
139void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)
140{
141 if (m_dl_tbf == tbf)
142 return;
143
144 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
145 tlli(), tbf->name());
146
147 Guard guard(this);
148
149 if (m_dl_tbf)
150 detach_tbf(m_dl_tbf);
151
152 m_dl_tbf = tbf;
153}
154
155void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
156{
157 if (m_ul_tbf && tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf))
158 m_ul_tbf = NULL;
159 else if (m_dl_tbf && tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf))
160 m_dl_tbf = NULL;
161 else
162 return;
163
164 LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
165 tlli(), tbf->name());
166
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200167 if (tbf->ms() == this)
168 tbf->set_ms(NULL);
169
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200170 update_status();
171}
172
173void GprsMs::update_status()
174{
175 if (m_ref > 0)
176 return;
177
178 if (is_idle() && !m_is_idle) {
179 m_is_idle = true;
180 m_cb->ms_idle(this);
181 /* this can be deleted by now, do not access it */
182 return;
183 }
184
185 if (!is_idle() && m_is_idle) {
186 m_is_idle = false;
187 m_cb->ms_active(this);
188 }
189}
190
191void GprsMs::set_tlli(uint32_t tlli)
192{
Jacob Erlbeck93990462015-05-15 15:50:43 +0200193 if (tlli == m_tlli || tlli == m_new_ul_tlli)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200194 return;
195
Jacob Erlbeck93990462015-05-15 15:50:43 +0200196 if (tlli != m_new_dl_tlli) {
197 LOGP(DRLCMAC, LOGL_INFO,
198 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
199 "not yet confirmed\n",
200 this->tlli(), tlli);
201 m_new_ul_tlli = tlli;
202 return;
203 }
204
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200205 LOGP(DRLCMAC, LOGL_INFO,
Jacob Erlbeck93990462015-05-15 15:50:43 +0200206 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
207 "already confirmed partly\n",
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200208 m_tlli, tlli);
209
210 m_tlli = tlli;
Jacob Erlbeck93990462015-05-15 15:50:43 +0200211 m_new_dl_tlli = 0;
212 m_new_ul_tlli = 0;
213}
214
215bool GprsMs::confirm_tlli(uint32_t tlli)
216{
217 if (tlli == m_tlli || tlli == m_new_dl_tlli)
218 return false;
219
220 if (tlli != m_new_ul_tlli) {
221 /* The MS has not sent a message with the new TLLI, which may
222 * happen according to the spec [TODO: add reference]. */
223
224 LOGP(DRLCMAC, LOGL_INFO,
225 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
226 "partly confirmed\n", tlli);
227 /* Use the network's idea of TLLI as candidate, this does not
228 * change the result value of tlli() */
229 m_new_dl_tlli = tlli;
230 return false;
231 }
232
233 LOGP(DRLCMAC, LOGL_INFO,
234 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
235
236 m_tlli = tlli;
237 m_new_dl_tlli = 0;
238 m_new_ul_tlli = 0;
239
240 return true;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200241}
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200242
243void GprsMs::set_imsi(const char *imsi)
244{
245 if (!imsi) {
246 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
247 return;
248 }
249
250 if (imsi[0] && strlen(imsi) < 3) {
251 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
252 imsi);
253 return;
254 }
255
256 if (strcmp(imsi, m_imsi) == 0)
257 return;
258
259 LOGP(DRLCMAC, LOGL_INFO,
260 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
261 tlli(), m_imsi, imsi);
262
263 strncpy(m_imsi, imsi, sizeof(m_imsi));
264 m_imsi[sizeof(m_imsi) - 1] = '\0';
265}
266
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200267void GprsMs::set_ta(uint8_t ta_)
268{
269 if (ta_ == m_ta)
270 return;
271
272 LOGP(DRLCMAC, LOGL_INFO,
273 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
274 tlli(), m_ta, ta_);
275
276 m_ta = ta_;
277}
278