Move struct sgsn_ggsn_ctx to its own file gtp_ggsn.{c,h}

Similar to what we already have for struct sgsn_mme_ctx in
gtp_mme.{c,h}.

This is just the nth step of properly splitting different
protocol layers, data model, etc.

Change-Id: Iad1895f09e43e299df7bb126bf52fdb98268392e
changes/62/30862/2
Pau Espin 2023-01-04 21:30:28 +01:00
parent fc1a5538d0
commit 5f4736aa85
13 changed files with 229 additions and 169 deletions

View File

@ -22,6 +22,7 @@ noinst_HEADERS = \
gprs_subscriber.h \
gprs_utils.h \
gtphub.h \
gtp_ggsn.h \
gtp_mme.h \
sgsn.h \
sgsn_rim.h \

View File

@ -20,6 +20,7 @@
struct gprs_llc_lle;
struct ctrl_handle;
struct gprs_subscr;
struct sgsn_ggsn_ctx;
enum gsm48_gsm_cause;
@ -366,35 +367,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
struct sgsn_ggsn_ctx {
struct llist_head list;
uint32_t id;
unsigned int gtp_version;
struct in_addr remote_addr;
int remote_restart_ctr;
struct gsn_t *gsn;
struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
struct osmo_timer_list echo_timer;
unsigned int echo_interval;
};
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
#define LOGGGSN(ggc, level, fmt, args...) { \
char _buf[INET_ADDRSTRLEN]; \
LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
} while (0)
struct apn_ctx {
struct llist_head list;
struct sgsn_ggsn_ctx *ggsn;

View File

@ -0,0 +1,40 @@
#pragma once
#include <stdint.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/gprs/protocol/gsm_24_301.h>
struct gsn_t;
struct sgsn_pdp_ctx;
struct sgsn_ggsn_ctx {
struct llist_head list;
uint32_t id;
unsigned int gtp_version;
struct in_addr remote_addr;
int remote_restart_ctr;
struct gsn_t *gsn;
struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
struct osmo_timer_list echo_timer;
unsigned int echo_interval;
};
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
#define LOGGGSN(ggc, level, fmt, args...) { \
char _buf[INET_ADDRSTRLEN]; \
LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
} while (0)

View File

@ -54,6 +54,7 @@ osmo_sgsn_SOURCES = \
gprs_sndcp_pcomp.c \
gprs_sndcp_vty.c \
gprs_sndcp_xid.c \
gtp_ggsn.c \
gtp_mme.c \
sgsn_main.c \
sgsn_vty.c \

View File

@ -37,6 +37,7 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gtp_ggsn.h>
/* Send RAB activation requests for all PDP contexts */
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)

View File

