blob: e9c31d052d18ba0e028340fe583367031c19e9a3 [file] [log] [blame]
Pau Espin Pedrol36ecddb2020-06-26 12:07:05 +02001/* GMM mobility management states on the network side, 3GPP TS 24.008 ยง 4.1.3.3 */
2/*
3 * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * SPDX-License-Identifier: AGPL-3.0+
7 *
8 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
Pau Espin Pedrol31c46572019-09-02 16:45:27 +020023#include <osmocom/core/tdef.h>
24
25#include <osmocom/sgsn/gprs_gmm_fsm.h>
Alexander Couzens91a8bbd2019-09-11 03:38:14 +020026#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
27#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
Pau Espin Pedrol31c46572019-09-02 16:45:27 +020028
29#include <osmocom/sgsn/debug.h>
30#include <osmocom/sgsn/sgsn.h>
31
32#define X(s) (1 << (s))
33
34static const struct osmo_tdef_state_timeout gmm_fsm_timeouts[32] = {
35 [ST_GMM_DEREGISTERED] = { },
36 [ST_GMM_COMMON_PROC_INIT] = { },
37 [ST_GMM_REGISTERED_NORMAL] = { },
38 [ST_GMM_REGISTERED_SUSPENDED] = { },
39 [ST_GMM_DEREGISTERED_INIT] = { },
40};
41
42#define gmm_fsm_state_chg(fi, NEXT_STATE) \
43 osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, gmm_fsm_timeouts, sgsn->cfg.T_defs, -1)
44
45static void st_gmm_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *data)
46{
47 switch(event) {
48 case E_GMM_COMMON_PROC_INIT_REQ:
49 gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
50 break;
51 case E_GMM_ATTACH_SUCCESS:
52 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
53 break;
54 }
55}
56
57static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
58{
59 switch(event) {
Pau Espin Pedrolc26072a2021-03-25 16:57:22 +010060 case E_GMM_COMMON_PROC_INIT_REQ:
61 /* MS may retransmit GPRS Attach Request if for some reason
62 * CommonProcedure didn't go forward correctly */
63 break;
Pau Espin Pedrol31c46572019-09-02 16:45:27 +020064 /* TODO: events not used
65 case E_GMM_LOWER_LAYER_FAILED:
66 case E_GMM_COMMON_PROC_FAILED:
67 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
68 break;
69 */
70 case E_GMM_COMMON_PROC_SUCCESS:
71 case E_GMM_ATTACH_SUCCESS:
72 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
73 break;
74 }
75}
76
77static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, void *data)
78{
79 switch(event) {
80 case E_GMM_COMMON_PROC_INIT_REQ:
81 gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
82 break;
Maxb43496a2022-10-08 21:34:19 +030083 case E_GMM_COMMON_PROC_SUCCESS:
84 /* If we were moved from ST_GMM_COMMON_PROC_INIT here by
85 * E_GMM_ATTACH_SUCCESS instead of E_GMM_COMMON_PROC_SUCCESS then we'll receive the latter here:
86 * we should simply ignore it */
87 break;
Pau Espin Pedrol31c46572019-09-02 16:45:27 +020088 /* case E_GMM_NET_INIT_DETACH_REQ:
89 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
90 break; */
91 /* case E_GMM_MS_INIT_DETACH_REQ:
92 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
93 break; */
94 case E_GMM_SUSPEND:
95 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_SUSPENDED);
96 break;
97 }
98}
99
100static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
101{
102 switch(event) {
Harald Welte5e1a4862020-06-17 10:29:46 +0200103 case E_GMM_RESUME: /* explicit BSSGP RESUME from BSS */
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200104 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
105 break;
Harald Welte5e1a4862020-06-17 10:29:46 +0200106 case E_GMM_COMMON_PROC_INIT_REQ: /* implicit resume from MS */
107 gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
108 break;
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200109 }
110}
111
112static void st_gmm_deregistered_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
113{
114 switch(event) {
115 /* TODO: events not used in osmo-sgsn code
116 case E_GMM_DETACH_ACCEPTED:
117 case E_GMM_LOWER_LAYER_FAILED:
118 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
119 break;
120 */
121 }
122}
123
124static struct osmo_fsm_state gmm_fsm_states[] = {
125 [ST_GMM_DEREGISTERED] = {
126 .in_event_mask =
127 X(E_GMM_COMMON_PROC_INIT_REQ) |
128 X(E_GMM_ATTACH_SUCCESS),
129 .out_state_mask = X(ST_GMM_COMMON_PROC_INIT),
130 .name = "Deregistered",
131 .action = st_gmm_deregistered,
132 },
133 [ST_GMM_COMMON_PROC_INIT] = {
134 .in_event_mask =
135 /* X(E_GMM_LOWER_LAYER_FAILED) | */
136 /* X(E_GMM_COMMON_PROC_FAILED) | */
137 X(E_GMM_COMMON_PROC_SUCCESS) |
Pau Espin Pedrolc26072a2021-03-25 16:57:22 +0100138 X(E_GMM_ATTACH_SUCCESS) |
139 X(E_GMM_COMMON_PROC_INIT_REQ),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200140 .out_state_mask =
141 X(ST_GMM_DEREGISTERED) |
142 X(ST_GMM_REGISTERED_NORMAL),
143 .name = "CommonProcedureInitiated",
144 .action = st_gmm_common_proc_init,
145 },
146 [ST_GMM_REGISTERED_NORMAL] = {
147 .in_event_mask =
148 X(E_GMM_COMMON_PROC_INIT_REQ) |
Maxb43496a2022-10-08 21:34:19 +0300149 X(E_GMM_COMMON_PROC_SUCCESS) |
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200150 /* X(E_GMM_NET_INIT_DETACH_REQ) | */
151 /* X(E_GMM_MS_INIT_DETACH_REQ) | */
152 X(E_GMM_SUSPEND),
153 .out_state_mask =
154 X(ST_GMM_DEREGISTERED) |
155 X(ST_GMM_COMMON_PROC_INIT) |
156 X(ST_GMM_DEREGISTERED_INIT) |
157 X(ST_GMM_REGISTERED_SUSPENDED),
158 .name = "Registered.NORMAL",
159 .action = st_gmm_registered_normal,
160 },
161 [ST_GMM_REGISTERED_SUSPENDED] = {
Harald Welte5e1a4862020-06-17 10:29:46 +0200162 .in_event_mask = X(E_GMM_RESUME) |
163 X(E_GMM_COMMON_PROC_INIT_REQ),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200164 .out_state_mask =
165 X(ST_GMM_DEREGISTERED) |
Harald Welte5e1a4862020-06-17 10:29:46 +0200166 X(ST_GMM_REGISTERED_NORMAL) |
167 X(ST_GMM_COMMON_PROC_INIT),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200168 .name = "Registered.SUSPENDED",
169 .action = st_gmm_registered_suspended,
170 },
171 [ST_GMM_DEREGISTERED_INIT] = {
172 .in_event_mask = 0
173 /* X(E_GMM_DETACH_ACCEPTED) | */
174 /* X(E_GMM_LOWER_LAYER_FAILED) */,
175 .out_state_mask = X(ST_GMM_DEREGISTERED),
176 .name = "DeregisteredInitiated",
177 .action = st_gmm_deregistered_init,
178 },
179};
180
181const struct value_string gmm_fsm_event_names[] = {
182 OSMO_VALUE_STRING(E_GMM_COMMON_PROC_INIT_REQ),
183 /* OSMO_VALUE_STRING(E_GMM_COMMON_PROC_FAILED), */
184 /* OSMO_VALUE_STRING(E_GMM_LOWER_LAYER_FAILED), */
185 OSMO_VALUE_STRING(E_GMM_COMMON_PROC_SUCCESS),
186 OSMO_VALUE_STRING(E_GMM_ATTACH_SUCCESS),
187 /* OSMO_VALUE_STRING(E_GMM_NET_INIT_DETACH_REQ), */
188 /* OSMO_VALUE_STRING(E_GMM_MS_INIT_DETACH_REQ), */
189 /* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
190 OSMO_VALUE_STRING(E_GMM_SUSPEND),
191 OSMO_VALUE_STRING(E_GMM_CLEANUP),
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200192 OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200193 { 0, NULL }
194};
195
196void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200197 struct sgsn_mm_ctx *mmctx = fi->priv;
198 struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data;
199
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200200 switch (event) {
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200201 case E_GMM_RAT_CHANGE:
202
203 switch (fi->state) {
204 case ST_GMM_COMMON_PROC_INIT:
205 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
206 default:
207 if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200208 osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200209 else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200210 osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200211 mmctx->gb.llme = rat_chg->llme;
212 }
213
214 mmctx->ran_type = rat_chg->new_ran_type;
215 break;
216 }
217
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200218 case E_GMM_CLEANUP:
219 switch (fi->state) {
220 case ST_GMM_DEREGISTERED:
221 break;
222 default:
223 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
224 break;
225 }
226 }
227}
228
229int gmm_fsm_timer_cb(struct osmo_fsm_inst *fi)
230{
231 return 0;
232}
233
234struct osmo_fsm gmm_fsm = {
235 .name = "GMM",
236 .states = gmm_fsm_states,
237 .num_states = ARRAY_SIZE(gmm_fsm_states),
238 .event_names = gmm_fsm_event_names,
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200239 .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200240 .allstate_action = gmm_fsm_allstate_action,
241 .log_subsys = DMM,
242 .timer_cb = gmm_fsm_timer_cb,
243};
244
245static __attribute__((constructor)) void gmm_fsm_init(void)
246{
Harald Weltea868e172019-12-01 13:23:53 +0100247 OSMO_ASSERT(osmo_fsm_register(&gmm_fsm) == 0);
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200248}