blob: 6e812d31d462f4a1d4dd486f2a04bf09361ef750 [file] [log] [blame]
Pau Espin Pedrol913dbcd2021-04-14 13:18:31 +02001/* TS 23.060 ยง 6.1.1 Mobility Management States (A/Gb mode) */
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 Pedrol02514bc2019-08-30 16:14:22 +020023#include <osmocom/core/tdef.h>
24
25#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
Alexander Couzens68880212019-09-10 16:32:05 +020026#include <osmocom/sgsn/gprs_llc.h>
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020027
28#include <osmocom/sgsn/debug.h>
29#include <osmocom/sgsn/sgsn.h>
30
31#define X(s) (1 << (s))
32
33static const struct osmo_tdef_state_timeout mm_state_gb_fsm_timeouts[32] = {
34 [ST_MM_IDLE] = { },
35 [ST_MM_READY] = { .T=3314 },
36 [ST_MM_STANDBY] = { },
37};
38
39#define mm_state_gb_fsm_state_chg(fi, NEXT_STATE) \
40 osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_gb_fsm_timeouts, sgsn->cfg.T_defs, -1)
41
Alexander Couzens68880212019-09-10 16:32:05 +020042static void st_mm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state) {
43 struct sgsn_mm_ctx *ctx = fi->priv;
44
Alexander Couzens4c7609a2019-09-11 03:00:47 +020045 /* FIXME: remove this timer when RAU has it's own fsm */
46 if (ctx->T == 3350 && osmo_timer_pending(&ctx->timer))
47 osmo_timer_del(&ctx->timer);
48
Alexander Couzens68880212019-09-10 16:32:05 +020049 if (ctx->gb.llme) {
50 gprs_llgmm_unassign(ctx->gb.llme);
51 ctx->gb.llme = NULL;
52 }
53}
54
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020055static void st_mm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
56{
57 switch(event) {
58 case E_MM_GPRS_ATTACH:
59 mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
60 break;
61 case E_MM_PDU_RECEPTION:
62 break;
63 }
64}
65
66static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
67{
68 unsigned long t_secs;
69
70 switch(event) {
71 case E_MM_READY_TIMER_EXPIRY:
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020072 mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
73 break;
Pau Espin Pedrol888052e2021-04-14 13:27:34 +020074 case E_MM_GPRS_DETACH:
Alexander Couzens12235312019-09-17 17:44:14 +020075 mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
76 break;
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020077 case E_MM_PDU_RECEPTION:
78 /* RE-arm the READY timer upon receival of Gb PDUs */
79 t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3314, OSMO_TDEF_S, -1);
80 osmo_timer_schedule(&fi->timer, t_secs, 0);
81 break;
82 case E_MM_RA_UPDATE:
83 break;
84 }
85}
86
87static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
88{
89 switch(event) {
90 case E_MM_PDU_RECEPTION:
91 mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
92 break;
Pau Espin Pedrol888052e2021-04-14 13:27:34 +020093 case E_MM_GPRS_DETACH:
Daniel Willmann7c86a1e2020-01-28 17:05:33 +010094 mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
95 break;
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +020096 }
97}
98
99static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
100 [ST_MM_IDLE] = {
101 .in_event_mask = X(E_MM_GPRS_ATTACH) | X(E_MM_PDU_RECEPTION),
102 .out_state_mask = X(ST_MM_READY),
Alexander Couzens68880212019-09-10 16:32:05 +0200103 .onenter = st_mm_idle_on_enter,
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +0200104 .name = "Idle",
105 .action = st_mm_idle,
106 },
107 [ST_MM_READY] = {
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200108 .in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_GPRS_DETACH) | X(E_MM_PDU_RECEPTION),
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +0200109 .out_state_mask = X(ST_MM_IDLE) | X(ST_MM_STANDBY),
110 .name = "Ready",
111 .action = st_mm_ready,
112 },
113 [ST_MM_STANDBY] = {
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200114 .in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_GPRS_DETACH),
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +0200115 .out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
116 .name = "Standby",
117 .action = st_mm_standby,
118 },
119};
120
121const struct value_string mm_state_gb_fsm_event_names[] = {
122 OSMO_VALUE_STRING(E_MM_GPRS_ATTACH),
123 OSMO_VALUE_STRING(E_MM_PDU_RECEPTION),
Pau Espin Pedrol888052e2021-04-14 13:27:34 +0200124 OSMO_VALUE_STRING(E_MM_GPRS_DETACH),
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +0200125 OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
126 OSMO_VALUE_STRING(E_MM_RA_UPDATE),
127 { 0, NULL }
128};
129
130int mm_state_gb_fsm_timer_cb(struct osmo_fsm_inst *fi)
131{
132 switch(fi->state) {
133 case ST_MM_READY:
134 /* timer for mm state. state=READY: T3314 (aka TS 23.060 "READY timer") */
135 osmo_fsm_inst_dispatch(fi, E_MM_READY_TIMER_EXPIRY, NULL);
136 break;
137 }
138
139 return 0;
140}
141
142struct osmo_fsm mm_state_gb_fsm = {
143 .name = "MM_STATE_Gb",
144 .states = mm_state_gb_fsm_states,
145 .num_states = ARRAY_SIZE(mm_state_gb_fsm_states),
146 .event_names = mm_state_gb_fsm_event_names,
147 .log_subsys = DMM,
148 .timer_cb = mm_state_gb_fsm_timer_cb,
149};
150
151static __attribute__((constructor)) void mm_state_gb_fsm_init(void)
152{
Harald Weltea868e172019-12-01 13:23:53 +0100153 OSMO_ASSERT(osmo_fsm_register(&mm_state_gb_fsm) == 0);
Pau Espin Pedrol02514bc2019-08-30 16:14:22 +0200154}