Rework NS configuration over the info indication
Add support of the second NSVC in the info indication. Add support to update a previous NS configuration. Allow to update of a NS-VC while the NSE is still available over the second. Depends-on: I917f25ebd1239eae5855d973ced15b93731e33a0 (libosmocore) Depends-on: I3a0cd305fd73b3cb9ec70246ec15ac70b83e57f2 (libosmocore) Depends-on: I5a2bb95d05d06d909347e2fb084a446ead888cb3 (libosmocore) Depends-on: I54f110acc3acccb362f6e554324d08cc42b7c328 (libosmocore) Depends-on: Ia00753a64b7622a0864341f51ea49b6963543755 (libosmocore) Depends-on: Ic8f6f8aca10da23a18fab8870be7806065a34b47 (libosmocore) Depends-on: I5f67e6a9bf4cb322bd169061fee0a528012ed54d (libosmocore) Change-Id: I589ebaa2a2b7de55b7e4e975d8fd6412dd5f214b
This commit is contained in:
parent
3839605ec9
commit
5bece2a0ed
|
@ -56,6 +56,8 @@
|
|||
#define PCU_IF_ADDR_TYPE_IPV4 0x04 /* IPv4 address */
|
||||
#define PCU_IF_ADDR_TYPE_IPV6 0x29 /* IPv6 address */
|
||||
|
||||
#define PCU_IF_NUM_NSVC 2
|
||||
|
||||
enum gsm_pcu_if_text_type {
|
||||
PCU_VERSION,
|
||||
PCU_OML_ALERT,
|
||||
|
@ -167,14 +169,14 @@ struct gsm_pcu_if_info_ind {
|
|||
uint8_t initial_cs;
|
||||
uint8_t initial_mcs;
|
||||
/* NSVC */
|
||||
uint16_t nsvci[2];
|
||||
uint16_t local_port[2];
|
||||
uint16_t remote_port[2];
|
||||
uint8_t address_type[2];
|
||||
uint16_t nsvci[PCU_IF_NUM_NSVC];
|
||||
uint16_t local_port[PCU_IF_NUM_NSVC];
|
||||
uint16_t remote_port[PCU_IF_NUM_NSVC];
|
||||
uint8_t address_type[PCU_IF_NUM_NSVC];
|
||||
union {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
} remote_ip[2];
|
||||
} remote_ip[PCU_IF_NUM_NSVC];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct gsm_pcu_if_act_req {
|
||||
|
|
|
@ -920,44 +920,161 @@ static void bvc_timeout(void *_priv)
|
|||
osmo_timer_schedule(&the_pcu.bvc_timer, the_pcu.bts->fc_interval, 0);
|
||||
}
|
||||
|
||||
|
||||
int gprs_nsvc_create_and_connect(struct gprs_rlcmac_bts *bts,
|
||||
const struct osmo_sockaddr *local,
|
||||
const struct osmo_sockaddr *sgsn,
|
||||
uint16_t nsei, uint16_t nsvci)
|
||||
static int ns_create_nsvc(struct gprs_rlcmac_bts *bts,
|
||||
uint16_t nsei,
|
||||
const struct osmo_sockaddr *local,
|
||||
const struct osmo_sockaddr *remote,
|
||||
const uint16_t *nsvci,
|
||||
uint16_t valid)
|
||||
{
|
||||
int i, rc;
|
||||
uint16_t binds = 0;
|
||||
bool nsvcs = false;
|
||||
struct gprs_ns2_vc *nsvc;
|
||||
struct gprs_ns2_vc_bind *bind;
|
||||
int rc;
|
||||
struct gprs_ns2_vc_bind *bind[PCU_IF_NUM_NSVC] = { };
|
||||
|
||||
if (!valid)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < PCU_IF_NUM_NSVC; i++) {
|
||||
if (!(valid & (1 << i)))
|
||||
continue;
|
||||
|
||||
if (!gprs_ns2_ip_bind_by_sockaddr(bts->nsi, &local[i])) {
|
||||
rc = gprs_ns2_ip_bind(bts->nsi, &local[i], 0, &bind[i]);
|
||||
if (rc < 0) {
|
||||
LOGP(DBSSGP, LOGL_ERROR, "Failed to bind to %s\n", osmo_sockaddr_to_str(&local[i]));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
binds |= 1 << i;
|
||||
}
|
||||
|
||||
if (!binds) {
|
||||
LOGP(DBSSGP, LOGL_ERROR, "Failed to bind to any NS-VC\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bts->nse = gprs_ns2_nse_by_nsei(bts->nsi, nsei);
|
||||
if (bts->nse != NULL) {
|
||||
/* FIXME: we end up here on receipt of subsequent INFO.ind.
|
||||
* What are we supposed to do? Re-establish the connection? */
|
||||
LOGP(DBSSGP, LOGL_INFO, "NSE with NSEI %u is already configured, "
|
||||
"keeping it unchanged\n", nsei);
|
||||
return 0;
|
||||
}
|
||||
if (!bts->nse)
|
||||
bts->nse = gprs_ns2_create_nse(bts->nsi, nsei);
|
||||
|
||||
bts->nse = gprs_ns2_create_nse(bts->nsi, nsei);
|
||||
if (!bts->nse) {
|
||||
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NSE\n");
|
||||
gprs_ns2_free_binds(bts->nsi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = gprs_ns2_ip_bind(bts->nsi, local, 0, &bind);
|
||||
if (rc < 0) {
|
||||
LOGP(DBSSGP, LOGL_ERROR, "Failed to create socket\n");
|
||||
gprs_ns2_free(bts->nsi);
|
||||
return 1;
|
||||
for (i = 0; i < PCU_IF_NUM_NSVC; i++) {
|
||||
if (!(binds & (1 << i)))
|
||||
continue;
|
||||
|
||||
/* FIXME: for SNS we just use the first successful NS-VC instead of all for the initial connect */
|
||||
if (bts->gb_dialect_sns) {
|
||||
rc = gprs_ns2_ip_connect_sns(bind[i], &remote[i], nsei);
|
||||
if (!rc)
|
||||
return rc;
|
||||
else
|
||||
LOGP(DBSSGP, LOGL_ERROR, "Failed to connect to (SNS) towards SGSN %s!\n", osmo_sockaddr_to_str(&remote[i]));
|
||||
} else {
|
||||
nsvc = gprs_ns2_ip_connect(bind[i], &remote[i], bts->nse, nsvci[i]);
|
||||
if (nsvc)
|
||||
nsvcs = true;
|
||||
else
|
||||
LOGP(DBSSGP, LOGL_ERROR, "Failed to connect to towards SGSN %s!\n", osmo_sockaddr_to_str(&remote[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (bts->gb_dialect_sns) {
|
||||
rc = gprs_ns2_ip_connect_sns(bind, sgsn, nsei);
|
||||
return nsvcs ? 0 : -1;
|
||||
}
|
||||
|
||||
struct nsvc_cb {
|
||||
const struct osmo_sockaddr *local;
|
||||
const struct osmo_sockaddr *remote;
|
||||
const uint16_t *nsvci;
|
||||
/* [in] bitmask of valid nsvc in local/remote */
|
||||
uint16_t valid;
|
||||
/* [out] bitmask of found nsvcs */
|
||||
uint16_t found;
|
||||
};
|
||||
|
||||
static int ns_conf_vc_cb(struct gprs_ns2_vc *nsvc, void *ctx)
|
||||
{
|
||||
struct nsvc_cb *data = (struct nsvc_cb *) ctx;
|
||||
|
||||
for (unsigned int i = 0; i < PCU_IF_NUM_NSVC; i++) {
|
||||
if (!(data->valid & (1 << i)))
|
||||
continue;
|
||||
if (data->found & (1 << i))
|
||||
continue;
|
||||
|
||||
if (gprs_ns2_ip_vc_equal(nsvc, &data->local[i],
|
||||
&data->remote[i],
|
||||
data->nsvci[i])) {
|
||||
data->found |= 1 << i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Found an extra nsvc */
|
||||
LOGP(DBSSGP, LOGL_DEBUG, " Removing NSVC %s\n", gprs_ns2_ll_str(nsvc));
|
||||
gprs_ns2_free_nsvc(nsvc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gprs_ns_config(struct gprs_rlcmac_bts *bts, uint16_t nsei,
|
||||
const struct osmo_sockaddr *local,
|
||||
const struct osmo_sockaddr *remote,
|
||||
uint16_t *nsvci, uint16_t valid)
|
||||
{
|
||||
int rc = 0;
|
||||
if (!bts->nse) {
|
||||
/* there shouldn't any previous state. */
|
||||
gprs_ns2_free_nses(bts->nsi);
|
||||
gprs_ns2_free_binds(bts->nsi);
|
||||
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
|
||||
} else if (nsei != gprs_ns2_nse_nsei(bts->nse)) {
|
||||
/* the NSEI has changed */
|
||||
gprs_ns2_free_nses(bts->nsi);
|
||||
gprs_ns2_free_binds(bts->nsi);
|
||||
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
|
||||
} else if (bts->gb_dialect_sns) {
|
||||
/* SNS: check if the initial nsvc is the same, if not recreate it */
|
||||
const struct osmo_sockaddr *initial = gprs_ns2_nse_sns_remote(bts->nse);
|
||||
for (unsigned int i = 0; i < PCU_IF_NUM_NSVC; i++) {
|
||||
if (!(valid & (1 << i)))
|
||||
continue;
|
||||
|
||||
/* found the initial - everything should be fine */
|
||||
if (!osmo_sockaddr_cmp(initial, &remote[i]))
|
||||
return 0;
|
||||
}
|
||||
|
||||
gprs_ns2_free_nses(bts->nsi);
|
||||
gprs_ns2_free_binds(bts->nsi);
|
||||
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
|
||||
} else {
|
||||
nsvc = gprs_ns2_ip_connect2(bind, sgsn, nsei, nsvci);
|
||||
if (!nsvc)
|
||||
rc = -1;
|
||||
/* check if all NSVC are still the same. */
|
||||
struct nsvc_cb data = {
|
||||
.local = &local[0],
|
||||
.remote = &remote[0],
|
||||
.nsvci = &nsvci[0],
|
||||
.valid = valid,
|
||||
.found = 0,
|
||||
};
|
||||
|
||||
/* search the current active nsvcs */
|
||||
gprs_ns2_nse_foreach_nsvc(bts->nse, &ns_conf_vc_cb, &data);
|
||||
|
||||
/* we found all our valid nsvcs and might have removed all other nsvcs */
|
||||
if (valid == data.found)
|
||||
return 0;
|
||||
|
||||
/* remove all found nsvcs from the valid field */
|
||||
valid &= ~data.found;
|
||||
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
|
|
|
@ -81,10 +81,10 @@ struct gprs_bssgp_pcu *gprs_bssgp_init(
|
|||
uint16_t mcc, uint16_t mnc, bool mnc_3_digits,
|
||||
uint16_t lac, uint16_t rac, uint16_t cell_id);
|
||||
|
||||
int gprs_nsvc_create_and_connect(struct gprs_rlcmac_bts *bts,
|
||||
const struct osmo_sockaddr *local,
|
||||
const struct osmo_sockaddr *sgsn,
|
||||
uint16_t nsei, uint16_t nsvci);
|
||||
int gprs_ns_config(struct gprs_rlcmac_bts *bts, uint16_t nsei,
|
||||
const struct osmo_sockaddr *local,
|
||||
const struct osmo_sockaddr *remote,
|
||||
uint16_t *nsvci, uint16_t valid);
|
||||
|
||||
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
|
||||
int gprs_gp_send_cb(void *ctx, struct msgb *msg);
|
||||
|
|
|
@ -39,6 +39,7 @@ extern "C" {
|
|||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gprs/gprs_ns2.h>
|
||||
#include <osmocom/gsm/l1sap.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
}
|
||||
|
@ -488,12 +489,64 @@ static int pcu_rx_rach_ind(const struct gsm_pcu_if_rach_ind *rach_ind)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int pcu_info_ind_ns(struct gprs_rlcmac_bts *bts,
|
||||
const struct gsm_pcu_if_info_ind *info_ind)
|
||||
{
|
||||
struct osmo_sockaddr remote[PCU_IF_NUM_NSVC] = { };
|
||||
struct osmo_sockaddr local[PCU_IF_NUM_NSVC] = { };
|
||||
uint16_t nsvci[PCU_IF_NUM_NSVC] = { };
|
||||
uint16_t valid = 0;
|
||||
|
||||
for (unsigned int i = 0; i < PCU_IF_NUM_NSVC; i++) {
|
||||
struct osmo_sockaddr_str sockstr;
|
||||
|
||||
switch (info_ind->address_type[i]) {
|
||||
case PCU_IF_ADDR_TYPE_IPV4:
|
||||
local[i].u.sin.sin_family = AF_INET;
|
||||
local[i].u.sin.sin_addr.s_addr = INADDR_ANY;
|
||||
local[i].u.sin.sin_port = htons(info_ind->local_port[i]);
|
||||
|
||||
remote[i].u.sin.sin_family = AF_INET;
|
||||
remote[i].u.sin.sin_addr = info_ind->remote_ip[i].v4;
|
||||
remote[i].u.sin.sin_port = htons(info_ind->remote_port[i]);
|
||||
break;
|
||||
case PCU_IF_ADDR_TYPE_IPV6:
|
||||
local[i].u.sin6.sin6_family = AF_INET6;
|
||||
local[i].u.sin6.sin6_addr = in6addr_any;
|
||||
local[i].u.sin6.sin6_port = htons(info_ind->local_port[i]);
|
||||
|
||||
remote[i].u.sin6.sin6_family = AF_INET6;
|
||||
remote[i].u.sin6.sin6_addr = info_ind->remote_ip[i].v6;
|
||||
remote[i].u.sin6.sin6_port = htons(info_ind->remote_port[i]);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
nsvci[i] = info_ind->nsvci[i];
|
||||
|
||||
LOGP(DL1IF, LOGL_DEBUG, " NS%u nsvci=%u\n", i, nsvci[i]);
|
||||
if (osmo_sockaddr_str_from_sockaddr(&sockstr, &remote[i].u.sas))
|
||||
strcpy(sockstr.ip, "invalid");
|
||||
|
||||
LOGP(DL1IF, LOGL_DEBUG, " NS%u address: r=%s:%u<->l=NULL:%u\n",
|
||||
i, sockstr.ip, sockstr.port, info_ind->local_port[i]);
|
||||
|
||||
valid |= 1 << i;
|
||||
}
|
||||
|
||||
if (valid == 0) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "No NSVC available to connect to the SGSN!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return gprs_ns_config(bts, info_ind->nsei, local, remote, nsvci, valid);
|
||||
}
|
||||
|
||||
static int pcu_rx_info_ind(const struct gsm_pcu_if_info_ind *info_ind)
|
||||
{
|
||||
struct gprs_rlcmac_bts *bts = bts_main_data();
|
||||
struct gprs_bssgp_pcu *pcu;
|
||||
int rc = 0;
|
||||
int good_nsvc = 0;
|
||||
unsigned int trx_nr, ts_nr;
|
||||
int i;
|
||||
|
||||
|
@ -578,54 +631,8 @@ bssgp_failed:
|
|||
goto bssgp_failed;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(info_ind->nsvci); i++) {
|
||||
struct osmo_sockaddr remote_sockaddr = { };
|
||||
struct osmo_sockaddr local_sockaddr = { };
|
||||
struct osmo_sockaddr_str sockstr;
|
||||
|
||||
switch (info_ind->address_type[i]) {
|
||||
case PCU_IF_ADDR_TYPE_IPV4:
|
||||
local_sockaddr.u.sin.sin_family = AF_INET;
|
||||
local_sockaddr.u.sin.sin_addr.s_addr = INADDR_ANY;
|
||||
local_sockaddr.u.sin.sin_port = htons(info_ind->local_port[i]);
|
||||
|
||||
remote_sockaddr.u.sin.sin_family = AF_INET;
|
||||
remote_sockaddr.u.sin.sin_addr = info_ind->remote_ip[i].v4;
|
||||
remote_sockaddr.u.sin.sin_port = htons(info_ind->remote_port[i]);
|
||||
break;
|
||||
case PCU_IF_ADDR_TYPE_IPV6:
|
||||
local_sockaddr.u.sin6.sin6_family = AF_INET6;
|
||||
local_sockaddr.u.sin6.sin6_addr = in6addr_any;
|
||||
local_sockaddr.u.sin6.sin6_port = htons(info_ind->local_port[i]);
|
||||
|
||||
remote_sockaddr.u.sin6.sin6_family = AF_INET6;
|
||||
remote_sockaddr.u.sin6.sin6_addr = info_ind->remote_ip[i].v6;
|
||||
remote_sockaddr.u.sin6.sin6_port = htons(info_ind->remote_port[i]);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
LOGP(DL1IF, LOGL_DEBUG, " NS%u nsvci=%u\n", i, info_ind->nsvci[i]);
|
||||
|
||||
if (osmo_sockaddr_str_from_sockaddr(&sockstr, &remote_sockaddr.u.sas))
|
||||
strcpy(sockstr.ip, "invalid");
|
||||
|
||||
LOGP(DL1IF, LOGL_DEBUG, " NS%u address: r=%s:%u<->l=NULL:%u\n",
|
||||
i, sockstr.ip, sockstr.port, info_ind->local_port[i]);
|
||||
rc = gprs_nsvc_create_and_connect(bts,
|
||||
&local_sockaddr, &remote_sockaddr,
|
||||
info_ind->nsei, info_ind->nsvci[i]);
|
||||
if (rc) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "Failed to create NSVC connection to %s:%u!\n",
|
||||
sockstr.ip, sockstr.port);
|
||||
continue;
|
||||
}
|
||||
|
||||
good_nsvc++;
|
||||
}
|
||||
|
||||
if (good_nsvc == 0) {
|
||||
rc = pcu_info_ind_ns(pcu->bts, info_ind);
|
||||
if (rc < 0) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "No NSVC available to connect to the SGSN!\n");
|
||||
goto bssgp_failed;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,8 @@ void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts,
|
|||
{
|
||||
struct gprs_bssgp_pcu *pcu;
|
||||
struct osmo_sockaddr local, remote;
|
||||
uint16_t nsvci = 20;
|
||||
uint16_t nsei = 20;
|
||||
|
||||
local.u.sin.sin_family = AF_INET;
|
||||
local.u.sin.sin_addr.s_addr = 0;
|
||||
|
@ -104,8 +106,7 @@ void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts,
|
|||
remote.u.sin.sin_port = htons(sgsn_port);
|
||||
|
||||
pcu = gprs_bssgp_init(bts, 20, 20, 901, 99, false, 1, 0, 0);
|
||||
gprs_nsvc_create_and_connect(bts, &local, &remote,
|
||||
20, 20);
|
||||
gprs_ns_config(bts, nsei, &local, &remote, &nsvci, 1);
|
||||
|
||||
pcu->on_unblock_ack = bvci_unblocked;
|
||||
pcu->on_dl_unit_data = bssgp_data;
|
||||
|
|
Loading…
Reference in New Issue