@ -47,6 +47,7 @@
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <pdp.h>
@ -535,88 +536,6 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
talloc_free(pdp);
}
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
{
bool pending = osmo_timer_pending(&ggc->echo_timer);
/* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
if (!pending)
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
} else {
if (pending)
osmo_timer_del(&ggc->echo_timer);
}
}
/* GGSN contexts */
static void echo_timer_cb(void *data)
{
struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
sgsn_ggsn_echo_req(ggc);
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_ctx);
if (!ggc)
return NULL;
ggc->id = id;
ggc->gtp_version = 1;
ggc->remote_restart_ctr = -1;
/* if we are called from config file parse, this gsn doesn't exist yet */
ggc->gsn = sgsn->gsn;
INIT_LLIST_HEAD(&ggc->pdp_list);
osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
llist_add(&ggc->list, &sgsn_ggsn_ctxts);
return ggc;
}
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
{
OSMO_ASSERT(llist_empty(&ggc->pdp_list));
llist_del(&ggc->list);
talloc_free(ggc);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
if (id == ggc->id)
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = sgsn_ggsn_ctx_by_id(id);
if (!ggc)
ggc = sgsn_ggsn_ctx_alloc(id);
return ggc;
}
/* APN contexts */
static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
@ -764,64 +683,6 @@ failed:
return GSM_RESERVED_TMSI;
}
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
{
/* the MM context can be deleted while the GGSN is not reachable or
* if has been crashed. */
if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) {
gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true);
sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx);
} else {
/* FIXME: GPRS paging in case MS is SUSPENDED */
LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
"recovery\n");
/* FIXME: how to tell this to libgtp? */
sgsn_pdp_ctx_free(pctx);
}
}
/* High-level function to be called in case a GGSN has disappeared or
* otherwise lost state (recovery procedure). It will detach all related pdp ctx
* from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
* be kept alive to allow handling later message which contained the Recovery IE. */
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
{
int num = 0;
struct sgsn_pdp_ctx *pdp, *pdp2;
llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
if (pdp == except)
continue;
sgsn_ggsn_ctx_drop_pdp(pdp);
num++;
}
return num;
}
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
{
return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
}
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
}
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_del(&pdp->ggsn_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
if (pdp->destroy_ggsn)
sgsn_ggsn_ctx_free(pdp->ggsn);
pdp->ggsn = NULL;
/* Drop references to libgtp since the conn is down */
if (pdp->lib)
pdp_freepdp(pdp->lib);
pdp->lib = NULL;
}
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
{
OSMO_ASSERT(mmctx != NULL);

View File

@ -36,6 +36,7 @@
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_llc.h>

178
src/sgsn/gtp_ggsn.c Normal file
View File

@ -0,0 +1,178 @@
/* GGSN context (peer) */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2023 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_sm.h>
extern void *tall_sgsn_ctx;
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
{
bool pending = osmo_timer_pending(&ggc->echo_timer);
/* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
if (!pending)
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
} else {
if (pending)
osmo_timer_del(&ggc->echo_timer);
}
}
/* GGSN contexts */
static void echo_timer_cb(void *data)
{
struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
sgsn_ggsn_echo_req(ggc);
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_ctx);
if (!ggc)
return NULL;
ggc->id = id;
ggc->gtp_version = 1;
ggc->remote_restart_ctr = -1;
/* if we are called from config file parse, this gsn doesn't exist yet */
ggc->gsn = sgsn->gsn;
INIT_LLIST_HEAD(&ggc->pdp_list);
osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
llist_add(&ggc->list, &sgsn_ggsn_ctxts);
return ggc;
}
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
{
OSMO_ASSERT(llist_empty(&ggc->pdp_list));
llist_del(&ggc->list);
talloc_free(ggc);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
if (id == ggc->id)
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = sgsn_ggsn_ctx_by_id(id);
if (!ggc)
ggc = sgsn_ggsn_ctx_alloc(id);
return ggc;
}
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
{
/* the MM context can be deleted while the GGSN is not reachable or
* if has been crashed. */
if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) {
gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true);
sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx);
} else {
/* FIXME: GPRS paging in case MS is SUSPENDED */
LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
"recovery\n");
/* FIXME: how to tell this to libgtp? */
sgsn_pdp_ctx_free(pctx);
}
}
/* High-level function to be called in case a GGSN has disappeared or
* otherwise lost state (recovery procedure). It will detach all related pdp ctx
* from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
* be kept alive to allow handling later message which contained the Recovery IE. */
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
{
int num = 0;
struct sgsn_pdp_ctx *pdp, *pdp2;
llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
if (pdp == except)
continue;
sgsn_ggsn_ctx_drop_pdp(pdp);
num++;
}
return num;
}
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
{
return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
}
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
}
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_del(&pdp->ggsn_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
if (pdp->destroy_ggsn)
sgsn_ggsn_ctx_free(pdp->ggsn);
pdp->ggsn = NULL;
/* Drop references to libgtp since the conn is down */
if (pdp->lib)
pdp_freepdp(pdp->lib);
pdp->lib = NULL;
}

View File

@ -27,6 +27,7 @@
#include <osmocom/gsm/apn.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <gtp.h>
#include <pdp.h>

View File

@ -55,6 +55,7 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/gprs_bssgp.h>

View File

@ -39,6 +39,7 @@
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_bssgp.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/gsupclient/gsup_client.h>

View File

@ -56,6 +56,7 @@ sgsn_test_LDADD = \
$(top_builddir)/src/sgsn/gprs_gmm_fsm.o \
$(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \
$(top_builddir)/src/sgsn/gprs_sgsn.o \
$(top_builddir)/src/sgsn/gtp_ggsn.o \
$(top_builddir)/src/sgsn/gtp_mme.o \
$(top_builddir)/src/sgsn/sgsn_vty.o \
$(top_builddir)/src/sgsn/sgsn_libgtp.o \

View File

@ -38,6 +38,7 @@
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <stdio.h>