From d923cff170904e4d22ef00dd410b0d6256f95068 Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Tue, 1 Dec 2020 01:03:52 +0100 Subject: [PATCH] gprs_ns2: introduce NS dialects A NS dialect describes how the NS Entity interacts with different virtual circuits. E.g. ipaccess use reset/block on udp and is a dynamic connection. A single NS Entity can only support one dialect. This can be later used to protect a NS Entity against dynamic NS virtual circuits of a different type. It further allows a bind to support multiple dialects at the same time. Change-Id: Ia118bb6f994845d84db09de7a94856f5ca573404 --- include/osmocom/gprs/gprs_ns2.h | 17 +++++++--- src/gb/gprs_ns2.c | 59 +++++++++++++++++++++++---------- src/gb/gprs_ns2_fr.c | 5 ++- src/gb/gprs_ns2_frgre.c | 2 -- src/gb/gprs_ns2_internal.h | 14 ++++---- src/gb/gprs_ns2_udp.c | 12 +++++-- src/gb/gprs_ns2_vty.c | 54 ++++-------------------------- src/gb/libosmogb.map | 2 -- 8 files changed, 79 insertions(+), 86 deletions(-) diff --git a/include/osmocom/gprs/gprs_ns2.h b/include/osmocom/gprs/gprs_ns2.h index 45753292d..6140da242 100644 --- a/include/osmocom/gprs/gprs_ns2.h +++ b/include/osmocom/gprs/gprs_ns2.h @@ -32,6 +32,14 @@ enum gprs_ns2_vc_mode { NS2_VC_MODE_ALIVE, }; +enum gprs_ns2_dialect { + NS2_DIALECT_UNDEF, + NS2_DIALECT_STATIC_ALIVE, + NS2_DIALECT_STATIC_RESETBLOCK, + NS2_DIALECT_IPACCESS, + NS2_DIALECT_SNS, +}; + /*! Osmocom NS link layer types */ enum gprs_ns2_ll { GPRS_NS2_LL_UDP, /*!< NS/UDP/IP */ @@ -144,7 +152,8 @@ int gprs_ns2_nse_foreach_nsvc(struct gprs_ns2_nse *nse, gprs_ns2_foreach_nsvc_cb cb, void *cb_data); struct gprs_ns2_nse *gprs_ns2_nse_by_nsei(struct gprs_ns2_inst *nsi, uint16_t nsei); struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nsei, - enum gprs_ns2_ll linklayer); + enum gprs_ns2_ll linklayer, + enum gprs_ns2_dialect dialect); uint16_t gprs_ns2_nse_nsei(struct gprs_ns2_nse *nse); void gprs_ns2_free_nse(struct gprs_ns2_nse *nse); void gprs_ns2_free_nses(struct gprs_ns2_inst *nsi); @@ -160,7 +169,6 @@ int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi, struct gprs_ns2_vc_bind **result); struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi, const struct osmo_sockaddr *sockaddr); -void gprs_ns2_bind_set_mode(struct gprs_ns2_vc_bind *bind, enum gprs_ns2_vc_mode mode); /* FR VL driver */ struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif( @@ -188,7 +196,8 @@ struct gprs_ns2_vc *gprs_ns2_ip_connect(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *gprs_ns2_ip_connect2(struct gprs_ns2_vc_bind *bind, const struct osmo_sockaddr *remote, uint16_t nsei, - uint16_t nsvci); + uint16_t nsvci, + enum gprs_ns2_dialect dialect); struct gprs_ns2_vc *gprs_ns2_ip_connect_inactive(struct gprs_ns2_vc_bind *bind, const struct osmo_sockaddr *remote, struct gprs_ns2_nse *nse, @@ -238,7 +247,5 @@ const char *gprs_ns2_nsvc_state_name(struct gprs_ns2_vc *nsvc); int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi, const struct osmo_sockaddr_str *default_bind); int gprs_ns2_vty_create(); -void gprs_ns2_vty_force_vc_mode(bool force, enum gprs_ns2_vc_mode mode, const char *reason); - /*! @} */ diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c index d90ba850b..920fa684c 100644 --- a/src/gb/gprs_ns2.c +++ b/src/gb/gprs_ns2.c @@ -492,7 +492,8 @@ void ns2_prim_status_ind(struct gprs_ns2_nse *nse, * \param[in] nse The NS Entity on which we operate * \param[in] initiater - if this is an incoming remote (!initiater) or a local outgoing connection (initater) * \return newly allocated NS-VC on success; NULL on error */ -struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_nse *nse, bool initiater) +struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_nse *nse, bool initiater, + enum gprs_ns2_vc_mode vc_mode) { struct gprs_ns2_vc *nsvc = talloc_zero(bind, struct gprs_ns2_vc); @@ -501,7 +502,7 @@ struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_ nsvc->bind = bind; nsvc->nse = nse; - nsvc->mode = bind->vc_mode; + nsvc->mode = vc_mode; nsvc->sig_weight = 1; nsvc->data_weight = 1; @@ -672,7 +673,8 @@ struct gprs_ns2_vc *gprs_ns2_nsvc_by_nsvci(struct gprs_ns2_inst *nsi, uint16_t n * \param[in] nsi NS instance in which to create NS Entity * \param[in] nsei NS Entity Identifier of to-be-created NSE * \returns newly-allocated NS-E in successful case; NULL on error */ -struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nsei, enum gprs_ns2_ll linklayer) +struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nsei, + enum gprs_ns2_ll linklayer, enum gprs_ns2_dialect dialect) { struct gprs_ns2_nse *nse; @@ -686,6 +688,7 @@ struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nse if (!nse) return NULL; + nse->dialect = dialect; nse->ll = linklayer; nse->nsei = nsei; nse->nsi = nsi; @@ -765,6 +768,8 @@ enum gprs_ns2_cs ns2_create_vc(struct gprs_ns2_vc_bind *bind, struct tlv_parsed tp; struct gprs_ns2_vc *nsvc; struct gprs_ns2_nse *nse; + enum gprs_ns2_dialect dialect; + enum gprs_ns2_vc_mode vc_mode; uint16_t nsvci; uint16_t nsei; @@ -794,8 +799,10 @@ enum gprs_ns2_cs ns2_create_vc(struct gprs_ns2_vc_bind *bind, return GPRS_NS2_CS_SKIPPED; case NS_PDUT_RESET: /* accept PDU RESET when vc_mode matches */ - if (bind->vc_mode == NS2_VC_MODE_BLOCKRESET) + if (bind->accept_ipaccess) { + dialect = NS2_DIALECT_IPACCESS; break; + } rc = reject_status_msg(msg, &tp, reject, NS_CAUSE_PDU_INCOMP_PSTATE); if (rc < 0) { @@ -837,13 +844,14 @@ enum gprs_ns2_cs ns2_create_vc(struct gprs_ns2_vc_bind *bind, return GPRS_NS2_CS_SKIPPED; } - nse = gprs_ns2_create_nse(bind->nsi, nsei, bind->ll); + nse = gprs_ns2_create_nse(bind->nsi, nsei, bind->ll, dialect); if (!nse) { return GPRS_NS2_CS_ERROR; } } - nsvc = ns2_vc_alloc(bind, nse, false); + vc_mode = gprs_ns2_dialect_to_vc_mode(dialect); + nsvc = ns2_vc_alloc(bind, nse, false, vc_mode); if (!nsvc) return GPRS_NS2_CS_SKIPPED; @@ -911,12 +919,13 @@ struct gprs_ns2_vc *gprs_ns2_ip_connect(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *gprs_ns2_ip_connect2(struct gprs_ns2_vc_bind *bind, const struct osmo_sockaddr *remote, uint16_t nsei, - uint16_t nsvci) + uint16_t nsvci, + enum gprs_ns2_dialect dialect) { struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei); if (!nse) { - nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_UDP); + nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_UDP, dialect); if (!nse) return NULL; } @@ -937,11 +946,19 @@ int gprs_ns2_ip_connect_sns(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc; if (!nse) { - nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_UDP); + nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_UDP, NS2_DIALECT_SNS); if (!nse) return -1; } + if (nse->ll != GPRS_NS2_LL_UDP) { + return -2; + } + + if (nse->dialect != NS2_DIALECT_SNS) { + return -2; + } + nsvc = gprs_ns2_ip_bind_connect(bind, nse, remote); if (!nsvc) return -1; @@ -1199,14 +1216,6 @@ void gprs_ns2_start_alive_all_nsvcs(struct gprs_ns2_nse *nse) } } -/*! Set the mode of given bind. - * \param[in] bind the bind we want to set the mode of - * \param[in] mode mode to set bind to */ -void gprs_ns2_bind_set_mode(struct gprs_ns2_vc_bind *bind, enum gprs_ns2_vc_mode mode) -{ - bind->vc_mode = mode; -} - /*! Destroy a given bind. * \param[in] bind the bind we want to destroy */ void gprs_ns2_free_bind(struct gprs_ns2_vc_bind *bind) @@ -1234,4 +1243,20 @@ void gprs_ns2_free_binds(struct gprs_ns2_inst *nsi) gprs_ns2_free_bind(bind); } } + +enum gprs_ns2_vc_mode gprs_ns2_dialect_to_vc_mode( + enum gprs_ns2_dialect dialect) +{ + switch (dialect) { + case NS2_DIALECT_SNS: + case NS2_DIALECT_STATIC_ALIVE: + return NS2_VC_MODE_ALIVE; + case NS2_DIALECT_STATIC_RESETBLOCK: + case NS2_DIALECT_IPACCESS: + return NS2_VC_MODE_BLOCKRESET; + default: + return -1; + } +} + /*! @} */ diff --git a/src/gb/gprs_ns2_fr.c b/src/gb/gprs_ns2_fr.c index 2d5b02159..6b4fa52e9 100644 --- a/src/gb/gprs_ns2_fr.c +++ b/src/gb/gprs_ns2_fr.c @@ -486,7 +486,6 @@ int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi, } strncpy(priv->netif, netif, sizeof(priv->netif)); - ns2_vty_bind_apply(bind); if (result) *result = bind; @@ -600,7 +599,7 @@ struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind, struct priv_vc *priv = NULL; struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei); if (!nse) { - nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR); + nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, NS2_DIALECT_STATIC_RESETBLOCK); if (!nse) return NULL; created_nse = true; @@ -611,7 +610,7 @@ struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind, goto err_nse; } - nsvc = ns2_vc_alloc(bind, nse, true); + nsvc = ns2_vc_alloc(bind, nse, true, NS2_VC_MODE_BLOCKRESET); if (!nsvc) goto err_nse; diff --git a/src/gb/gprs_ns2_frgre.c b/src/gb/gprs_ns2_frgre.c index 3c276bc5d..423ea4b70 100644 --- a/src/gb/gprs_ns2_frgre.c +++ b/src/gb/gprs_ns2_frgre.c @@ -592,8 +592,6 @@ int gprs_ns2_frgre_bind(struct gprs_ns2_inst *nsi, dscp, rc, errno); } - ns2_vty_bind_apply(bind); - if (result) *result = bind; diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h index e72deff1e..8c0c13547 100644 --- a/src/gb/gprs_ns2_internal.h +++ b/src/gb/gprs_ns2_internal.h @@ -130,6 +130,9 @@ struct gprs_ns2_nse { /*! which link-layer are we based on? */ enum gprs_ns2_ll ll; + /*! which dialect does this NSE speaks? */ + enum gprs_ns2_dialect dialect; + struct osmo_fsm_inst *bss_sns_fi; }; @@ -188,8 +191,8 @@ struct gprs_ns2_vc_bind { struct gprs_ns2_inst *nsi; struct gprs_ns2_vc_driver *driver; - /*! if VCs use reset/block/unblock method. IP shall not use this */ - enum gprs_ns2_vc_mode vc_mode; + bool accept_ipaccess; + bool accept_sns; /*! which link-layer are we based on? */ enum gprs_ns2_ll ll; @@ -222,7 +225,8 @@ int ns2_recv_vc(struct gprs_ns2_vc *nsvc, struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_nse *nse, - bool initiater); + bool initiater, + enum gprs_ns2_vc_mode vc_mode); struct msgb *gprs_ns2_msgb_alloc(void); @@ -298,8 +302,6 @@ int gprs_ns2_vc_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed int gprs_ns2_vc_is_alive(struct gprs_ns2_vc *nsvc); int gprs_ns2_vc_is_unblocked(struct gprs_ns2_vc *nsvc); -/* vty.c */ -void ns2_vty_bind_apply(struct gprs_ns2_vc_bind *bind); - /* nse */ void ns2_nse_notify_unblocked(struct gprs_ns2_vc *nsvc, bool unblocked); +enum gprs_ns2_vc_mode gprs_ns2_dialect_to_vc_mode(enum gprs_ns2_dialect dialect); diff --git a/src/gb/gprs_ns2_udp.c b/src/gb/gprs_ns2_udp.c index 928116d60..b923e8180 100644 --- a/src/gb/gprs_ns2_udp.c +++ b/src/gb/gprs_ns2_udp.c @@ -359,8 +359,6 @@ int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi, } llist_add(&bind->list, &nsi->binding); - ns2_vty_bind_apply(bind); - if (result) *result = bind; @@ -378,8 +376,16 @@ struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind, { struct gprs_ns2_vc *nsvc; struct priv_vc *priv; + enum gprs_ns2_vc_mode vc_mode; - nsvc = ns2_vc_alloc(bind, nse, true); + vc_mode = gprs_ns2_dialect_to_vc_mode(nse->dialect); + if ((int) vc_mode == -1) { + LOGP(DLNS, LOGL_ERROR, "Can not derive vc mode from dialect %d. Maybe libosmocore is too old.\n", + nse->dialect); + return NULL; + } + + nsvc = ns2_vc_alloc(bind, nse, true, vc_mode); if (!nsvc) return NULL; diff --git a/src/gb/gprs_ns2_vty.c b/src/gb/gprs_ns2_vty.c index 43e9c2c31..d285c2241 100644 --- a/src/gb/gprs_ns2_vty.c +++ b/src/gb/gprs_ns2_vty.c @@ -62,10 +62,6 @@ struct ns2_vty_priv { struct osmo_sockaddr_str frgreaddr; int dscp; enum gprs_ns2_vc_mode vc_mode; - /* force vc mode if another configuration forces - * the vc mode. E.g. SNS configuration */ - bool force_vc_mode; - const char *force_vc_mode_reason; bool frgre; struct llist_head vtyvc; @@ -714,30 +710,14 @@ DEFUN(cfg_nsip_res_block_unblock, cfg_nsip_res_block_unblock_cmd, "Disable NS-{RESET,BLOCK,UNBLOCK}\n") { enum gprs_ns2_vc_mode vc_mode; - struct gprs_ns2_vc_bind *bind; if (!strcmp(argv[0], "enabled")) vc_mode = NS2_VC_MODE_BLOCKRESET; else vc_mode = NS2_VC_MODE_ALIVE; - if (priv.force_vc_mode) { - if (priv.vc_mode != vc_mode) - { - vty_out(vty, "Ignoring use-reset-block because it's already set by %s.%s", - priv.force_vc_mode_reason, VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; - } - priv.vc_mode = vc_mode; - llist_for_each_entry(bind, &vty_nsi->binding, list) { - gprs_ns2_bind_set_mode(bind, priv.vc_mode); - } - return CMD_SUCCESS; } @@ -902,6 +882,7 @@ int gprs_ns2_vty_create() { struct gprs_ns2_nse *nse; struct gprs_ns2_vc *nsvc; struct osmo_sockaddr sockaddr; + enum gprs_ns2_dialect dialect = NS2_DIALECT_UNDEF; int rc = 0; if (!vty_nsi) @@ -918,7 +899,7 @@ int gprs_ns2_vty_create() { /* TODO: could not bind on the specific address */ return -1; } - gprs_ns2_bind_set_mode(bind, priv.vc_mode); + bind->accept_ipaccess = true; } /* create vcs */ @@ -926,6 +907,7 @@ int gprs_ns2_vty_create() { /* validate settings */ switch (vtyvc->ll) { case GPRS_NS2_LL_UDP: + dialect = NS2_DIALECT_IPACCESS; if (strlen(vtyvc->remote.ip) == 0) { /* Invalid IP for VC */ continue; @@ -942,14 +924,16 @@ int gprs_ns2_vty_create() { } break; case GPRS_NS2_LL_FR: + dialect = NS2_DIALECT_STATIC_RESETBLOCK; break; case GPRS_NS2_LL_FR_GRE: + dialect = NS2_DIALECT_STATIC_RESETBLOCK; continue; } nse = gprs_ns2_nse_by_nsei(vty_nsi, vtyvc->nsei); if (!nse) { - nse = gprs_ns2_create_nse(vty_nsi, vtyvc->nsei, vtyvc->ll); + nse = gprs_ns2_create_nse(vty_nsi, vtyvc->nsei, vtyvc->ll, dialect); if (!nse) { /* Could not create NSE for VTY */ continue; @@ -1001,29 +985,3 @@ int gprs_ns2_vty_create() { return 0; } - -/*! - * \brief ns2_vty_bind_apply will be called when a new bind is created to apply vty settings - * \param bind - * \return - */ -void ns2_vty_bind_apply(struct gprs_ns2_vc_bind *bind) -{ - gprs_ns2_bind_set_mode(bind, priv.vc_mode); -} - -/*! - * \brief ns2_vty_force_vc_mode force a mode and prevents the vty from overwriting it. - * \param force if true mode and reason will be set. false to allow modification via vty. - * \param mode - * \param reason A description shown to the user when a vty command wants to change the mode. - */ -void gprs_ns2_vty_force_vc_mode(bool force, enum gprs_ns2_vc_mode mode, const char *reason) -{ - priv.force_vc_mode = force; - - if (force) { - priv.vc_mode = mode; - priv.force_vc_mode_reason = reason; - } -} diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map index f8ad901c5..e3301be4c 100644 --- a/src/gb/libosmogb.map +++ b/src/gb/libosmogb.map @@ -109,7 +109,6 @@ gprs_ns_ll_clear; gprs_ns_msgb_alloc; gprs_ns2_aff_cause_prim_strs; -gprs_ns2_bind_set_mode; gprs_ns2_cause_strs; gprs_ns2_create_nse; gprs_ns2_dynamic_create_nse; @@ -159,7 +158,6 @@ gprs_ns2_recv_prim; gprs_ns2_reset_persistent_nsvcs; gprs_ns2_start_alive_all_nsvcs; gprs_ns2_vty_create; -gprs_ns2_vty_force_vc_mode; gprs_ns2_vty_init; gprs_nsvc_create2;