blob: ea3194170ab73eb6e57eb2b908d9fc2b1f65b0a0 [file] [log] [blame]
Pau Espin Pedrolccd12522019-08-30 17:06:36 +02001#include <arpa/inet.h>
2
3#include <osmocom/core/tdef.h>
4
5#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
6
7#include <osmocom/sgsn/debug.h>
8#include <osmocom/sgsn/sgsn.h>
Alexander Couzenseb5aee52019-09-10 21:00:18 +02009#include <osmocom/sgsn/gprs_ranap.h>
Pau Espin Pedrolccd12522019-08-30 17:06:36 +020010
11#define X(s) (1 << (s))
12
13static const struct osmo_tdef_state_timeout mm_state_iu_fsm_timeouts[32] = {
14 [ST_PMM_DETACHED] = { },
Alexander Couzens3bad31b2019-09-11 02:17:31 +020015 /* non-spec -T3314 (User inactivity timer) */
16 [ST_PMM_CONNECTED] = { .T=-3314 },
Pau Espin Pedrolccd12522019-08-30 17:06:36 +020017 [ST_PMM_IDLE] = { },
18};
19
20#define mm_state_iu_fsm_state_chg(fi, NEXT_STATE) \
21 osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_iu_fsm_timeouts, sgsn->cfg.T_defs, -1)
22
23static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
24{
25 char buf[INET_ADDRSTRLEN];
26 struct sgsn_pdp_ctx *pdp;
27 llist_for_each_entry(pdp, &mm_ctx->pdp_list, list) {
28 LOGMMCTXP(LOGL_INFO, mm_ctx, "Changing GTP-U endpoints %s -> %s\n",
29 sgsn_gtp_ntoa(&pdp->lib->gsnlu),
30 inet_ntop(AF_INET, &sgsn->cfg.gtp_listenaddr.sin_addr, buf, sizeof(buf)));
31 sgsn_pdp_upd_gtp_u(pdp,
32 &sgsn->cfg.gtp_listenaddr.sin_addr,
33 sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
34 }
35}
36
37static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data)
38{
39 switch(event) {
40 case E_PMM_PS_ATTACH:
41 mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
42 break;
43 case E_PMM_IMPLICIT_DETACH:
44 break;
45 }
46}
47
48static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
49{
Alexander Couzenseb5aee52019-09-10 21:00:18 +020050 struct sgsn_mm_ctx *ctx = fi->priv;
Alexander Couzens3bad31b2019-09-11 02:17:31 +020051 const struct RANAP_Cause user_inactive_cause = {
52 .present = RANAP_Cause_PR_radioNetwork,
53 .choice.radioNetwork = RANAP_CauseRadioNetwork_user_inactivity,
54 };
Alexander Couzenseb5aee52019-09-10 21:00:18 +020055
Pau Espin Pedrolccd12522019-08-30 17:06:36 +020056 switch(event) {
57 case E_PMM_PS_CONN_RELEASE:
Alexander Couzenseb5aee52019-09-10 21:00:18 +020058 sgsn_ranap_iu_free(ctx);
Pau Espin Pedrolccd12522019-08-30 17:06:36 +020059 mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE);
60 break;
61 case E_PMM_IMPLICIT_DETACH:
Alexander Couzenseb5aee52019-09-10 21:00:18 +020062 sgsn_ranap_iu_release_free(ctx, NULL);
Pau Espin Pedrolccd12522019-08-30 17:06:36 +020063 mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
64 break;
Alexander Couzens3bad31b2019-09-11 02:17:31 +020065 case E_PMM_USER_INACTIVITY:
66 sgsn_ranap_iu_release_free(ctx, &user_inactive_cause);
67 mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
68 break;
Pau Espin Pedrolccd12522019-08-30 17:06:36 +020069 case E_PMM_RA_UPDATE:
70 break;
71 }
72}
73
74static void st_pmm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
75{
76 struct sgsn_mm_ctx *ctx = fi->priv;
77
78 mmctx_change_gtpu_endpoints_to_sgsn(ctx);
79}
80
81static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
82{
83 switch(event) {
84 case E_PMM_PS_CONN_ESTABLISH:
85 mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
86 break;
87 case E_PMM_IMPLICIT_DETACH:
88 mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
89 break;
90 }
91}
92
Alexander Couzens3bad31b2019-09-11 02:17:31 +020093static int pmm_state_fsm_timer_cb(struct osmo_fsm_inst *fi)
94{
95 switch(fi->state) {
96 case ST_PMM_CONNECTED:
97 /* timer for pmm state. state=CONNECTED: -T3314 (User inactivity timer) */
98 osmo_fsm_inst_dispatch(fi, E_PMM_USER_INACTIVITY, NULL);
99 break;
100 }
101
102 return 0;
103}
104
Pau Espin Pedrolccd12522019-08-30 17:06:36 +0200105static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
106 [ST_PMM_DETACHED] = {
107 .in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_IMPLICIT_DETACH),
108 .out_state_mask = X(ST_PMM_CONNECTED),
109 .name = "Detached",
110 .action = st_pmm_detached,
111 },
112 [ST_PMM_CONNECTED] = {
Alexander Couzens3bad31b2019-09-11 02:17:31 +0200113 .in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE)
114 | X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_USER_INACTIVITY),
Pau Espin Pedrolccd12522019-08-30 17:06:36 +0200115 .out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_IDLE),
116 .name = "Connected",
117 .action = st_pmm_connected,
118 },
119 [ST_PMM_IDLE] = {
120 .in_event_mask = X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_PS_CONN_ESTABLISH),
121 .out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_CONNECTED),
122 .name = "Idle",
123 .onenter = st_pmm_idle_on_enter,
124 .action = st_pmm_idle,
125 },
126};
127
128const struct value_string mm_state_iu_fsm_event_names[] = {
129 OSMO_VALUE_STRING(E_PMM_PS_ATTACH),
130 OSMO_VALUE_STRING(E_PMM_PS_CONN_RELEASE),
131 OSMO_VALUE_STRING(E_PMM_PS_CONN_ESTABLISH),
132 OSMO_VALUE_STRING(E_PMM_IMPLICIT_DETACH),
133 OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
Alexander Couzens3bad31b2019-09-11 02:17:31 +0200134 OSMO_VALUE_STRING(E_PMM_USER_INACTIVITY),
Pau Espin Pedrolccd12522019-08-30 17:06:36 +0200135 { 0, NULL }
136};
137
138struct osmo_fsm mm_state_iu_fsm = {
139 .name = "MM_STATE_Iu",
140 .states = mm_state_iu_fsm_states,
141 .num_states = ARRAY_SIZE(mm_state_iu_fsm_states),
142 .event_names = mm_state_iu_fsm_event_names,
Vadim Yanitskiy0e124d32019-10-09 18:32:47 +0700143 .timer_cb = pmm_state_fsm_timer_cb,
Pau Espin Pedrolccd12522019-08-30 17:06:36 +0200144 .log_subsys = DMM,
145};
146
147static __attribute__((constructor)) void mm_state_iu_fsm_init(void)
148{
149 osmo_fsm_register(&mm_state_iu_fsm);
150}