1
|
#include <osmocom/core/fsm.h>
|
2
|
|
3
|
enum lchan_fsm_states {
|
4
|
/* Administratively disableD */
|
5
|
ST_DISABLED,
|
6
|
/* Inactive; waiting to be allocated */
|
7
|
ST_INACTIVE,
|
8
|
/* waiting for RSL CHAN ACT ACK from BTS */
|
9
|
ST_WAIT_ACT_ACK,
|
10
|
/* active, i.e. channel in use at BTS/MS */
|
11
|
ST_ACTIVE,
|
12
|
/* waiting for RSL RF CHAN REL ACK from BTS */
|
13
|
ST_WAIT_DEACT_ACK,
|
14
|
|
15
|
/* waiting for RSL CHAN ACT ACK from BTS for PDCH */
|
16
|
ST_WAIT_ACT_PDCH_ACK,
|
17
|
/* active in PDCH mode for GPRS/EGPRS */
|
18
|
ST_ACTIVE_PDCH,
|
19
|
/* waiting for RSL CHAN ACT ACK from BTS for PDCH */
|
20
|
ST_WAIT_DEACT_PDCH_ACK,
|
21
|
};
|
22
|
|
23
|
enum lchan_fsm_timer {
|
24
|
LCHAN_T_ACT,
|
25
|
LCHAN_T_DEACT,
|
26
|
};
|
27
|
|
28
|
enum lchan_fsm_event {
|
29
|
/* OML tells us this lchan is enabled (->INACTIVE) */
|
30
|
LCHAN_EV_ENABLE,
|
31
|
/* OML tells us to disable this chnanel (->DISABLED) */
|
32
|
LCHAN_EV_DISABLE,
|
33
|
/* BSC requests channel activation */
|
34
|
LCHAN_EV_ACTIVATE,
|
35
|
/* BSC requests channel deactivation */
|
36
|
LCHAN_EV_DEACTIVATE,
|
37
|
|
38
|
/* RSL DChan ACT/DEACT Events */
|
39
|
LCHAN_EV_CHAN_ACT_ACK,
|
40
|
LCHAN_EV_CHAN_ACT_NACK,
|
41
|
LCHAN_EV_CHAN_REL_ACK,
|
42
|
LCHAN_EV_CHAN_REL_NACK,
|
43
|
|
44
|
/* RSL RLL Message */
|
45
|
LCHAN_EV_RLL_FROM_BTS,
|
46
|
LCHAN_EV_RLL_FROM_BSC,
|
47
|
/* RSL DCHAN Message */
|
48
|
LCHAN_EV_DCHAN_FROM_BTS,
|
49
|
LCHAN_EV_DCHAN_FROM_BSC,
|
50
|
};
|
51
|
|
52
|
static void lchan_fsm_disabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
53
|
{
|
54
|
struct gsm_lchan *lchan = fi->priv;
|
55
|
|
56
|
switch (event) {
|
57
|
case LCHAN_EV_ENABLE:
|
58
|
osmo_fsm_inst_state_chg(fi, ST_INACTIVE, 0, 0);
|
59
|
break;
|
60
|
}
|
61
|
}
|
62
|
|
63
|
static void lchan_fsm_inactive(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
64
|
{
|
65
|
struct gsm_lchan *lchan = fi->priv;
|
66
|
|
67
|
switch (event) {
|
68
|
case LCHAN_EV_DISABLE:
|
69
|
osmo_fsm_inst_state_chg(fi, ST_DISABLED, 0, 0);
|
70
|
break;
|
71
|
case LCHAN_EV_ACTIVATE:
|
72
|
/* Send RSL RF CHAN ACT */
|
73
|
rsl_chan_activate_lchan(lchan, act_type, ho_ref);
|
74
|
osmo_fsm_inst_state_chg(fi, ST_WAIT_ACT_ACK, 4, LCHAN_T_ACT);
|
75
|
break;
|
76
|
}
|
77
|
}
|
78
|
|
79
|
static void lchan_fsm_wait_act_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
80
|
{
|
81
|
struct gsm_lchan *lchan = fi->priv;
|
82
|
struct tlv_parsed *tp = data;
|
83
|
|
84
|
switch (event) {
|
85
|
case LCHAN_EV_CHAN_ACT_ACK:
|
86
|
osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
|
87
|
if (lchan->rqd_ref) {
|
88
|
rsl_send_imm_assignment(lchan);
|
89
|
talloc_free(lchan->rqd_ref);
|
90
|
lchan->rqd_ref = NULL;
|
91
|
lchan->rqd_ta = 0;
|
92
|
}
|
93
|
send_lchan_signal(S_LCHAN_ACTIVATE_ACK, lchan, NULL);
|
94
|
break;
|
95
|
case LCHAN_EV_CHAN_ACT_NACK:
|
96
|
rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_CHAN_ACT_NACK]);
|
97
|
if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) {
|
98
|
const uint8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE);
|
99
|
/* print cause */
|
100
|
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC) {
|
101
|
/* rsl_lchan_mark_broken(msg->lchan, "NACK on activation"); */
|
102
|
} else {
|
103
|
rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE);
|
104
|
}
|
105
|
} else {
|
106
|
/*rsl_lchan_mark_broken(msg->lchan, "NACK on activation no IE");*/
|
107
|
}
|
108
|
send_lchan_signal(S_LCHAN_ACTIVATE_NACK, lchan, NULL);
|
109
|
break;
|
110
|
}
|
111
|
}
|
112
|
|
113
|
static void lchan_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
114
|
{
|
115
|
struct gsm_lchan *lchan = fi->priv;
|
116
|
|
117
|
switch (event) {
|
118
|
case LCHAN_EV_DEACTIVATE:
|
119
|
/* Send RSL RF CHAN REL */
|
120
|
rsl_rf_chan_release(lchan, error, deact_sacch;
|
121
|
osmo_fsm_inst_state_chg(fi, ST_WAIT_DEACT_ACK, 4, LCHAN_T_DEACT);
|
122
|
break;
|
123
|
case LCHAN_EV_RLL_FROM_BTS:
|
124
|
/* forward from BTS to MSC */
|
125
|
break;
|
126
|
case LCHAN_EV_RLL_FROM_BSC:
|
127
|
/* forward from MSC/BSC to BTS */
|
128
|
break;
|
129
|
case LCHAN_EV_DCHAN_FROM_BTS:
|
130
|
/* forward from BTS to MSC */
|
131
|
break;
|
132
|
case LCHAN_EV_DCHAN_FROM_BSC:
|
133
|
/* forward from MSC/BSC to BTS */
|
134
|
break;
|
135
|
}
|
136
|
}
|
137
|
|
138
|
static void lchan_fsm_wait_deact_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
139
|
{
|
140
|
struct gsm_lchan *lchan = fi->priv;
|
141
|
|
142
|
switch (event) {
|
143
|
case LCHAN_EV_CHAN_REL_ACK:
|
144
|
/* FIXME: check if this is a dynamic channel + activate as PDCH? */
|
145
|
osmo_fsm_inst_state_chg(fi, ST_INACTIVE, 0, 0);
|
146
|
break;
|
147
|
case LCHAN_EV_CHAN_REL_NACK:
|
148
|
break;
|
149
|
}
|
150
|
}
|
151
|
|
152
|
static void lchan_fsm_wait_act_pdch_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
153
|
{
|
154
|
struct gsm_lchan *lchan = fi->priv;
|
155
|
|
156
|
switch (event) {
|
157
|
case LCHAN_EV_CHAN_ACT_ACK:
|
158
|
osmo_fsm_inst_state_chg(fi, ST_ACTIVE_PDCH, 0, 0);
|
159
|
break;
|
160
|
case LCHAN_EV_CHAN_ACT_NACK:
|
161
|
break;
|
162
|
}
|
163
|
}
|
164
|
|
165
|
static void lchan_fsm_active_pdch(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
166
|
{
|
167
|
struct gsm_lchan *lchan = fi->priv;
|
168
|
|
169
|
switch (event) {
|
170
|
case LCHAN_EV_DEACTIVATE:
|
171
|
rsl_rf_chan_release(lchan, 0, 0);
|
172
|
osmo_fsm_inst_state_chg(fi, ST_WAIT_DEACT_PDCH_ACK, 0, 0);
|
173
|
break;
|
174
|
case LCHAN_EV_ACTIVATE: /* transition to non-PDCH mode */
|
175
|
foo = 1;
|
176
|
osmo_fsm_inst_state_chg(fi, ST_WAIT_DEACT_PDCH_ACK, 0, 0);
|
177
|
break;
|
178
|
}
|
179
|
}
|
180
|
|
181
|
static void lchan_fsm_wait_deact_pdch_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
182
|
{
|
183
|
struct gsm_lchan *lchan = fi->priv;
|
184
|
|
185
|
switch (event) {
|
186
|
case LCHAN_EV_CHAN_REL_ACK:
|
187
|
osmo_fsm_inst_state_chg(fi, ST_INACTIVE, 0, 0);
|
188
|
/* immediately re-activate as desired type, if pending */
|
189
|
if (foo)
|
190
|
osmo_fsm_inst_dispatch_event(fi, LCHAN_EV_ACTIVATE, NULL);
|
191
|
break;
|
192
|
case LCHAN_EV_CHAN_REL_NACK:
|
193
|
break;
|
194
|
}
|
195
|
}
|
196
|
|
197
|
|
198
|
static int lchan_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
199
|
{
|
200
|
struct gsm_lchan *lchan = fi->priv;
|
201
|
|
202
|
switch (fi->T) {
|
203
|
case LCHAN_T_ACT:
|
204
|
break;
|
205
|
case LCHAN_T_DEACT:
|
206
|
break;
|
207
|
}
|
208
|
}
|
209
|
|
210
|
const struct osmo_fsm_state lchan_fsm_stats[] = {
|
211
|
[ST_DISABLED] = {
|
212
|
.in_event_mask = S(LCHAN_EV_ENABLE),
|
213
|
.out_state_mask = S(ST_INACTIVE),
|
214
|
.name = "DISABLED",
|
215
|
.action = lchan_fsm_disabled,
|
216
|
},
|
217
|
[ST_INACTIVE] = {
|
218
|
.in_event_mask = S(LCHAN_EV_ACTIVATE) |
|
219
|
S(LCHAN_EV_DISABLE),
|
220
|
.out_state_mask = S(ST_WAIT_ACT_ACK) |
|
221
|
S(ST_WAIT_ACT_PDCH_ACK),
|
222
|
.name = "INACTIVE",
|
223
|
.action = lchan_fsm_inactive,
|
224
|
},
|
225
|
[ST_WAIT_ACT_ACK] = {
|
226
|
.in_event_mask = S(LCHAN_EV_CHAN_ACT_ACK) |
|
227
|
S(LCHAN_EV_CHAN_ACT_NACK),
|
228
|
.out_state_mask = S(ST_INACTIVE) | S(ST_ACTIVE),
|
229
|
.name = "WAIT_ACT_ACK",
|
230
|
.action = lchan_fsm_wait_act_ack,
|
231
|
},
|
232
|
[ST_ACTIVE] = {
|
233
|
.in_event_mask = S(LCHAN_EV_DEACTIVATE) |
|
234
|
S(LCHAN_EV_RLL_FROM_BTS) |
|
235
|
S(LCHAN_EV_RLL_FROM_BSC) |
|
236
|
S(LCHAN_EV_DCHAN_FROM_BTS) |
|
237
|
S(LCHAN_EV_DCHAN_FROM_BSC),
|
238
|
.out_state_mask = S(ST_WAIT_DEACT_ACK),
|
239
|
.name = "ACTIVE",
|
240
|
.action = lchan_fsm_active,
|
241
|
},
|
242
|
[ST_WAIT_DEACT_ACK] = {
|
243
|
.in_event_mask = S(LCHAN_EV_CHAN_REL_ACK) |
|
244
|
S(LCHAN_EV_CHAN_REL_NACK),
|
245
|
.out_state_mask = S(ST_INACTIVE),
|
246
|
.name = "WAIT_DEACT_ACK",
|
247
|
.action = lchan_fsm_wait_deact_ack,
|
248
|
},
|
249
|
|
250
|
[ST_WAIT_ACT_PDCH_ACK] = {
|
251
|
.in_event_mask = S(LCHAN_EV_CHAN_ACT_ACK) |
|
252
|
S(LCHAN_EV_CHAN_ACT_NACK),
|
253
|
.out_state_mask = S(ST_INACTIVE) | S(ST_ACTIVE_PDCH),
|
254
|
.name = "WAIT_ACT_PDCH_ACK",
|
255
|
.action = lchan_fsm_wait_act_pdch_ack,
|
256
|
},
|
257
|
[ST_ACTIVE_PDCH] = {
|
258
|
.in_event_mask = S(LCHAN_EV_DEACTIVATE) |
|
259
|
S(LCHAN_EV_ACTIVATE),
|
260
|
.out_state_mask = S(ST_WAIT_DEACT_PDCH_ACK),
|
261
|
.name = "ACTIVE_PDCH",
|
262
|
.action = lchan_fsm_active_pdch,
|
263
|
},
|
264
|
[ST_WAIT_DEACT_PDCH_ACK] = {
|
265
|
.in_event_mask = S(LCHAN_EV_CHAN_REL_ACK) |
|
266
|
S(LCHAN_EV_CHAN_REL_NACK),
|
267
|
.out_state_mask = S(ST_INACTIVE),
|
268
|
.name = "WAIT_DEACT_PDCH_ACK",
|
269
|
.action = lchan_fsm_wait_deact_pdch_ack,
|
270
|
},
|
271
|
|
272
|
|
273
|
};
|
274
|
|
275
|
struct osmo_fsm lchan_fsm = {
|
276
|
.name = "LCHAN",
|
277
|
.states = lchan_fsm_states,
|
278
|
.num_states = ARRAY_SIZE(lchan_fsm_states),
|
279
|
.timer_cb = lchan_fsm_timer_cb,
|
280
|
.log_subsys = DRSL,
|
281
|
.event_names = lchan_fsm_event_names,
|
282
|
};
|
283
|
|
284
|
struct osmo_fsm_inst *lchan_fsm_inst_alloc(struct gsm_lchan *lchan, int log_level)
|
285
|
{
|
286
|
return osmo_fsm_inst_alloc(&lchan_fsm, lchan->ts->trx, lchan, log_level, id);
|
287
|
}
|