blob: 886726c680c1d32bc5e0184cbc185bd1c8a4a380 [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) {
60 /* TODO: events not used
61 case E_GMM_LOWER_LAYER_FAILED:
62 case E_GMM_COMMON_PROC_FAILED:
63 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
64 break;
65 */
66 case E_GMM_COMMON_PROC_SUCCESS:
67 case E_GMM_ATTACH_SUCCESS:
68 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
69 break;
70 }
71}
72
73static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, void *data)
74{
75 switch(event) {
76 case E_GMM_COMMON_PROC_INIT_REQ:
77 gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
78 break;
79 /* case E_GMM_NET_INIT_DETACH_REQ:
80 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
81 break; */
82 /* case E_GMM_MS_INIT_DETACH_REQ:
83 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
84 break; */
85 case E_GMM_SUSPEND:
86 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_SUSPENDED);
87 break;
88 }
89}
90
91static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
92{
93 switch(event) {
Harald Welte5e1a4862020-06-17 10:29:46 +020094 case E_GMM_RESUME: /* explicit BSSGP RESUME from BSS */
Pau Espin Pedrol31c46572019-09-02 16:45:27 +020095 gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
96 break;
Harald Welte5e1a4862020-06-17 10:29:46 +020097 case E_GMM_COMMON_PROC_INIT_REQ: /* implicit resume from MS */
98 gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
99 break;
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200100 }
101}
102
103static void st_gmm_deregistered_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
104{
105 switch(event) {
106 /* TODO: events not used in osmo-sgsn code
107 case E_GMM_DETACH_ACCEPTED:
108 case E_GMM_LOWER_LAYER_FAILED:
109 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
110 break;
111 */
112 }
113}
114
115static struct osmo_fsm_state gmm_fsm_states[] = {
116 [ST_GMM_DEREGISTERED] = {
117 .in_event_mask =
118 X(E_GMM_COMMON_PROC_INIT_REQ) |
119 X(E_GMM_ATTACH_SUCCESS),
120 .out_state_mask = X(ST_GMM_COMMON_PROC_INIT),
121 .name = "Deregistered",
122 .action = st_gmm_deregistered,
123 },
124 [ST_GMM_COMMON_PROC_INIT] = {
125 .in_event_mask =
126 /* X(E_GMM_LOWER_LAYER_FAILED) | */
127 /* X(E_GMM_COMMON_PROC_FAILED) | */
128 X(E_GMM_COMMON_PROC_SUCCESS) |
129 X(E_GMM_ATTACH_SUCCESS),
130 .out_state_mask =
131 X(ST_GMM_DEREGISTERED) |
132 X(ST_GMM_REGISTERED_NORMAL),
133 .name = "CommonProcedureInitiated",
134 .action = st_gmm_common_proc_init,
135 },
136 [ST_GMM_REGISTERED_NORMAL] = {
137 .in_event_mask =
138 X(E_GMM_COMMON_PROC_INIT_REQ) |
139 /* X(E_GMM_NET_INIT_DETACH_REQ) | */
140 /* X(E_GMM_MS_INIT_DETACH_REQ) | */
141 X(E_GMM_SUSPEND),
142 .out_state_mask =
143 X(ST_GMM_DEREGISTERED) |
144 X(ST_GMM_COMMON_PROC_INIT) |
145 X(ST_GMM_DEREGISTERED_INIT) |
146 X(ST_GMM_REGISTERED_SUSPENDED),
147 .name = "Registered.NORMAL",
148 .action = st_gmm_registered_normal,
149 },
150 [ST_GMM_REGISTERED_SUSPENDED] = {
Harald Welte5e1a4862020-06-17 10:29:46 +0200151 .in_event_mask = X(E_GMM_RESUME) |
152 X(E_GMM_COMMON_PROC_INIT_REQ),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200153 .out_state_mask =
154 X(ST_GMM_DEREGISTERED) |
Harald Welte5e1a4862020-06-17 10:29:46 +0200155 X(ST_GMM_REGISTERED_NORMAL) |
156 X(ST_GMM_COMMON_PROC_INIT),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200157 .name = "Registered.SUSPENDED",
158 .action = st_gmm_registered_suspended,
159 },
160 [ST_GMM_DEREGISTERED_INIT] = {
161 .in_event_mask = 0
162 /* X(E_GMM_DETACH_ACCEPTED) | */
163 /* X(E_GMM_LOWER_LAYER_FAILED) */,
164 .out_state_mask = X(ST_GMM_DEREGISTERED),
165 .name = "DeregisteredInitiated",
166 .action = st_gmm_deregistered_init,
167 },
168};
169
170const struct value_string gmm_fsm_event_names[] = {
171 OSMO_VALUE_STRING(E_GMM_COMMON_PROC_INIT_REQ),
172 /* OSMO_VALUE_STRING(E_GMM_COMMON_PROC_FAILED), */
173 /* OSMO_VALUE_STRING(E_GMM_LOWER_LAYER_FAILED), */
174 OSMO_VALUE_STRING(E_GMM_COMMON_PROC_SUCCESS),
175 OSMO_VALUE_STRING(E_GMM_ATTACH_SUCCESS),
176 /* OSMO_VALUE_STRING(E_GMM_NET_INIT_DETACH_REQ), */
177 /* OSMO_VALUE_STRING(E_GMM_MS_INIT_DETACH_REQ), */
178 /* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
179 OSMO_VALUE_STRING(E_GMM_SUSPEND),
180 OSMO_VALUE_STRING(E_GMM_CLEANUP),
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200181 OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200182 { 0, NULL }
183};
184
185void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200186 struct sgsn_mm_ctx *mmctx = fi->priv;
187 struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data;
188
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200189 switch (event) {
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200190 case E_GMM_RAT_CHANGE:
191
192 switch (fi->state) {
193 case ST_GMM_COMMON_PROC_INIT:
194 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
195 default:
196 if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
197 osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
198 else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
199 osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
200 mmctx->gb.llme = rat_chg->llme;
201 }
202
203 mmctx->ran_type = rat_chg->new_ran_type;
204 break;
205 }
206
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200207 case E_GMM_CLEANUP:
208 switch (fi->state) {
209 case ST_GMM_DEREGISTERED:
210 break;
211 default:
212 gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
213 break;
214 }
215 }
216}
217
218int gmm_fsm_timer_cb(struct osmo_fsm_inst *fi)
219{
220 return 0;
221}
222
223struct osmo_fsm gmm_fsm = {
224 .name = "GMM",
225 .states = gmm_fsm_states,
226 .num_states = ARRAY_SIZE(gmm_fsm_states),
227 .event_names = gmm_fsm_event_names,
Alexander Couzens91a8bbd2019-09-11 03:38:14 +0200228 .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200229 .allstate_action = gmm_fsm_allstate_action,
230 .log_subsys = DMM,
231 .timer_cb = gmm_fsm_timer_cb,
232};
233
234static __attribute__((constructor)) void gmm_fsm_init(void)
235{
Harald Weltea868e172019-12-01 13:23:53 +0100236 OSMO_ASSERT(osmo_fsm_register(&gmm_fsm) == 0);
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200237}