mirror of https://gerrit.osmocom.org/libosmocore
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
This commit is contained in:
parent
c8158ecfc4
commit
d923cff170
|
@ -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);
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue