blob: 02f67471c0a8351e2beee79ace078ed29ab7566b [file] [log] [blame]
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +02001#include <osmocom/core/tdef.h>
2
3#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
Alexander Couzens68880212019-09-10 16:32:05 +02004#include <osmocom/sgsn/gprs_llc.h>
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +02005
6#include <osmocom/sgsn/debug.h>
7#include <osmocom/sgsn/sgsn.h>
8
9#define X(s) (1 << (s))
10
11static const struct osmo_tdef_state_timeout mm_state_gb_fsm_timeouts[32] = {
12 [ST_MM_IDLE] = { },
13 [ST_MM_READY] = { .T=3314 },
14 [ST_MM_STANDBY] = { },
15};
16
17#define mm_state_gb_fsm_state_chg(fi, NEXT_STATE) \
18 osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_gb_fsm_timeouts, sgsn->cfg.T_defs, -1)
19
Alexander Couzens68880212019-09-10 16:32:05 +020020static void st_mm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state) {
21 struct sgsn_mm_ctx *ctx = fi->priv;
22
Alexander Couzens4c7609a2019-09-11 03:00:47 +020023 /* FIXME: remove this timer when RAU has it's own fsm */
24 if (ctx->T == 3350 && osmo_timer_pending(&ctx->timer))
25 osmo_timer_del(&ctx->timer);
26
Alexander Couzens68880212019-09-10 16:32:05 +020027 if (ctx->gb.llme) {
28 gprs_llgmm_unassign(ctx->gb.llme);
29 ctx->gb.llme = NULL;
30 }
31}
32
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020033static void st_mm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
34{
35 switch(event) {
36 case E_MM_GPRS_ATTACH:
37 mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
38 break;
39 case E_MM_PDU_RECEPTION:
40 break;
41 }
42}
43
44static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
45{
46 unsigned long t_secs;
47
48 switch(event) {
49 case E_MM_READY_TIMER_EXPIRY:
50 case E_MM_IMPLICIT_DETACH:
51 mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
52 break;
53 case E_MM_PDU_RECEPTION:
54 /* RE-arm the READY timer upon receival of Gb PDUs */
55 t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3314, OSMO_TDEF_S, -1);
56 osmo_timer_schedule(&fi->timer, t_secs, 0);
57 break;
58 case E_MM_RA_UPDATE:
59 break;
60 }
61}
62
63static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
64{
65 switch(event) {
66 case E_MM_PDU_RECEPTION:
67 mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
68 break;
69 }
70}
71
72static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
73 [ST_MM_IDLE] = {
74 .in_event_mask = X(E_MM_GPRS_ATTACH) | X(E_MM_PDU_RECEPTION),
75 .out_state_mask = X(ST_MM_READY),
Alexander Couzens68880212019-09-10 16:32:05 +020076 .onenter = st_mm_idle_on_enter,
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020077 .name = "Idle",
78 .action = st_mm_idle,
79 },
80 [ST_MM_READY] = {
81 .in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_IMPLICIT_DETACH) | X(E_MM_PDU_RECEPTION),
82 .out_state_mask = X(ST_MM_IDLE) | X(ST_MM_STANDBY),
83 .name = "Ready",
84 .action = st_mm_ready,
85 },
86 [ST_MM_STANDBY] = {
87 .in_event_mask = X(E_MM_PDU_RECEPTION),
88 .out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
89 .name = "Standby",
90 .action = st_mm_standby,
91 },
92};
93
94const struct value_string mm_state_gb_fsm_event_names[] = {
95 OSMO_VALUE_STRING(E_MM_GPRS_ATTACH),
96 OSMO_VALUE_STRING(E_MM_PDU_RECEPTION),
97 OSMO_VALUE_STRING(E_MM_IMPLICIT_DETACH),
98 OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
99 OSMO_VALUE_STRING(E_MM_RA_UPDATE),
100 { 0, NULL }
101};
102
103int mm_state_gb_fsm_timer_cb(struct osmo_fsm_inst *fi)
104{
105 switch(fi->state) {
106 case ST_MM_READY:
107 /* timer for mm state. state=READY: T3314 (aka TS 23.060 "READY timer") */
108 osmo_fsm_inst_dispatch(fi, E_MM_READY_TIMER_EXPIRY, NULL);
109 break;
110 }
111
112 return 0;
113}
114
115struct osmo_fsm mm_state_gb_fsm = {
116 .name = "MM_STATE_Gb",
117 .states = mm_state_gb_fsm_states,
118 .num_states = ARRAY_SIZE(mm_state_gb_fsm_states),
119 .event_names = mm_state_gb_fsm_event_names,
120 .log_subsys = DMM,
121 .timer_cb = mm_state_gb_fsm_timer_cb,
122};
123
124static __attribute__((constructor)) void mm_state_gb_fsm_init(void)
125{
126 osmo_fsm_register(&mm_state_gb_fsm);
127}