blob: 93019313597f4a2de669265a61e70f2d6e83646e [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 Pedroldc2aaac2021-05-14 12:50:46 +020047 { 0, NULL }
48};
49
Pau Espin Pedrol33e80072021-07-22 19:20:50 +020050static void mod_ass_type(struct tbf_fsm_ctx *ctx, uint8_t t, bool set)
51{
52 const char *ch = "UNKNOWN";
53 bool prev_set = ctx->state_flags & (1 << t);
54
55 switch (t) {
56 case GPRS_RLCMAC_FLAG_CCCH:
57 ch = "CCCH";
58 break;
59 case GPRS_RLCMAC_FLAG_PACCH:
60 ch = "PACCH";
61 break;
62 default:
63 LOGPTBF(ctx->tbf, LOGL_ERROR,
64 "attempted to %sset unexpected ass. type %d - FIXME!\n",
65 set ? "" : "un", t);
66 return;
67 }
68
69 if (set && prev_set) {
70 LOGPTBF(ctx->tbf, LOGL_ERROR,
71 "attempted to set ass. type %s which is already set.\n", ch);
72 } else if (!set && !prev_set) {
73 return;
74 }
75
76 LOGPTBF(ctx->tbf, LOGL_INFO, "%sset ass. type %s [prev CCCH:%u, PACCH:%u]\n",
77 set ? "" : "un", ch,
78 !!(ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)),
79 !!(ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH)));
80
81 if (set) {
82 ctx->state_flags |= (1 << t);
83 } else {
84 ctx->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; /* keep to flags */
85 ctx->state_flags &= ~(1 << t);
86 }
87}
88
89
90static void st_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)
91{
92 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
93 switch (event) {
94 case TBF_EV_ASSIGN_ADD_CCCH:
95 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, true);
96 tbf_fsm_state_chg(fi, tbf_direction(ctx->tbf) == GPRS_RLCMAC_DL_TBF ?
97 TBF_ST_ASSIGN : TBF_ST_FLOW);
98 break;
99 case TBF_EV_ASSIGN_ADD_PACCH:
100 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_PACCH, true);
101 tbf_fsm_state_chg(fi, TBF_ST_ASSIGN);
102 break;
103 default:
104 OSMO_ASSERT(0);
105 }
106}
107
108static void st_assign(struct osmo_fsm_inst *fi, uint32_t event, void *data)
109{
110 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
111 switch (event) {
112 case TBF_EV_ASSIGN_ADD_CCCH:
113 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, true);
114 break;
115 case TBF_EV_ASSIGN_ADD_PACCH:
116 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_PACCH, true);
117 break;
118 default:
119 OSMO_ASSERT(0);
120 }
121}
122
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200123static void tbf_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
124{
125 /* TODO: needed ?
126 * struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
127 */
128}
129
130static int tbf_fsm_timer_cb(struct osmo_fsm_inst *fi)
131{
132 switch (fi->T) {
133 default:
134 break;
135 }
136 return 0;
137}
138
139static struct osmo_fsm_state tbf_fsm_states[] = {
140 [TBF_ST_NULL] = {
141 .in_event_mask =
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200142 X(TBF_EV_ASSIGN_ADD_CCCH) |
143 X(TBF_EV_ASSIGN_ADD_PACCH),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200144 .out_state_mask =
145 X(TBF_ST_ASSIGN) |
146 X(TBF_ST_FLOW) |
147 X(TBF_ST_RELEASING),
148 .name = "NULL",
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200149 .action = st_null,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200150 },
151 [TBF_ST_ASSIGN] = {
152 .in_event_mask =
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200153 X(TBF_EV_ASSIGN_ADD_CCCH) |
154 X(TBF_EV_ASSIGN_ADD_PACCH),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200155 .out_state_mask =
156 X(TBF_ST_FLOW) |
157 X(TBF_ST_FINISHED) |
158 X(TBF_ST_RELEASING),
159 .name = "ASSIGN",
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200160 .action = st_assign,
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200161 },
162 [TBF_ST_FLOW] = {
163 .in_event_mask =
164 0,
165 .out_state_mask =
166 X(TBF_ST_FINISHED) |
167 X(TBF_ST_WAIT_RELEASE) |
168 X(TBF_ST_RELEASING),
169 .name = "FLOW",
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200170 },
171 [TBF_ST_FINISHED] = {
172 .in_event_mask =
173 0,
174 .out_state_mask =
175 X(TBF_ST_WAIT_RELEASE),
176 .name = "FINISHED",
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200177 },
178 [TBF_ST_WAIT_RELEASE] = {
179 .in_event_mask =
180 0,
181 .out_state_mask =
182 X(TBF_ST_RELEASING),
183 .name = "WAIT_RELEASE",
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200184 },
185 [TBF_ST_RELEASING] = {
186 .in_event_mask =
187 0,
188 .out_state_mask =
189 0,
190 .name = "RELEASING",
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200191 },
192};
193
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200194void tbf_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
195{
196 struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
197 switch (event) {
198 case TBF_EV_ASSIGN_DEL_CCCH:
199 mod_ass_type(ctx, GPRS_RLCMAC_FLAG_CCCH, false);
200 break;
201 default:
202 OSMO_ASSERT(0);
203 }
204}
205
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200206struct osmo_fsm tbf_fsm = {
207 .name = "TBF",
208 .states = tbf_fsm_states,
209 .num_states = ARRAY_SIZE(tbf_fsm_states),
210 .timer_cb = tbf_fsm_timer_cb,
211 .cleanup = tbf_fsm_cleanup,
212 .log_subsys = DTBF,
213 .event_names = tbf_fsm_event_names,
Pau Espin Pedrol33e80072021-07-22 19:20:50 +0200214 .allstate_action = tbf_fsm_allstate_action,
215 .allstate_event_mask = X(TBF_EV_ASSIGN_DEL_CCCH),
Pau Espin Pedroldc2aaac2021-05-14 12:50:46 +0200216};
217
218static __attribute__((constructor)) void tbf_fsm_init(void)
219{
220 OSMO_ASSERT(osmo_fsm_register(&tbf_fsm) == 0);
221}