blob: a57dd08545e24f04a6d2738649fc2fe8a400b632 [file] [log] [blame]
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +02001/* tbf_fsm.c
2 *
3 * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4 * Author: Pau Espin Pedrol <pespin@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#include <unistd.h>
22
23#include <talloc.h>
24
25#include <tbf_fsm.h>
26#include <gprs_rlcmac.h>
27#include <gprs_debug.h>
28#include <gprs_ms.h>
29#include <encoding.h>
30#include <bts.h>
31
32#define X(s) (1 << (s))
33
34const struct osmo_tdef_state_timeout tbf_fsm_timeouts[32] = {
35 [TBF_ST_NULL] = {},
36 [TBF_ST_ASSIGN] = { },
37 [TBF_ST_FLOW] = { },
38 [TBF_ST_FINISHED] = {},
39 [TBF_ST_WAIT_RELEASE] = {},
40 [TBF_ST_RELEASING] = {},
41};
42
43const struct value_string tbf_fsm_event_names[] = {
Pau Espin Pedrol33e80072021-07-22 19:20:50 +020044 { TBF_EV_ASSIGN_ADD_CCCH, "ASSIGN_ADD_CCCH" },
45 { TBF_EV_ASSIGN_ADD_PACCH, "ASSIGN_ADD_PACCH" },
46 { TBF_EV_ASSIGN_DEL_CCCH, "ASSIGN_DEL_CCCH" },
Pau Espin Pedrol720e19e2021-07-22 19:56:37 +020047 { TBF_EV_ASSIGN_ACK_PACCH, "ASSIGN_ACK_PACCH" },
48 { TBF_EV_ASSIGN_READY_CCCH, "ASSIGN_READY_CCCH" },
Pau Espin Pedrolc32c4a32021-07-23 18:27:57 +020049 { TBF_EV_LAST_DL_DATA_SENT, "LAST_DL_DATA_SENT" },
50 { TBF_EV_LAST_UL_DATA_RECVD, "LAST_UL_DATA_RECVD" },
Pau Espin Pedrolefcb0462021-07-26 12:33:39 +020051 { TBF_EV_FINAL_ACK_RECVD, "FINAL_ACK_RECVD" },
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +020052 { TBF_EV_MAX_N3101 , "MAX_N3101" },
53 { TBF_EV_MAX_N3103 , "MAX_N3103" },
54 { TBF_EV_MAX_N3105 , "MAX_N3105" },
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +020055 { 0, NULL }
56};
57
Pau Espin Pedrol33e80072021-07-22 19:20:50 +020058static void mod_ass_type(struct tbf_fsm_ctx *ctx, uint8_t t, bool set)
59{
60 const char *ch = "UNKNOWN";
61 bool prev_set = ctx->state_flags & (1 << t);
62
63 switch (t) {
64 case GPRS_RLCMAC_FLAG_CCCH:
65 ch = "CCCH";
66 break;
67 case GPRS_RLCMAC_FLAG_PACCH:
68 ch = "PACCH";
69 break;
70 default:
71 LOGPTBF(ctx->tbf, LOGL_ERROR,
72 "attempted to %sset unexpected ass. type %d - FIXME!\n",
73 set ? "" : "un", t);
74 return;
75 }
76
77 if (set && prev_set) {
78 LOGPTBF(ctx->tbf, LOGL_ERROR,
79 "attempted to set ass. type %s which is already set.\n", ch);
80 } else if (!set && !prev_set) {
81 return;
82 }
83
84 LOGPTBF(ctx->tbf, LOGL_INFO, "%sset ass. type %s [prev CCCH:%u, PACCH:%u]\n",
85 set ? "" : "un", ch,
86 !!(ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)),
87 !!(ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH)));
88
89 if (set) {
90 ctx->state_flags |= (1 << t);
91 } else {
92 ctx->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; /* keep to flags */
93 ctx->state_flags &= ~(1 << t);
94 }
95}
96
97
98static void st_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)
99{
100 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
101 switch (event) {
102 case TBF_EV_ASSIGN_ADD_CCCH:
103 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, true);
104 tbf_fsm_state_chg(fi, tbf_direction(ctx->tbf) == GPRS_RLCMAC_DL_TBF ?
105 TBF_ST_ASSIGN : TBF_ST_FLOW);
106 break;
107 case TBF_EV_ASSIGN_ADD_PACCH:
108 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_PACCH, true);
109 tbf_fsm_state_chg(fi, TBF_ST_ASSIGN);
110 break;
111 default:
112 OSMO_ASSERT(0);
113 }
114}
115
116static void st_assign(struct osmo_fsm_inst *fi, uint32_t event, void *data)
117{
118 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
119 switch (event) {
120 case TBF_EV_ASSIGN_ADD_CCCH:
121 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, true);
122 break;
123 case TBF_EV_ASSIGN_ADD_PACCH:
124 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_PACCH, true);
125 break;
Pau Espin Pedrol720e19e2021-07-22 19:56:37 +0200126 case TBF_EV_ASSIGN_ACK_PACCH:
127 if (ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)) {
128 /* We now know that the PACCH really existed */
129 LOGPTBF(ctx->tbf, LOGL_INFO,
130 "The TBF has been confirmed on the PACCH, "
131 "changed type from CCCH to PACCH\n");
132 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, false);
133 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_PACCH, true);
134 }
135 tbf_fsm_state_chg(fi, TBF_ST_FLOW);
136 break;
137 case TBF_EV_ASSIGN_READY_CCCH:
138 /* change state to FLOW, so scheduler will start transmission */
139 tbf_fsm_state_chg(fi, TBF_ST_FLOW);
140 break;
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200141 default:
142 OSMO_ASSERT(0);
143 }
144}
145
Pau Espin Pedrolc32c4a32021-07-23 18:27:57 +0200146static void st_flow(struct osmo_fsm_inst *fi, uint32_t event, void *data)
147{
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200148 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
Pau Espin Pedrolc32c4a32021-07-23 18:27:57 +0200149 switch (event) {
150 case TBF_EV_LAST_DL_DATA_SENT:
151 case TBF_EV_LAST_UL_DATA_RECVD:
152 /* All data has been sent or received, change state to FINISHED */
153 tbf_fsm_state_chg(fi, TBF_ST_FINISHED);
154 break;
Pau Espin Pedrolefcb0462021-07-26 12:33:39 +0200155 case TBF_EV_FINAL_ACK_RECVD:
156 /* We received Final Ack (DL ACK/NACK) from MS. move to
157 WAIT_RELEASE, we wait there for release or re-use the TBF in
158 case we receive more DL data to tx */
159 tbf_fsm_state_chg(fi, TBF_ST_WAIT_RELEASE);
160 break;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200161 case TBF_EV_MAX_N3101:
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200162 ctx->T_release = 3169;
163 tbf_fsm_state_chg(fi, TBF_ST_RELEASING);
164 break;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200165 case TBF_EV_MAX_N3105:
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200166 ctx->T_release = 3195;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200167 tbf_fsm_state_chg(fi, TBF_ST_RELEASING);
168 break;
Pau Espin Pedrolefcb0462021-07-26 12:33:39 +0200169 default:
170 OSMO_ASSERT(0);
171 }
172}
173
174static void st_finished(struct osmo_fsm_inst *fi, uint32_t event, void *data)
175{
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200176 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
Pau Espin Pedrolefcb0462021-07-26 12:33:39 +0200177 switch (event) {
178 case TBF_EV_FINAL_ACK_RECVD:
179 /* We received Final Ack (DL ACK/NACK) from MS. move to
180 WAIT_RELEASE, we wait there for release or re-use the TBF in
181 case we receive more DL data to tx */
182 tbf_fsm_state_chg(fi, TBF_ST_WAIT_RELEASE);
183 break;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200184 case TBF_EV_MAX_N3103:
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200185 ctx->T_release = 3169;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200186 tbf_fsm_state_chg(fi, TBF_ST_RELEASING);
187 break;
188 case TBF_EV_MAX_N3105:
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200189 ctx->T_release = 3195;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200190 tbf_fsm_state_chg(fi, TBF_ST_RELEASING);
191 break;
192 default:
193 OSMO_ASSERT(0);
194 }
195}
196
197static void st_wait_release(struct osmo_fsm_inst *fi, uint32_t event, void *data)
198{
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200199 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200200 switch (event) {
201 case TBF_EV_FINAL_ACK_RECVD:
202 /* ignore, duplicate ACK, we already know about since we are in WAIT_RELEASE */
203 break;
204 case TBF_EV_MAX_N3101:
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200205 ctx->T_release = 3169;
206 tbf_fsm_state_chg(fi, TBF_ST_RELEASING);
207 break;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200208 case TBF_EV_MAX_N3105:
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200209 ctx->T_release = 3195;
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200210 tbf_fsm_state_chg(fi, TBF_ST_RELEASING);
211 break;
Pau Espin Pedrolc32c4a32021-07-23 18:27:57 +0200212 default:
213 OSMO_ASSERT(0);
214 }
215}
216
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200217static void st_releasing_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
218{
219 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
220 unsigned long val;
221
222 if (!ctx->T_release)
223 return;
224
225 /* In general we should end up here with an assigned timer in ctx->T_release. Possible values are:
226 * T3195: Wait for reuse of TFI(s) when there is no response from the MS
227 * (radio failure or cell change) for this TBF/MBMS radio bearer.
228 * T3169: Wait for reuse of USF and TFI(s) after the MS uplink assignment for this TBF is invalid.
229 */
230 val = osmo_tdef_get(tbf_ms(ctx->tbf)->bts->T_defs_bts, ctx->T_release, OSMO_TDEF_S, -1);
231 fi->T = ctx->T_release;
232 LOGPTBF(ctx->tbf, LOGL_DEBUG, "starting timer T%u with %lu sec. %u microsec\n",
233 ctx->T_release, val, 0);
234 osmo_timer_schedule(&fi->timer, val, 0);
235}
236
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200237static void tbf_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
238{
239 /* TODO: needed ?
240 * struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
241 */
242}
243
244static int tbf_fsm_timer_cb(struct osmo_fsm_inst *fi)
245{
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200246 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200247 switch (fi->T) {
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200248 case 3169:
249 case 3195:
250 tbf_free(ctx->tbf);
251 break;
252 default:
253 OSMO_ASSERT(0);
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200254 }
255 return 0;
256}
257
258static struct osmo_fsm_state tbf_fsm_states[] = {
259 [TBF_ST_NULL] = {
260 .in_event_mask =
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200261 X(TBF_EV_ASSIGN_ADD_CCCH) |
262 X(TBF_EV_ASSIGN_ADD_PACCH),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200263 .out_state_mask =
264 X(TBF_ST_ASSIGN) |
265 X(TBF_ST_FLOW) |
266 X(TBF_ST_RELEASING),
267 .name = "NULL",
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200268 .action = st_null,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200269 },
270 [TBF_ST_ASSIGN] = {
271 .in_event_mask =
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200272 X(TBF_EV_ASSIGN_ADD_CCCH) |
Pau Espin Pedrol720e19e2021-07-22 19:56:37 +0200273 X(TBF_EV_ASSIGN_ADD_PACCH) |
274 X(TBF_EV_ASSIGN_ACK_PACCH) |
275 X(TBF_EV_ASSIGN_READY_CCCH),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200276 .out_state_mask =
277 X(TBF_ST_FLOW) |
278 X(TBF_ST_FINISHED) |
279 X(TBF_ST_RELEASING),
280 .name = "ASSIGN",
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200281 .action = st_assign,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200282 },
283 [TBF_ST_FLOW] = {
284 .in_event_mask =
Pau Espin Pedrolc32c4a32021-07-23 18:27:57 +0200285 X(TBF_EV_LAST_DL_DATA_SENT) |
Pau Espin Pedrolefcb0462021-07-26 12:33:39 +0200286 X(TBF_EV_LAST_UL_DATA_RECVD) |
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200287 X(TBF_EV_FINAL_ACK_RECVD) |
288 X(TBF_EV_MAX_N3101) |
289 X(TBF_EV_MAX_N3105),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200290 .out_state_mask =
291 X(TBF_ST_FINISHED) |
292 X(TBF_ST_WAIT_RELEASE) |
293 X(TBF_ST_RELEASING),
294 .name = "FLOW",
Pau Espin Pedrolc32c4a32021-07-23 18:27:57 +0200295 .action = st_flow,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200296 },
297 [TBF_ST_FINISHED] = {
298 .in_event_mask =
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200299 X(TBF_EV_FINAL_ACK_RECVD) |
300 X(TBF_EV_MAX_N3103) |
301 X(TBF_EV_MAX_N3105),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200302 .out_state_mask =
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200303 X(TBF_ST_WAIT_RELEASE) |
304 X(TBF_ST_RELEASING),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200305 .name = "FINISHED",
Pau Espin Pedrolefcb0462021-07-26 12:33:39 +0200306 .action = st_finished,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200307 },
308 [TBF_ST_WAIT_RELEASE] = {
309 .in_event_mask =
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200310 X(TBF_EV_FINAL_ACK_RECVD) |
311 X(TBF_EV_MAX_N3101) |
312 X(TBF_EV_MAX_N3105),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200313 .out_state_mask =
314 X(TBF_ST_RELEASING),
315 .name = "WAIT_RELEASE",
Pau Espin Pedrol55f600b2021-07-26 15:54:39 +0200316 .action = st_wait_release,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200317 },
318 [TBF_ST_RELEASING] = {
319 .in_event_mask =
320 0,
321 .out_state_mask =
322 0,
323 .name = "RELEASING",
Pau Espin Pedrolcfb61d92021-07-26 17:17:02 +0200324 .onenter = st_releasing_on_enter,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200325 },
326};
327
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200328void tbf_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
329{
330 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
331 switch (event) {
332 case TBF_EV_ASSIGN_DEL_CCCH:
333 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, false);
334 break;
335 default:
336 OSMO_ASSERT(0);
337 }
338}
339
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200340struct osmo_fsm tbf_fsm = {
341 .name = "TBF",
342 .states = tbf_fsm_states,
343 .num_states = ARRAY_SIZE(tbf_fsm_states),
344 .timer_cb = tbf_fsm_timer_cb,
345 .cleanup = tbf_fsm_cleanup,
346 .log_subsys = DTBF,
347 .event_names = tbf_fsm_event_names,
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200348 .allstate_action = tbf_fsm_allstate_action,
349 .allstate_event_mask = X(TBF_EV_ASSIGN_DEL_CCCH),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200350};
351
352static __attribute__((constructor)) void tbf_fsm_init(void)
353{
354 OSMO_ASSERT(osmo_fsm_register(&tbf_fsm) == 0);
355}