blob: 78946b5b1c7a634ad2cc1adde95a50a60ddd8c49 [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;
83 /* case E_GMM_NET_INIT_DETACH_REQ:
84 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
85 break; */
86 /* case E_GMM_MS_INIT_DETACH_REQ:
87 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
88 break; */
89 case E_GMM_SUSPEND:
90 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_SUSPENDED);
91 break;
92 }
93}
94
95static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
96{
97 switch(event) {
Harald Welte5e1a4862020-06-17 10:29:46 +020098 case E_GMM_RESUME: /* explicit BSSGP RESUME from BSS */
Pau Espin Pedrol31c46572019-09-02 16:45:27 +020099 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
100 break;
Harald Welte5e1a4862020-06-17 10:29:46 +0200101 case E_GMM_COMMON_PROC_INIT_REQ: /* implicit resume from MS */
102 gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
103 break;
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200104 }
105}
106
107static void st_gmm_deregistered_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
108{
109 switch(event) {
110 /* TODO: events not used in osmo-sgsn code
111 case E_GMM_DETACH_ACCEPTED:
112 case E_GMM_LOWER_LAYER_FAILED:
113 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
114 break;
115 */
116 }
117}
118
119static struct osmo_fsm_state gmm_fsm_states[] = {
120 [ST_GMM_DEREGISTERED] = {
121 .in_event_mask =
122 X(E_GMM_COMMON_PROC_INIT_REQ) |
123 X(E_GMM_ATTACH_SUCCESS),
124 .out_state_mask = X(ST_GMM_COMMON_PROC_INIT),
125 .name = "Deregistered",
126 .action = st_gmm_deregistered,
127 },
128 [ST_GMM_COMMON_PROC_INIT] = {
129 .in_event_mask =
130 /* X(E_GMM_LOWER_LAYER_FAILED) | */
131 /* X(E_GMM_COMMON_PROC_FAILED) | */
132 X(E_GMM_COMMON_PROC_SUCCESS) |
Pau Espin Pedrolc26072a2021-03-25 16:57:22 +0100133 X(E_GMM_ATTACH_SUCCESS) |
134 X(E_GMM_COMMON_PROC_INIT_REQ),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200135 .out_state_mask =
136 X(ST_GMM_DEREGISTERED) |
137 X(ST_GMM_REGISTERED_NORMAL),
138 .name = "CommonProcedureInitiated",
139 .action = st_gmm_common_proc_init,
140 },
141 [ST_GMM_REGISTERED_NORMAL] = {
142 .in_event_mask =
143 X(E_GMM_COMMON_PROC_INIT_REQ) |
144 /* X(E_GMM_NET_INIT_DETACH_REQ) | */
145 /* X(E_GMM_MS_INIT_DETACH_REQ) | */
146 X(E_GMM_SUSPEND),
147 .out_state_mask =
148 X(ST_GMM_DEREGISTERED) |
149 X(ST_GMM_COMMON_PROC_INIT) |
150 X(ST_GMM_DEREGISTERED_INIT) |
151 X(ST_GMM_REGISTERED_SUSPENDED),
152 .name = "Registered.NORMAL",
153 .action = st_gmm_registered_normal,
154 },
155 [ST_GMM_REGISTERED_SUSPENDED] = {
Harald Welte5e1a4862020-06-17 10:29:46 +0200156 .in_event_mask = X(E_GMM_RESUME) |
157 X(E_GMM_COMMON_PROC_INIT_REQ),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200158 .out_state_mask =
159 X(ST_GMM_DEREGISTERED) |
Harald Welte5e1a4862020-06-17 10:29:46 +0200160 X(ST_GMM_REGISTERED_NORMAL) |
161 X(ST_GMM_COMMON_PROC_INIT),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200162 .name = "Registered.SUSPENDED",
163 .action = st_gmm_registered_suspended,
164 },
165 [ST_GMM_DEREGISTERED_INIT] = {
166 .in_event_mask = 0
167 /* X(E_GMM_DETACH_ACCEPTED) | */
168 /* X(E_GMM_LOWER_LAYER_FAILED) */,
169 .out_state_mask = X(ST_GMM_DEREGISTERED),
170 .name = "DeregisteredInitiated",
171 .action = st_gmm_deregistered_init,
172 },
173};
174
175const struct value_string gmm_fsm_event_names[] = {
176 OSMO_VALUE_STRING(E_GMM_COMMON_PROC_INIT_REQ),
177 /* OSMO_VALUE_STRING(E_GMM_COMMON_PROC_FAILED), */
178 /* OSMO_VALUE_STRING(E_GMM_LOWER_LAYER_FAILED), */
179 OSMO_VALUE_STRING(E_GMM_COMMON_PROC_SUCCESS),
180 OSMO_VALUE_STRING(E_GMM_ATTACH_SUCCESS),
181 /* OSMO_VALUE_STRING(E_GMM_NET_INIT_DETACH_REQ), */
182 /* OSMO_VALUE_STRING(E_GMM_MS_INIT_DETACH_REQ), */
183 /* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
184 OSMO_VALUE_STRING(E_GMM_SUSPEND),
185 OSMO_VALUE_STRING(E_GMM_CLEANUP),
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200186 OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200187 { 0, NULL }
188};
189
190void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200191 struct sgsn_mm_ctx *mmctx = fi->priv;
192 struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data;
193
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200194 switch (event) {
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200195 case E_GMM_RAT_CHANGE:
196
197 switch (fi->state) {
198 case ST_GMM_COMMON_PROC_INIT:
199 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
200 default:
201 if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200202 osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200203 else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200204 osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200205 mmctx->gb.llme = rat_chg->llme;
206 }
207
208 mmctx->ran_type = rat_chg->new_ran_type;
209 break;
210 }
211
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200212 case E_GMM_CLEANUP:
213 switch (fi->state) {
214 case ST_GMM_DEREGISTERED:
215 break;
216 default:
217 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
218 break;
219 }
220 }
221}
222
223int gmm_fsm_timer_cb(struct osmo_fsm_inst *fi)
224{
225 return 0;
226}
227
228struct osmo_fsm gmm_fsm = {
229 .name = "GMM",
230 .states = gmm_fsm_states,
231 .num_states = ARRAY_SIZE(gmm_fsm_states),
232 .event_names = gmm_fsm_event_names,
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200233 .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200234 .allstate_action = gmm_fsm_allstate_action,
235 .log_subsys = DMM,
236 .timer_cb = gmm_fsm_timer_cb,
237};
238
239static __attribute__((constructor)) void gmm_fsm_init(void)
240{
Harald Weltea868e172019-12-01 13:23:53 +0100241 OSMO_ASSERT(osmo_fsm_register(&gmm_fsm) == 0);
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200242}