Fixed incorrect SMF selection in Multi-SMF (#2557)

This commit is contained in:
Sukchan Lee 2023-10-23 22:35:54 +09:00
parent 125740727e
commit d406fbeb92
18 changed files with 729 additions and 133 deletions

View File

@ -161,6 +161,12 @@ char ogs_from_hex(char ch)
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
char ogs_to_hex(char ch)
{
static char hex[] = "0123456789ABCDEF";
return hex[ch & 15];
}
char *ogs_uint24_to_0string(ogs_uint24_t x)
{
return ogs_msprintf("%06x", x.v);

View File

@ -44,6 +44,7 @@ void *ogs_bcd_to_buffer_reverse_order(const char *in, void *out, int *out_len);
void *ogs_buffer_to_bcd(uint8_t *in, int in_len, void *out);
char ogs_from_hex(char ch);
char ogs_to_hex(char ch);
char *ogs_uint24_to_0string(ogs_uint24_t x);
char *ogs_uint28_to_0string(uint32_t x);

View File

@ -1316,6 +1316,62 @@ ogs_sbi_nf_info_t *ogs_sbi_nf_info_find(
return NULL;
}
bool ogs_sbi_check_smf_info_slice(
ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn)
{
int i, j;
ogs_assert(smf_info);
ogs_assert(s_nssai);
ogs_assert(dnn);
for (i = 0; i < smf_info->num_of_slice; i++) {
if (s_nssai->sst == smf_info->slice[i].s_nssai.sst &&
s_nssai->sd.v == smf_info->slice[i].s_nssai.sd.v) {
for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) {
if (ogs_strcasecmp(dnn, smf_info->slice[i].dnn[j]) == 0)
return true;
}
}
}
return false;
}
bool ogs_sbi_check_smf_info_tai(
ogs_sbi_smf_info_t *smf_info, ogs_5gs_tai_t *tai)
{
int i, j;
ogs_assert(smf_info);
ogs_assert(tai);
if (smf_info->num_of_nr_tai == 0 && smf_info->num_of_nr_tai_range == 0)
return true;
for (i = 0; i < smf_info->num_of_nr_tai; i++) {
if (memcmp(&tai->plmn_id,
&smf_info->nr_tai[i].plmn_id, OGS_PLMN_ID_LEN) == 0) {
if (tai->tac.v == smf_info->nr_tai[i].tac.v)
return true;
}
}
for (i = 0; i < smf_info->num_of_nr_tai_range; i++) {
if (memcmp(&tai->plmn_id,
&smf_info->nr_tai_range[i].plmn_id, OGS_PLMN_ID_LEN) == 0) {
for (j = 0; j < smf_info->nr_tai_range[i].num_of_tac_range; j++) {
if (tai->tac.v >= smf_info->nr_tai_range[i].start[j].v &&
tai->tac.v <= smf_info->nr_tai_range[i].end[j].v) {
return true;
}
}
}
}
return false;
}
void ogs_sbi_nf_instance_build_default(ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_server_t *server = NULL;
@ -1547,6 +1603,8 @@ bool ogs_sbi_discovery_option_is_matched(
OpenAPI_nf_type_e requester_nf_type,
ogs_sbi_discovery_option_t *discovery_option)
{
ogs_sbi_nf_info_t *nf_info = NULL;
ogs_assert(nf_instance);
ogs_assert(requester_nf_type);
ogs_assert(discovery_option);
@ -1581,6 +1639,30 @@ bool ogs_sbi_discovery_option_is_matched(
if (exist == false) return false;
}
ogs_list_for_each(&nf_instance->nf_info_list, nf_info) {
if (nf_instance->nf_type != nf_info->nf_type) {
ogs_error("Invalid NF-Type [%d:%d]",
nf_instance->nf_type, nf_info->nf_type);
return false;
}
switch (nf_info->nf_type) {
case OpenAPI_nf_type_SMF:
if (discovery_option->num_of_snssais && discovery_option->dnn &&
ogs_sbi_check_smf_info_slice(&nf_info->smf,
&discovery_option->snssais[0],
discovery_option->dnn) == false)
return false;
if (discovery_option->num_of_tai &&
ogs_sbi_check_smf_info_tai(&nf_info->smf,
&discovery_option->tai[0]) == false)
return false;
break;
default:
break;
}
}
return true;
}

View File

@ -402,6 +402,11 @@ void ogs_sbi_nf_info_remove_all(ogs_list_t *list);
ogs_sbi_nf_info_t *ogs_sbi_nf_info_find(
ogs_list_t *list, OpenAPI_nf_type_e nf_type);
bool ogs_sbi_check_smf_info_slice(
ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn);
bool ogs_sbi_check_smf_info_tai(
ogs_sbi_smf_info_t *smf_info, ogs_5gs_tai_t *tai);
void ogs_sbi_nf_instance_build_default(ogs_sbi_nf_instance_t *nf_instance);
ogs_sbi_nf_service_t *ogs_sbi_nf_service_build_default(
ogs_sbi_nf_instance_t *nf_instance, const char *name);
@ -424,7 +429,9 @@ int ogs_sbi_client_default_port(void);
ogs_assert(__nFInstance); \
\
if ((__cTX).nf_instance) { \
ogs_warn("NF Instance updated [%s]", (__nFInstance)->id); \
ogs_warn("NF Instance [%s] updated [%s]", \
OpenAPI_nf_type_ToString((__nFInstance)->nf_type), \
(__nFInstance)->id); \
ogs_sbi_nf_instance_remove((__cTX).nf_instance); \
} \
\

View File

@ -364,10 +364,51 @@ char *ogs_sbi_client_apiroot(ogs_sbi_client_t *client)
* Thanks Geek Hideout!
* http://www.geekhideout.com/urlcode.shtml
*/
static char *url_decode(const char *str)
char *ogs_sbi_url_encode(const char *str)
{
if (str != NULL) {
char *pstr = (char*)str;
char *pstr = (char *)str;
char *buf = ogs_malloc(strlen(str) * 3 + 1);
char *pbuf = buf;
ogs_assert(buf);
while (*pstr) {
if (*pstr == '"' ||
*pstr == '(' ||
*pstr == ')' ||
*pstr == ',' ||
*pstr == '/' ||
*pstr == ':' ||
*pstr == ';' ||
*pstr == '<' ||
*pstr == '=' ||
*pstr == '>' ||
*pstr == '?' ||
*pstr == '@' ||
*pstr == '[' ||
*pstr == '\\' ||
*pstr == ']' ||
*pstr == '{' ||
*pstr == '}') {
*pbuf++ = '%';
*pbuf++ = ogs_to_hex(*pstr >> 4);
*pbuf++ = ogs_to_hex(*pstr & 15);
} else
*pbuf++ = *pstr;
pstr++;
}
*pbuf = '\0';
return buf;
} else {
return NULL;
}
}
char *ogs_sbi_url_decode(const char *str)
{
if (str != NULL) {
char *pstr = (char *)str;
char *buf = ogs_malloc(strlen(str) + 1);
char *pbuf = buf;
ogs_assert(buf);
@ -396,7 +437,7 @@ char *ogs_sbi_parse_uri(char *uri, const char *delim, char **saveptr)
{
char *item = NULL;
item = url_decode(ogs_strtok_r(uri, delim, saveptr));
item = ogs_sbi_url_decode(ogs_strtok_r(uri, delim, saveptr));
if (!item) {
return NULL;
}

View File

@ -40,6 +40,9 @@ char *ogs_sbi_server_uri(ogs_sbi_server_t *server, ogs_sbi_header_t *h);
char *ogs_sbi_client_apiroot(ogs_sbi_client_t *client);
char *ogs_sbi_client_uri(ogs_sbi_client_t *client, ogs_sbi_header_t *h);
char *ogs_sbi_url_encode(const char *str);
char *ogs_sbi_url_decode(const char *str);
char *ogs_sbi_parse_uri(char *uri, const char *delim, char **saveptr);
bool ogs_sbi_getaddr_from_uri(

View File

@ -388,6 +388,23 @@ ogs_sbi_request_t *ogs_sbi_build_request(ogs_sbi_message_t *message)
if (ogs_sbi_self()->discovery_config.no_service_names == false &&
discovery_option->num_of_service_names) {
/*
* Issues #1730
* Send NF discovery query with service-names delimited with comma
*
* OpenAPI specification for sending NF discovery query with
* "service-names" parameter is defined as folowing:
* name: service-names
* ...
* style: form
* explode: false
*
* According to OpenAPI specification, this means array items
* should be delimited with a comma character (example: /users?id=3,4,5).
*
* See also https://swagger.io/docs/specification/serialization/
*/
/* send array items separated by a comma */
char *v = ogs_sbi_discovery_option_build_service_names(
discovery_option);
@ -396,11 +413,47 @@ ogs_sbi_request_t *ogs_sbi_build_request(ogs_sbi_message_t *message)
OGS_SBI_PARAM_SERVICE_NAMES, v);
ogs_free(v);
} else {
ogs_warn("invalid service names failed[%d:%s]",
ogs_warn("build failed: service-names[%d:%s]",
discovery_option->num_of_service_names,
discovery_option->service_names[0]);
}
}
if (discovery_option->num_of_snssais) {
char *v = ogs_sbi_discovery_option_build_snssais(discovery_option);
if (v) {
/*
* In http.params, the CURL library automatically encodes the URL.
* http.headers implements open5gs to directly encode URLs.
*
* Since it is http.params, the result is sent as is.
*/
ogs_sbi_header_set(request->http.params,
OGS_SBI_PARAM_SNSSAIS, v);
ogs_free(v);
} else {
ogs_error("build failed: snssais(%d)[SST:%d SD:0x%x]",
discovery_option->num_of_snssais,
discovery_option->snssais[0].sst,
discovery_option->snssais[0].sd.v);
}
}
if (discovery_option->dnn) {
ogs_sbi_header_set(request->http.params,
OGS_SBI_PARAM_DNN, discovery_option->dnn);
}
if (discovery_option->num_of_tai) {
char *v = ogs_sbi_discovery_option_build_tai(discovery_option);
if (v) {
ogs_sbi_header_set(request->http.params, OGS_SBI_PARAM_TAI, v);
ogs_free(v);
} else {
ogs_error("build failed: tai(%d)[PLMN_ID:%06x,TAC:%d]",
discovery_option->num_of_tai,
ogs_plmn_id_hexdump(
&discovery_option->tai[0].plmn_id),
discovery_option->tai[0].tac.v);
}
}
if (discovery_option->requester_features) {
char *v = ogs_uint64_to_string(
discovery_option->requester_features);
@ -702,12 +755,47 @@ int ogs_sbi_parse_request(
}
} else if (!strcmp(ogs_hash_this_key(hi),
OGS_SBI_PARAM_SERVICE_NAMES)) {
/*
* Issues #1730
* Send NF discovery query with service-names delimited with comma
*
* OpenAPI specification for sending NF discovery query with
* "service-names" parameter is defined as folowing:
* name: service-names
* ...
* style: form
* explode: false
*
* According to OpenAPI specification, this means array items
* should be delimited with a comma character (example: /users?id=3,4,5).
*
* See also https://swagger.io/docs/specification/serialization/
*/
char *v = ogs_hash_this_val(hi);
if (v) {
ogs_sbi_discovery_option_parse_service_names(
discovery_option, v);
discovery_option_presence = true;
}
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_SNSSAIS)) {
char *v = ogs_hash_this_val(hi);
if (v) {
ogs_sbi_discovery_option_parse_snssais(discovery_option, v);
discovery_option_presence = true;
}
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_DNN)) {
char *v = ogs_hash_this_val(hi);
if (v) {
ogs_sbi_discovery_option_set_dnn(discovery_option, v);
discovery_option_presence = true;
}
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_TAI)) {
char *v = ogs_hash_this_val(hi);
if (v) {
ogs_sbi_discovery_option_parse_tai(discovery_option, v);
discovery_option_presence = true;
}
} else if (!strcmp(ogs_hash_this_key(hi),
OGS_SBI_PARAM_REQUESTER_FEATURES)) {
char *v = ogs_hash_this_val(hi);
@ -2682,6 +2770,8 @@ void ogs_sbi_discovery_option_free(
ogs_free(discovery_option->target_nf_instance_id);
if (discovery_option->requester_nf_instance_id)
ogs_free(discovery_option->requester_nf_instance_id);
if (discovery_option->dnn)
ogs_free(discovery_option->dnn);
for (i = 0; i < discovery_option->num_of_service_names; i++)
ogs_free(discovery_option->service_names[i]);
@ -2712,6 +2802,16 @@ void ogs_sbi_discovery_option_set_requester_nf_instance_id(
ogs_strdup(requester_nf_instance_id);
ogs_assert(discovery_option->requester_nf_instance_id);
}
void ogs_sbi_discovery_option_set_dnn(
ogs_sbi_discovery_option_t *discovery_option, char *dnn)
{
ogs_assert(discovery_option);
ogs_assert(dnn);
ogs_assert(!discovery_option->dnn);
discovery_option->dnn = ogs_strdup(dnn);
ogs_assert(discovery_option->dnn);
}
void ogs_sbi_discovery_option_add_service_names(
ogs_sbi_discovery_option_t *discovery_option,
char *service_name)
@ -2743,6 +2843,22 @@ char *ogs_sbi_discovery_option_build_service_names(
return NULL;;
}
/*
* Issues #1730
* Send NF discovery query with service-names delimited with comma
*
* OpenAPI specification for sending NF discovery query with
* "service-names" parameter is defined as folowing:
* name: service-names
* ...
* style: form
* explode: false
*
* According to OpenAPI specification, this means array items
* should be delimited with a comma character (example: /users?id=3,4,5).
*
* See also https://swagger.io/docs/specification/serialization/
*/
if (discovery_option->num_of_service_names > 1) {
for (i = 1; i < discovery_option->num_of_service_names; i++)
service_names = ogs_mstrcatf(
@ -2763,9 +2879,29 @@ void ogs_sbi_discovery_option_parse_service_names(
ogs_assert(discovery_option);
ogs_assert(service_names);
v = ogs_strdup(service_names);
ogs_assert(v);
v = ogs_sbi_url_decode(service_names);
if (!v) {
ogs_error("ogs_sbi_url_decode() failed : service_names[%s]",
service_names);
return;
}
/*
* Issues #1730
* Send NF discovery query with service-names delimited with comma
*
* OpenAPI specification for sending NF discovery query with
* "service-names" parameter is defined as folowing:
* name: service-names
* ...
* style: form
* explode: false
*
* According to OpenAPI specification, this means array items
* should be delimited with a comma character (example: /users?id=3,4,5).
*
* See also https://swagger.io/docs/specification/serialization/
*/
token = ogs_strtok_r(v, ",", &saveptr);
while (token != NULL) {
ogs_sbi_discovery_option_add_service_names(discovery_option, token);
@ -2774,3 +2910,205 @@ void ogs_sbi_discovery_option_parse_service_names(
ogs_free(v);
}
void ogs_sbi_discovery_option_add_snssais(
ogs_sbi_discovery_option_t *discovery_option, ogs_s_nssai_t *s_nssai)
{
ogs_assert(discovery_option);
ogs_assert(s_nssai);
ogs_assert(discovery_option->num_of_snssais < OGS_MAX_NUM_OF_SLICE);
memcpy(&discovery_option->snssais[discovery_option->num_of_snssais],
s_nssai, sizeof(ogs_s_nssai_t));
discovery_option->num_of_snssais++;
}
char *ogs_sbi_discovery_option_build_snssais(
ogs_sbi_discovery_option_t *discovery_option)
{
cJSON *item = NULL;
char *v = NULL;
int i;
ogs_assert(discovery_option);
item = cJSON_CreateArray();
if (!item) {
ogs_error("cJSON_CreateArray() failed");
return NULL;
}
for (i = 0; i < discovery_option->num_of_snssais; i++) {
OpenAPI_snssai_t sNSSAI;
cJSON *snssaiItem = NULL;
memset(&sNSSAI, 0, sizeof(sNSSAI));
sNSSAI.sst = discovery_option->snssais[i].sst;
sNSSAI.sd = ogs_s_nssai_sd_to_string(discovery_option->snssais[i].sd);
snssaiItem = OpenAPI_snssai_convertToJSON(&sNSSAI);
ogs_assert(snssaiItem);
cJSON_AddItemToArray(item, snssaiItem);
}
v = cJSON_PrintUnformatted(item);
ogs_expect(v);
cJSON_Delete(item);
return v;
}
void ogs_sbi_discovery_option_parse_snssais(
ogs_sbi_discovery_option_t *discovery_option, char *snssais)
{
cJSON *item = NULL;
cJSON *snssaiItem = NULL;
char *v = NULL;
ogs_assert(discovery_option);
ogs_assert(snssais);
v = ogs_sbi_url_decode(snssais);
if (!v) {
ogs_error("ogs_sbi_url_decode() failed : snssais[%s]", snssais);
return;
}
item = cJSON_Parse(v);
if (!item) {
ogs_error("Cannot parse snssais[%s]", snssais);
ogs_free(v);
return;
}
cJSON_ArrayForEach(snssaiItem, item) {
if (cJSON_IsObject(snssaiItem)) {
OpenAPI_snssai_t *sNSSAI = OpenAPI_snssai_parseFromJSON(snssaiItem);
if (sNSSAI) {
ogs_s_nssai_t s_nssai;
s_nssai.sst = sNSSAI->sst;
s_nssai.sd = ogs_s_nssai_sd_from_string(sNSSAI->sd);
ogs_sbi_discovery_option_add_snssais(
discovery_option, &s_nssai);
OpenAPI_snssai_free(sNSSAI);
} else {
ogs_error("OpenAPI_snssai_parseFromJSON() failed : snssais[%s]",
snssais);
}
} else {
ogs_error("Invalid cJSON Type in snssias[%s]", snssais);
}
}
cJSON_Delete(item);
ogs_free(v);
}
void ogs_sbi_discovery_option_add_tai(
ogs_sbi_discovery_option_t *discovery_option, ogs_5gs_tai_t *tai)
{
ogs_assert(discovery_option);
ogs_assert(tai);
ogs_assert(discovery_option->num_of_tai < OGS_MAX_NUM_OF_TAI);
memcpy(&discovery_option->tai[discovery_option->num_of_tai],
tai, sizeof(ogs_5gs_tai_t));
discovery_option->num_of_tai++;
}
char *ogs_sbi_discovery_option_build_tai(
ogs_sbi_discovery_option_t *discovery_option)
{
cJSON *item = NULL;
char *v = NULL;
int i;
ogs_assert(discovery_option);
item = cJSON_CreateArray();
if (!item) {
ogs_error("cJSON_CreateArray() failed");
return NULL;
}
for (i = 0; i < discovery_option->num_of_tai; i++) {
OpenAPI_tai_t Tai;
cJSON *taiItem = NULL;
memset(&Tai, 0, sizeof(Tai));
Tai.plmn_id = ogs_sbi_build_plmn_id(&discovery_option->tai[i].plmn_id);
ogs_assert(Tai.plmn_id);
Tai.tac = ogs_uint24_to_0string(discovery_option->tai[i].tac);
ogs_assert(Tai.tac);
taiItem = OpenAPI_tai_convertToJSON(&Tai);
ogs_assert(taiItem);
cJSON_AddItemToArray(item, taiItem);
ogs_sbi_free_plmn_id(Tai.plmn_id);
ogs_free(Tai.tac);
}
v = cJSON_PrintUnformatted(item);
ogs_expect(v);
cJSON_Delete(item);
return v;
}
void ogs_sbi_discovery_option_parse_tai(
ogs_sbi_discovery_option_t *discovery_option, char *tai)
{
cJSON *item = NULL;
cJSON *taiItem = NULL;
char *v = NULL;
ogs_assert(discovery_option);
ogs_assert(tai);
v = ogs_sbi_url_decode(tai);
if (!v) {
ogs_error("ogs_sbi_url_decode() failed : tai[%s]", tai);
return;
}
item = cJSON_Parse(v);
if (!item) {
ogs_error("Cannot parse tai[%s]", tai);
ogs_free(v);
return;
}
cJSON_ArrayForEach(taiItem, item) {
if (cJSON_IsObject(taiItem)) {
OpenAPI_tai_t *Tai = OpenAPI_tai_parseFromJSON(taiItem);
if (Tai) {
ogs_5gs_tai_t tai;
memset(&tai, 0, sizeof(tai));
if (Tai->plmn_id)
ogs_sbi_parse_plmn_id(&tai.plmn_id, Tai->plmn_id);
if (Tai->tac)
tai.tac = ogs_uint24_from_string(Tai->tac);
ogs_sbi_discovery_option_add_tai(discovery_option, &tai);
OpenAPI_tai_free(Tai);
} else {
ogs_error("OpenAPI_snssai_parseFromJSON() failed : tai[%s]",
tai);
}
} else {
ogs_error("Invalid cJSON Type in snssias[%s]", tai);
}
}
cJSON_Delete(item);
ogs_free(v);
}

View File

@ -279,6 +279,12 @@ extern "C" {
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_REQUESTER_NF_INSTANCE_ID
#define OGS_SBI_CUSTOM_DISCOVERY_SERVICE_NAMES \
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_SERVICE_NAMES
#define OGS_SBI_CUSTOM_DISCOVERY_SNSSAIS \
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_SNSSAIS
#define OGS_SBI_CUSTOM_DISCOVERY_DNN \
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_DNN
#define OGS_SBI_CUSTOM_DISCOVERY_TAI \
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_TAI
#define OGS_SBI_CUSTOM_DISCOVERY_REQUESTER_FEATURES \
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_REQUESTER_FEATURES
#define OGS_SBI_CUSTOM_PRODUCER_ID \
@ -314,6 +320,8 @@ extern "C" {
#define OGS_SBI_PARAM_PLMN_ID "plmn-id"
#define OGS_SBI_PARAM_SINGLE_NSSAI "single-nssai"
#define OGS_SBI_PARAM_SNSSAI "snssai"
#define OGS_SBI_PARAM_SNSSAIS "snssais"
#define OGS_SBI_PARAM_TAI "tai"
#define OGS_SBI_PARAM_SLICE_INFO_REQUEST_FOR_PDU_SESSION \
"slice-info-request-for-pdu-session"
#define OGS_SBI_PARAM_IPV4ADDR "ipv4Addr"
@ -407,6 +415,12 @@ typedef struct ogs_sbi_discovery_option_s {
int num_of_service_names;
char *service_names[OGS_SBI_MAX_NUM_OF_SERVICE_TYPE];
int num_of_snssais;
ogs_s_nssai_t snssais[OGS_MAX_NUM_OF_SLICE];
char *dnn;
int num_of_tai;
ogs_5gs_tai_t tai[OGS_MAX_NUM_OF_TAI];
uint64_t requester_features;
} ogs_sbi_discovery_option_t;
@ -591,6 +605,8 @@ void ogs_sbi_discovery_option_set_target_nf_instance_id(
void ogs_sbi_discovery_option_set_requester_nf_instance_id(
ogs_sbi_discovery_option_t *discovery_option,
char *requester_nf_instance_id);
void ogs_sbi_discovery_option_set_dnn(
ogs_sbi_discovery_option_t *discovery_option, char *dnn);
void ogs_sbi_discovery_option_add_service_names(
ogs_sbi_discovery_option_t *discovery_option,
@ -601,6 +617,20 @@ void ogs_sbi_discovery_option_parse_service_names(
ogs_sbi_discovery_option_t *discovery_option,
char *service_names);
void ogs_sbi_discovery_option_add_snssais(
ogs_sbi_discovery_option_t *discovery_option, ogs_s_nssai_t *s_nssai);
char *ogs_sbi_discovery_option_build_snssais(
ogs_sbi_discovery_option_t *discovery_option);
void ogs_sbi_discovery_option_parse_snssais(
ogs_sbi_discovery_option_t *discovery_option, char *snssais);
void ogs_sbi_discovery_option_add_tai(
ogs_sbi_discovery_option_t *discovery_option, ogs_5gs_tai_t *tai);
char *ogs_sbi_discovery_option_build_tai(
ogs_sbi_discovery_option_t *discovery_option);
void ogs_sbi_discovery_option_parse_tai(
ogs_sbi_discovery_option_t *discovery_option, char *tai);
#ifdef __cplusplus
}
#endif

View File

@ -777,7 +777,7 @@ static OpenAPI_smf_info_t *build_smf_info(ogs_sbi_nf_info_t *nf_info)
ogs_error("No TaiItem->tac");
if (TaiItem) {
if (TaiItem->plmn_id)
ogs_free(TaiItem->plmn_id);
ogs_sbi_free_plmn_id(TaiItem->plmn_id);
ogs_free(TaiItem);
}
free_smf_info(SmfInfo);
@ -972,7 +972,7 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
ogs_error("No TaiItem->tac");
if (TaiItem) {
if (TaiItem->plmn_id)
ogs_free(TaiItem->plmn_id);
ogs_sbi_free_plmn_id(TaiItem->plmn_id);
ogs_free(TaiItem);
}
free_amf_info(AmfInfo);

View File

@ -274,6 +274,72 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
nf_instance->id);
}
if (discovery_option && discovery_option->num_of_snssais) {
bool rc = false;
char *v = ogs_sbi_discovery_option_build_snssais(
discovery_option);
ogs_expect(v);
if (v) {
char *encoded = ogs_sbi_url_encode(v);
ogs_expect(encoded);
if (encoded) {
/*
* In http.params, the CURL library automatically encodes the URL.
* http.headers implements open5gs to directly encode URLs.
*
* Since it is http.headers,
* we need to encode `v` using ogs_sbi_url_encode();
*/
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_SNSSAIS, encoded);
ogs_free(encoded);
rc = true;
}
ogs_free(v);
}
if (rc == false)
ogs_error("build failed: snssais(%d)[SST:%d SD:0x%x]",
discovery_option->num_of_snssais,
discovery_option->snssais[0].sst,
discovery_option->snssais[0].sd.v);
}
if (discovery_option && discovery_option->dnn) {
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_DNN, discovery_option->dnn);
}
if (discovery_option && discovery_option->num_of_tai) {
bool rc = false;
char *v = ogs_sbi_discovery_option_build_tai(discovery_option);
ogs_expect(v);
if (v) {
char *encoded = ogs_sbi_url_encode(v);
ogs_expect(encoded);
if (encoded) {
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_TAI, encoded);
ogs_free(encoded);
rc = true;
}
ogs_free(v);
}
if (rc == false)
ogs_error("build failed: tai(%d)[PLMN_ID:%06x,TAC:%d]",
discovery_option->num_of_tai,
ogs_plmn_id_hexdump(
&discovery_option->tai[0].plmn_id),
discovery_option->tai[0].tac.v);
}
if (discovery_option &&
discovery_option->requester_features) {
char *v = ogs_uint64_to_string(
@ -615,19 +681,39 @@ static void build_default_discovery_parameter(
if (ogs_sbi_self()->discovery_config.
no_service_names == false &&
discovery_option->num_of_service_names) {
bool rc = false;
/* send array items separated by a comma */
char *v = ogs_sbi_discovery_option_build_service_names(
discovery_option);
ogs_expect(v);
if (v) {
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_SERVICE_NAMES, v);
char *encoded = ogs_sbi_url_encode(v);
ogs_expect(encoded);
if (encoded) {
/*
* In http.params, the CURL library automatically encodes the URL.
* http.headers implements open5gs to directly encode URLs.
*
* Since it is http.headers,
* we need to encode `v` using ogs_sbi_url_encode();
*/
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_SERVICE_NAMES, encoded);
ogs_free(encoded);
rc = true;
}
ogs_free(v);
} else {
}
if (rc == false)
ogs_warn("invalid service names failed[%d:%s]",
discovery_option->num_of_service_names,
discovery_option->service_names[0]);
}
}
}

View File

@ -2160,8 +2160,6 @@ amf_sess_t *amf_sess_cycle(amf_sess_t *sess)
return ogs_pool_cycle(&amf_sess_pool, sess);
}
static bool check_smf_info(ogs_sbi_nf_info_t *nf_info, void *context);
void amf_sbi_select_nf(
ogs_sbi_object_t *sbi_object,
ogs_sbi_service_type_e service_type,
@ -2170,7 +2168,6 @@ void amf_sbi_select_nf(
{
OpenAPI_nf_type_e target_nf_type = OpenAPI_nf_type_NULL;
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_nf_info_t *nf_info = NULL;
amf_sess_t *sess = NULL;
ogs_assert(sbi_object);
@ -2198,22 +2195,6 @@ void amf_sbi_select_nf(
false)
continue;
if ((nf_instance->nf_type == OpenAPI_nf_type_SMF) &&
(ogs_list_count(&nf_instance->nf_info_list) > 0)) {
ogs_list_for_each(&nf_instance->nf_info_list, nf_info) {
if (nf_info->nf_type != nf_instance->nf_type)
continue;
if (check_smf_info(nf_info, sess) == false)
continue;
break;
}
if (!nf_info)
continue;
}
OGS_SBI_SETUP_NF_INSTANCE(
sbi_object->service_type_array[service_type], nf_instance);
break;
@ -2551,90 +2532,6 @@ static void stats_remove_amf_session(void)
ogs_info("[Removed] Number of AMF-Sessions is now %d", num_of_amf_sess);
}
static bool check_smf_info_s_nssai(
ogs_sbi_smf_info_t *smf_info, amf_sess_t *sess);
static bool check_smf_info_nr_tai(
ogs_sbi_smf_info_t *smf_info, amf_sess_t *sess);
static bool check_smf_info(ogs_sbi_nf_info_t *nf_info, void *context)
{
amf_sess_t *sess = NULL;
ogs_assert(nf_info);
ogs_assert(nf_info->nf_type == OpenAPI_nf_type_SMF);
sess = context;
ogs_assert(sess);
if (check_smf_info_s_nssai(&nf_info->smf, sess) == false)
return false;
if (check_smf_info_nr_tai(&nf_info->smf, sess) == false)
return false;
return true;
}
static bool check_smf_info_s_nssai(
ogs_sbi_smf_info_t *smf_info, amf_sess_t *sess)
{
int i, j;
ogs_assert(sess);
ogs_assert(sess->dnn);
ogs_assert(smf_info);
for (i = 0; i < smf_info->num_of_slice; i++) {
if (sess->s_nssai.sst == smf_info->slice[i].s_nssai.sst &&
sess->s_nssai.sd.v == smf_info->slice[i].s_nssai.sd.v) {
for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) {
if (ogs_strcasecmp(sess->dnn, smf_info->slice[i].dnn[j]) == 0)
return true;
}
}
}
return false;
}
static bool check_smf_info_nr_tai(
ogs_sbi_smf_info_t *smf_info, amf_sess_t *sess)
{
amf_ue_t *amf_ue = NULL;
int i, j;
ogs_assert(sess);
amf_ue = sess->amf_ue;
ogs_assert(amf_ue);
ogs_assert(smf_info);
if (smf_info->num_of_nr_tai == 0 && smf_info->num_of_nr_tai_range == 0)
return true;
for (i = 0; i < smf_info->num_of_nr_tai; i++) {
if (memcmp(&amf_ue->nr_tai.plmn_id,
&smf_info->nr_tai[i].plmn_id, OGS_PLMN_ID_LEN) == 0) {
if (amf_ue->nr_tai.tac.v == smf_info->nr_tai[i].tac.v)
return true;
}
}
for (i = 0; i < smf_info->num_of_nr_tai_range; i++) {
if (memcmp(&amf_ue->nr_tai.plmn_id,
&smf_info->nr_tai_range[i].plmn_id, OGS_PLMN_ID_LEN) == 0) {
for (j = 0; j < smf_info->nr_tai_range[i].num_of_tac_range; j++) {
if (amf_ue->nr_tai.tac.v >=
smf_info->nr_tai_range[i].start[j].v &&
amf_ue->nr_tai.tac.v <=
smf_info->nr_tai_range[i].end[j].v) {
return true;
}
}
}
}
return false;
}
/*
* Issues #2482
*

View File

@ -1244,14 +1244,27 @@ int gmm_handle_ul_nas_transport(amf_ue_t *amf_ue,
sess->s_nssai.sst = selected_slice->s_nssai.sst;
sess->s_nssai.sd.v = selected_slice->s_nssai.sd.v;
ogs_info("UE SUPI[%s] DNN[%s] S_NSSAI[SST:%d SD:0x%x]",
amf_ue->supi, sess->dnn, sess->s_nssai.sst, sess->s_nssai.sd.v);
ogs_info("UE SUPI[%s] DNN[%s] S_NSSAI[SST:%d SD:0x%x] "
"smContextRef [%s]",
amf_ue->supi, sess->dnn, sess->s_nssai.sst, sess->s_nssai.sd.v,
sess->sm_context_ref ? sess->sm_context_ref : "NULL");
if (!SESSION_CONTEXT_IN_SMF(sess)) {
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_service_type_e service_type =
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION;
ogs_sbi_discovery_option_t *discovery_option = NULL;
discovery_option = ogs_sbi_discovery_option_new();
ogs_assert(discovery_option);
ogs_sbi_discovery_option_add_snssais(
discovery_option, &sess->s_nssai);
ogs_sbi_discovery_option_set_dnn(discovery_option, sess->dnn);
ogs_sbi_discovery_option_add_tai(
discovery_option, &amf_ue->nr_tai);
nf_instance = sess->sbi.
service_type_array[service_type].nf_instance;
if (!nf_instance) {
@ -1263,21 +1276,29 @@ int gmm_handle_ul_nas_transport(amf_ue_t *amf_ue,
&sess->sbi,
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION,
requester_nf_type,
NULL);
discovery_option);
nf_instance = sess->sbi.
service_type_array[service_type].nf_instance;
}
if (!nf_instance)
ogs_info("No SMF Instance");
else
ogs_info("SMF Instance [%s]", nf_instance->id);
} else
ogs_info("SMF Instance [%s]", nf_instance->id);
if (nf_instance) {
r = amf_sess_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION,
discovery_option,
amf_nsmf_pdusession_build_create_sm_context,
sess, AMF_CREATE_SM_CONTEXT_NO_STATE, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else {
r = amf_sess_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NNSSF_NSSELECTION, NULL,
OGS_SBI_SERVICE_TYPE_NNSSF_NSSELECTION,
discovery_option,
amf_nnssf_nsselection_build_get, sess, 0, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);

View File

@ -29,6 +29,7 @@ int amf_nnssf_nsselection_handle_get(
OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL;
ogs_sbi_client_t *client = NULL, *scp_client = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_sbi_discovery_option_t *discovery_option = NULL;
OpenAPI_authorized_network_slice_info_t *AuthorizedNetworkSliceInfo = NULL;
OpenAPI_nsi_information_t *NsiInformation = NULL;
@ -87,6 +88,13 @@ int amf_nnssf_nsselection_handle_get(
return OGS_ERROR;
}
discovery_option = ogs_sbi_discovery_option_new();
ogs_assert(discovery_option);
ogs_sbi_discovery_option_add_snssais(discovery_option, &sess->s_nssai);
ogs_sbi_discovery_option_set_dnn(discovery_option, sess->dnn);
ogs_sbi_discovery_option_add_tai(discovery_option, &amf_ue->nr_tai);
if (sess->nssf.nrf.id)
ogs_free(sess->nssf.nrf.id);
sess->nssf.nrf.id = ogs_strdup(NsiInformation->nrf_id);
@ -101,7 +109,7 @@ int amf_nnssf_nsselection_handle_get(
param.nrf_uri.nrf.id = sess->nssf.nrf.id;
r = amf_sess_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, discovery_option,
amf_nsmf_pdusession_build_create_sm_context,
sess, AMF_CREATE_SM_CONTEXT_NO_STATE, &param);
ogs_expect(r == OGS_OK);
@ -115,6 +123,9 @@ int amf_nnssf_nsselection_handle_get(
amf_ue, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
ogs_sbi_discovery_option_free(discovery_option);
return OGS_ERROR;;
}
@ -128,7 +139,7 @@ int amf_nnssf_nsselection_handle_get(
ogs_freeaddrinfo(addr);
r = amf_sess_sbi_discover_by_nsi(
sess, OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL);
sess, OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, discovery_option);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}

View File

@ -756,6 +756,22 @@ bool nrf_nnrf_handle_nf_discover(
ogs_debug("[%d] service-names[%s]", i,
discovery_option->service_names[i]);
}
if (discovery_option->num_of_snssais) {
for (i = 0; i < discovery_option->num_of_snssais; i++)
ogs_debug("[%d] snssais[SST:%d SD:0x%x]", i,
discovery_option->snssais[i].sst,
discovery_option->snssais[i].sd.v);
}
if (discovery_option->dnn) {
ogs_debug("dnn[%s]", discovery_option->dnn);
}
if (discovery_option->num_of_tai) {
for (i = 0; i < discovery_option->num_of_tai; i++)
ogs_debug("[%d] tai[PLMN_ID:%06x,TAC:%d]", i,
ogs_plmn_id_hexdump(
&discovery_option->tai[0].plmn_id),
discovery_option->tai[0].tac.v);
}
if (discovery_option->requester_features) {
ogs_debug("requester-features[0x%llx]",
(long long)discovery_option->requester_features);

View File

@ -283,6 +283,8 @@ void scp_assoc_remove(scp_assoc_t *assoc)
ogs_sbi_client_remove(assoc->client);
if (assoc->nrf_client)
ogs_sbi_client_remove(assoc->nrf_client);
if (assoc->discovery_option)
ogs_sbi_discovery_option_free(assoc->discovery_option);
ogs_pool_free(&scp_assoc_pool, assoc);
}

View File

@ -51,6 +51,7 @@ typedef struct scp_assoc_s {
ogs_sbi_request_t *request;
ogs_sbi_service_type_e service_type;
OpenAPI_nf_type_e requester_nf_type;
ogs_sbi_discovery_option_t *discovery_option;
ogs_sbi_nf_instance_t *nf_service_producer;
} scp_assoc_t;

View File

@ -201,6 +201,14 @@ static int request_handler(ogs_sbi_request_t *request, void *data)
service_type = ogs_sbi_service_type_from_name(
discovery_option->service_names[0]);
}
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_SNSSAIS)) {
if (val)
ogs_sbi_discovery_option_parse_snssais(discovery_option, val);
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_DNN)) {
ogs_sbi_discovery_option_set_dnn(discovery_option, val);
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_TAI)) {
if (val)
ogs_sbi_discovery_option_parse_tai(discovery_option, val);
} else if (!strcasecmp(key,
OGS_SBI_CUSTOM_DISCOVERY_REQUESTER_FEATURES)) {
if (val)
@ -466,18 +474,46 @@ static int request_handler(ogs_sbi_request_t *request, void *data)
ogs_assert(assoc->service_type);
assoc->requester_nf_type = requester_nf_type;
ogs_assert(assoc->requester_nf_type);
assoc->discovery_option = discovery_option;
ogs_assert(assoc->discovery_option);
ogs_assert(target_nf_type);
ogs_assert(discovery_option);
if (!discovery_option->num_of_service_names) {
ogs_error("No service names");
scp_assoc_remove(assoc);
return OGS_ERROR;
} else if (discovery_option->num_of_service_names > 1) {
/*
* TS29.500
* 6.10.3 NF Discovery and Selection for indirect communication
* with Delegated Discovery
* 6.10.3.2 Conveyance of NF Discovery Factors
*
* If the NF service consumer includes more than one service name in the
* 3gpp-Sbi-Discovery-service-names header, the service name corresponding
* to the service request shall be listed as the first service name
* in the header.
*
* NOTE 3: The SCP can assume that the service request corresponds
* to the first service name in the header.
*/
int i;
for (i = 1; i < discovery_option->num_of_service_names; i++)
ogs_free(discovery_option->service_names[i]);
discovery_option->num_of_service_names = 1;
ogs_error("NOTE 3: The SCP can assume that the service request "
"corresponds to the first service name in the header "
"in TS29.500");
}
nrf_request = ogs_nnrf_disc_build_discover(
target_nf_type, requester_nf_type, discovery_option);
if (!nrf_request) {
ogs_error("ogs_nnrf_disc_build_discover() failed");
ogs_sbi_discovery_option_free(discovery_option);
scp_assoc_remove(assoc);
return OGS_ERROR;
}
@ -486,15 +522,12 @@ static int request_handler(ogs_sbi_request_t *request, void *data)
ogs_error("ogs_sbi_client_send_request() failed");
scp_assoc_remove(assoc);
ogs_sbi_request_free(nrf_request);
ogs_sbi_discovery_option_free(discovery_option);
return OGS_ERROR;
}
ogs_sbi_request_free(nrf_request);
ogs_sbi_discovery_option_free(discovery_option);
return OGS_OK;
}
@ -577,7 +610,9 @@ static int discover_handler(
ogs_sbi_stream_t *stream = NULL;
ogs_sbi_request_t *request = NULL;
ogs_sbi_service_type_e service_type = OGS_SBI_SERVICE_TYPE_NULL;
OpenAPI_nf_type_e target_nf_type = OpenAPI_nf_type_NULL;
OpenAPI_nf_type_e requester_nf_type = OpenAPI_nf_type_NULL;
ogs_sbi_discovery_option_t *discovery_option = NULL;
ogs_sbi_request_t scp_request;
char *apiroot = NULL;
@ -592,8 +627,12 @@ static int discover_handler(
ogs_assert(request);
service_type = assoc->service_type;
ogs_assert(service_type);
target_nf_type = ogs_sbi_service_type_to_nf_type(service_type);
ogs_assert(target_nf_type);
requester_nf_type = assoc->requester_nf_type;
ogs_assert(requester_nf_type);
discovery_option = assoc->discovery_option;
ogs_assert(discovery_option);
if (status != OGS_OK) {
@ -631,8 +670,8 @@ static int discover_handler(
ogs_nnrf_disc_handle_nf_discover_search_result(message.SearchResult);
nf_instance = ogs_sbi_nf_instance_find_by_service_type(
service_type, requester_nf_type);
nf_instance = ogs_sbi_nf_instance_find_by_discovery_param(
target_nf_type, requester_nf_type, discovery_option);
if (!nf_instance) {
strerror = ogs_msprintf("(NF discover) No NF-Instance [%s:%s]",
ogs_sbi_service_type_to_name(service_type),

View File

@ -820,6 +820,20 @@ static void sbi_message_test8(abts_case *tc, void *data)
ogs_sbi_service_type_from_name(OGS_SBI_SERVICE_NAME_NNSSAAF_NSSAA));
}
static void sbi_message_test9(abts_case *tc, void *data)
{
const char *original = "{\"sst\": 1, \"sd\": \"A08923\"}";
char *encoded = ogs_sbi_url_encode(original);
char *decoded = ogs_sbi_url_decode(encoded);
ABTS_STR_EQUAL(tc,
"%7B%22sst%22%3A 1%2C %22sd%22%3A %22A08923%22%7D", encoded);
ABTS_STR_EQUAL(tc, original, decoded);
ogs_free(encoded);
ogs_free(decoded);
}
abts_suite *test_sbi_message(abts_suite *suite)
{
suite = ADD_SUITE(suite)
@ -832,6 +846,7 @@ abts_suite *test_sbi_message(abts_suite *suite)
abts_run_test(suite, sbi_message_test6, NULL);
abts_run_test(suite, sbi_message_test7, NULL);
abts_run_test(suite, sbi_message_test8, NULL);
abts_run_test(suite, sbi_message_test9, NULL);
return suite;
}