diff options
-rw-r--r-- | include/osmocom/sgsn/gprs_sgsn.h | 4 | ||||
-rw-r--r-- | include/osmocom/sgsn/sgsn.h | 1 | ||||
-rw-r--r-- | src/gprs/gprs_sgsn.c | 25 | ||||
-rw-r--r-- | src/gprs/sgsn_libgtp.c | 5 | ||||
-rw-r--r-- | src/gprs/sgsn_vty.c | 25 |
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); |