aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/sgsn/gprs_sgsn.h4
-rw-r--r--include/osmocom/sgsn/sgsn.h1
-rw-r--r--src/gprs/gprs_sgsn.c25
-rw-r--r--src/gprs/sgsn_libgtp.c5
-rw-r--r--src/gprs/sgsn_vty.c25
5 files changed, 58 insertions, 2 deletions
diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h
index 33b12dc25..5f3088961 100644
--- a/include/osmocom/sgsn/gprs_sgsn.h
+++ b/include/osmocom/sgsn/gprs_sgsn.h
@@ -353,6 +353,8 @@ struct sgsn_ggsn_ctx {
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;
+ int echo_interval;
};
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
@@ -360,6 +362,8 @@ 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);
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);
struct apn_ctx {
struct llist_head list;
diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h
index 829a8fc6e..dae9d12aa 100644
--- a/include/osmocom/sgsn/sgsn.h
+++ b/include/osmocom/sgsn/sgsn.h
@@ -171,6 +171,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
struct tlv_parsed *tp);
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
+void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
/* gprs_sndcp.c */
diff --git a/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c
index a58e504c5..55ce09616 100644
--- a/src/gprs/gprs_sgsn.c
+++ b/src/gprs/gprs_sgsn.c
@@ -411,7 +411,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
return NULL;
}
llist_add(&pdp->list, &mm->pdp_list);
- llist_add(&pdp->ggsn_list, &ggsn->pdp_list);
+ sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
return pdp;
@@ -466,7 +466,7 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
if (pdp->mm)
llist_del(&pdp->list);
if (pdp->ggsn)
- llist_del(&pdp->ggsn_list);
+ sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
llist_del(&pdp->g_list);
/* _if_ we still have a library handle, at least set it to NULL
@@ -487,6 +487,12 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
}
/* 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)
{
@@ -499,9 +505,11 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
ggc->id = id;
ggc->gtp_version = 1;
ggc->remote_restart_ctr = -1;
+ ggc->echo_interval = -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;
@@ -722,6 +730,19 @@ int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
return num;
}
+void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
+{
+ if (llist_empty(&ggc->pdp_list) && ggc->echo_interval > 0)
+ osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
+ llist_add(&pdp->ggsn_list, &ggc->pdp_list);
+}
+void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
+{
+ llist_del(&pdp->ggsn_list);
+ if (llist_empty(&ggc->pdp_list) && osmo_timer_pending(&ggc->echo_timer))
+ osmo_timer_del(&ggc->echo_timer);
+}
+
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
{
OSMO_ASSERT(mmctx != NULL);
diff --git a/src/gprs/sgsn_libgtp.c b/src/gprs/sgsn_libgtp.c
index 2da8c4a74..88cea5d4a 100644
--- a/src/gprs/sgsn_libgtp.c
+++ b/src/gprs/sgsn_libgtp.c
@@ -460,6 +460,11 @@ void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen)
gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
}
+void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc)
+{
+ gtp_echo_req(ggc->gsn, ggc->gtp_version, NULL, &ggc->remote_addr);
+}
+
#ifdef BUILD_IU
/* Callback for RAB assignment response */
int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
diff --git a/src/gprs/sgsn_vty.c b/src/gprs/sgsn_vty.c
index 07d4293db..9f9332c32 100644
--- a/src/gprs/sgsn_vty.c
+++ b/src/gprs/sgsn_vty.c
@@ -23,6 +23,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
+#include <inttypes.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
@@ -181,6 +182,9 @@ static int config_write_sgsn(struct vty *vty)
inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
gctx->gtp_version, VTY_NEWLINE);
+ if (gctx->echo_interval != -1)
+ vty_out(vty, " ggsn %u echo-interval %"PRId32"%s",
+ gctx->id, gctx->echo_interval, VTY_NEWLINE);
}
if (sgsn->cfg.dynamic_lookup)
@@ -356,6 +360,26 @@ DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
return CMD_SUCCESS;
}
+/* Seee 3GPP TS 29.060 section 7.2.1 */
+DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
+ "ggsn <0-255> echo-interval <1-36000>",
+ GGSN_STR "GGSN Number\n"
+ "Send an echo request to this static GGSN every interval.\n"
+ "Interval between echo requests in seconds.\n")
+{
+ uint32_t id = atoi(argv[0]);
+ struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+
+ ggc->echo_interval = atoi(argv[1]);
+
+ if (ggc->echo_interval < 60)
+ vty_out(vty, "%% 3GPP TS 29.060 section states inteval should " \
+ "not be lower than 60 seconds, use this value for " \
+ "testing purposes only!%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
"ggsn dynamic",
GGSN_STR
@@ -1277,6 +1301,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
+ install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
install_element(SGSN_NODE, &cfg_auth_policy_cmd);
install_element(SGSN_NODE, &cfg_encrypt_cmd);