Project

General

Profile

lchan_fsm.c

laforge, 05/28/2018 02:44 PM

 
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
}
Add picture from clipboard (Maximum size: 48.8 MB)