blob: 32e3533f66aa998595088c20099aa4a65db89e07 [file] [log] [blame]
Pau Espin Pedrolea8dbdd2021-07-29 18:39:16 +02001/* tbf_ul_ack_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 <osmocom/core/bitvec.h>
26
27#include <tbf_ul_ack_fsm.h>
28#include <gprs_rlcmac.h>
29#include <gprs_debug.h>
30#include <gprs_ms.h>
31#include <encoding.h>
32#include <bts.h>
33#include <tbf.h>
34#include <tbf_ul.h>
35
36#include <tbf_ul_ack_fsm.h>
37
38#define X(s) (1 << (s))
39
40const struct osmo_tdef_state_timeout tbf_ul_ack_fsm_timeouts[32] = {
41 [TBF_UL_ACK_ST_NONE] = {},
42 [TBF_UL_ACK_ST_SCHED_UL_ACK] = {},
43 [TBF_UL_ACK_ST_WAIT_ACK] = {},
44};
45
46const struct value_string tbf_ul_ack_fsm_event_names[] = {
47 { TBF_UL_ACK_EV_SCHED_ACK, "SCHED_ACK" },
48 { TBF_UL_ACK_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" },
49 { TBF_UL_ACK_EV_RX_CTRL_ACK, "RX_CTRL_ACK" },
50 { TBF_UL_ACK_EV_POLL_TIMEOUT, "POLL_TIMEOUT" },
51 { 0, NULL }
52};
53
54static struct msgb *create_ul_ack_nack(const struct tbf_ul_ack_fsm_ctx *ctx,
55 const struct tbf_ul_ack_ev_create_rlcmac_msg_ctx *d,
56 bool final)
57{
58 struct msgb *msg;
59 int rc;
60 unsigned int rrbp = 0;
61 uint32_t new_poll_fn = 0;
62 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)ctx->tbf;
63 struct GprsMs *ms = tbf_ms(tbf);
64
65 if (final) {
66 rc = tbf_check_polling(tbf, d->fn, d->ts, &new_poll_fn, &rrbp);
67 if (rc < 0)
68 return NULL;
69 }
70
71 msg = msgb_alloc(23, "rlcmac_ul_ack");
72 if (!msg)
73 return NULL;
74 struct bitvec *ack_vec = bitvec_alloc(23, tbf);
75 if (!ack_vec) {
76 msgb_free(msg);
77 return NULL;
78 }
79 bitvec_unhex(ack_vec, DUMMY_VEC);
80 write_packet_uplink_ack(ack_vec, ctx->tbf, final, rrbp);
81 bitvec_pack(ack_vec, msgb_put(msg, 23));
82 bitvec_free(ack_vec);
83
84 /* TS 44.060 7a.2.1.1: "The contention resolution is completed on
85 * the network side when the network receives an RLC data block that
86 * comprises the TLLI value that identifies the mobile station and the
87 * TFI value associated with the TBF."
88 * However, it's handier for us to mark contention resolution success
89 * here since according to spec upon rx UL ACK is the time at which MS
90 * realizes contention resolution succeeds. */
91 if (ms_tlli(ms) != GSM_RESERVED_TMSI)
92 ul_tbf_contention_resolution_success(ctx->tbf);
93
Pau Espin Pedrola161bf42021-07-30 13:42:06 +020094 if (final) {
Pau Espin Pedrolea8dbdd2021-07-29 18:39:16 +020095 tbf_set_polling(tbf, new_poll_fn, d->ts, PDCH_ULC_POLL_UL_ACK);
Pau Espin Pedrola161bf42021-07-30 13:42:06 +020096 LOGPTBFUL(tbf, LOGL_DEBUG,
97 "Scheduled UL Acknowledgement polling on PACCH (FN=%d, TS=%d)\n",
98 new_poll_fn, d->ts);
99 }
Pau Espin Pedrolea8dbdd2021-07-29 18:39:16 +0200100
101 return msg;
102}
103
104static void st_none(struct osmo_fsm_inst *fi, uint32_t event, void *data)
105{
106 switch (event) {
107 case TBF_UL_ACK_EV_SCHED_ACK:
108 tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_SCHED_UL_ACK);
109 break;
110 default:
111 OSMO_ASSERT(0);
112 }
113}
114
115static void st_sched_ul_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
116{
117 struct tbf_ul_ack_fsm_ctx *ctx = (struct tbf_ul_ack_fsm_ctx *)fi->priv;
118 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)ctx->tbf;
119 struct tbf_ul_ack_ev_create_rlcmac_msg_ctx *data_ctx;
120 bool final;
121
122 switch (event) {
123 case TBF_UL_ACK_EV_SCHED_ACK:
124 LOGPTBFUL(tbf, LOGL_DEBUG,
125 "Sending Ack/Nack already scheduled, no need to re-schedule\n");
126 break;
127 case TBF_UL_ACK_EV_CREATE_RLCMAC_MSG:
128 data_ctx = (struct tbf_ul_ack_ev_create_rlcmac_msg_ctx *)data;
129 final = tbf_state(tbf) == TBF_ST_FINISHED;
130 data_ctx->msg = create_ul_ack_nack(ctx, data_ctx, final);
131 if (!data_ctx->msg)
132 return;
133 if (final) /* poll set */
134 tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_WAIT_ACK);
135 else
136 tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_NONE);
137 break;
138 default:
139 OSMO_ASSERT(0);
140 }
141}
142
143static void st_wait_ctrl_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
144{
145 struct tbf_ul_ack_fsm_ctx *ctx = (struct tbf_ul_ack_fsm_ctx *)fi->priv;
146 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)ctx->tbf;
147
148 switch (event) {
149 case TBF_UL_ACK_EV_SCHED_ACK:
150 /* ignore, we are in the middle of waiting for a response */
151 break;
152 case TBF_UL_ACK_EV_RX_CTRL_ACK:
153 tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_NONE);
154 break;
155 case TBF_UL_ACK_EV_POLL_TIMEOUT:
156 LOGPTBF(tbf, LOGL_NOTICE,
157 "Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ACK: %s\n",
158 tbf_rlcmac_diag(tbf));
159 /* Reschedule Ul Ack/NAck */
160 tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_SCHED_UL_ACK);
161 break;
162 default:
163 OSMO_ASSERT(0);
164 }
165}
166
167static int tbf_ul_ack_fsm_timer_cb(struct osmo_fsm_inst *fi)
168{
169 switch (fi->T) {
170 default:
171 OSMO_ASSERT(0);
172 }
173 return 0;
174}
175
176static struct osmo_fsm_state tbf_ul_ack_fsm_states[] = {
177 [TBF_UL_ACK_ST_NONE] = {
178 .in_event_mask =
179 X(TBF_UL_ACK_EV_SCHED_ACK),
180 .out_state_mask =
181 X(TBF_UL_ACK_ST_SCHED_UL_ACK),
182 .name = "NONE",
183 .action = st_none,
184 },
185 [TBF_UL_ACK_ST_SCHED_UL_ACK] = {
186 .in_event_mask =
187 X(TBF_UL_ACK_EV_SCHED_ACK) |
188 X(TBF_UL_ACK_EV_CREATE_RLCMAC_MSG),
189 .out_state_mask =
190 X(TBF_UL_ACK_ST_NONE) |
191 X(TBF_UL_ACK_ST_WAIT_ACK),
192 .name = "SCHED_UL_ACK",
193 .action = st_sched_ul_ack,
194 },
195 [TBF_UL_ACK_ST_WAIT_ACK] = {
196 .in_event_mask =
197 X(TBF_UL_ACK_EV_SCHED_ACK) |
198 X(TBF_UL_ACK_EV_RX_CTRL_ACK) |
199 X(TBF_UL_ACK_EV_POLL_TIMEOUT),
200 .out_state_mask =
201 X(TBF_UL_ACK_ST_NONE) |
202 X(TBF_UL_ACK_ST_SCHED_UL_ACK),
203 .name = "WAIT_ACK",
204 .action = st_wait_ctrl_ack,
205 },
206};
207
208struct osmo_fsm tbf_ul_ack_fsm = {
209 .name = "UL_ACK_TBF",
210 .states = tbf_ul_ack_fsm_states,
211 .num_states = ARRAY_SIZE(tbf_ul_ack_fsm_states),
212 .timer_cb = tbf_ul_ack_fsm_timer_cb,
213 .log_subsys = DTBFUL,
214 .event_names = tbf_ul_ack_fsm_event_names,
215};
216
217static __attribute__((constructor)) void tbf_ul_ack_fsm_init(void)
218{
219 OSMO_ASSERT(osmo_fsm_register(&tbf_ul_ack_fsm) == 0);
220}
221
222
223struct msgb *tbf_ul_ack_create_rlcmac_msg(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts)
224{
225 int rc;
226 struct tbf_ul_ack_ev_create_rlcmac_msg_ctx data_ctx = {
227 .fn = fn,
228 .ts = ts,
229 .msg = NULL,
230 };
231 OSMO_ASSERT(tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF);
232
233 rc = osmo_fsm_inst_dispatch(tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf), TBF_UL_ACK_EV_CREATE_RLCMAC_MSG, &data_ctx);
234 if (rc != 0 || !data_ctx.msg)
235 return NULL;
236 return data_ctx.msg;
237}
238
239bool tbf_ul_ack_rts(const struct gprs_rlcmac_tbf *tbf)
240{
241 struct osmo_fsm_inst *fi = tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf);
242 return fi->state == TBF_UL_ACK_ST_SCHED_UL_ACK;
243}
244
245/* Did we already send the Final ACK and we are waiting for its confirmation (CTRL ACK) ? */
246bool tbf_ul_ack_waiting_cnf_final_ack(const struct gprs_rlcmac_tbf* tbf)
247{
248 OSMO_ASSERT(tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF);
249 struct osmo_fsm_inst *fi = tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf);
250 return fi->state == TBF_UL_ACK_ST_WAIT_ACK;
251}
252
253bool tbf_ul_ack_exp_ctrl_ack(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts)
254{
255 struct osmo_fsm_inst *fi = tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf);
256 return fi->state == TBF_UL_ACK_ST_WAIT_ACK;
257 /* FIXME: validate FN and TS match: && ctx->poll_fn = fn && ctx->poll_ts == ts */
258}