open5gs/lib/core/ogs-strings.c
Sukchan Lee 782a97efe9 Fix DNN Operator-Identifier format and refactor OI parsing for HR roaming interop
Align full-DNN construction with 3GPP TS 23.003 §9.1.2 by switching the
Operator Identifier format from "5gc.mncXXX.mccYYY.3gppnetwork.org" to
"mncXXX.mccYYY.gprs". Introduce new helper utilities to extract and build
OI (Operator Identifier) from both PLMN-ID and FQDN, and replace the
legacy `ogs_home_network_domain_from_fqdn()` usage in AMF/SMF/PCF paths.

This resolves DNN misalignment in vSMF–hSMF PDU Session Create that
caused interop issues with external 5G core vendors during HR roaming.

Includes updates across AMF/SMF/PCF, unit tests, and supporting helpers.

Issues: #4096
2025-12-06 22:23:34 +09:00

441 lines
10 KiB
C

/**
*
* Orcania library
*
* Different functions for different purposes but that can be shared between
* other projects
*
* orcania.c: main functions definitions
*
* Copyright 2015-2020 Nicolas Mora <mail@babelouest.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "core-config-private.h"
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#include "ogs-core.h"
int ogs_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
int r = -1;
/* Microsoft has finally implemented snprintf in Visual Studio 2015.
* In previous versions, I will simulate it as below. */
#if defined(_MSC_VER) && _MSC_VER < 1900
ogs_assert(str);
if (size != 0)
r = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
if (r == -1)
r = _vscprintf(format, ap);
#else
r = vsnprintf(str, size, format, ap);
#endif
str[size-1] = '\0';
return r;
}
int ogs_snprintf(char *str, size_t size, const char *format, ...)
{
int r;
va_list ap;
va_start(ap, format);
r = ogs_vsnprintf(str, size, format, ap);
va_end(ap);
return r;
}
char *ogs_vslprintf(char *str, char *last, const char *format, va_list ap)
{
int r = -1;
ogs_assert(last);
if (!str)
return NULL;
if (str < last)
r = ogs_vsnprintf(str, last - str, format, ap);
return (str + r);
}
char *ogs_slprintf(char *str, char *last, const char *format, ...)
{
char *r;
va_list ap;
va_start(ap, format);
r = ogs_vslprintf(str, last, format, ap);
va_end(ap);
return r;
}
char *ogs_cpystrn(char *dst, const char *src, size_t dst_size)
{
char *d = dst, *end;
if (dst_size == 0) {
return (dst);
}
if (src) {
end = dst + dst_size - 1;
for (; d < end; ++d, ++src) {
if (!(*d = *src)) {
return (d);
}
}
}
*d = '\0'; /* always null terminate */
return (d);
}
/*****************************************
* Memory Pool - Use talloc library
*****************************************/
char *ogs_talloc_strdup(const void *t, const char *p)
{
char *ptr = NULL;
ogs_thread_mutex_lock(ogs_mem_get_mutex());
ptr = talloc_strdup(t, p);
ogs_expect(ptr);
ogs_thread_mutex_unlock(ogs_mem_get_mutex());
return ptr;
}
char *ogs_talloc_strndup(const void *t, const char *p, size_t n)
{
char *ptr = NULL;
ogs_thread_mutex_lock(ogs_mem_get_mutex());
ptr = talloc_strndup(t, p, n);
ogs_expect(ptr);
ogs_thread_mutex_unlock(ogs_mem_get_mutex());
return ptr;
}
void *ogs_talloc_memdup(const void *t, const void *p, size_t size)
{
void *ptr = NULL;
ogs_thread_mutex_lock(ogs_mem_get_mutex());
ptr = talloc_memdup(t, p, size);
ogs_expect(ptr);
ogs_thread_mutex_unlock(ogs_mem_get_mutex());
return ptr;
}
char *ogs_talloc_asprintf(const void *t, const char *fmt, ...)
{
va_list ap;
char *ret;
ogs_thread_mutex_lock(ogs_mem_get_mutex());
va_start(ap, fmt);
ret = talloc_vasprintf(t, fmt, ap);
ogs_expect(ret);
va_end(ap);
ogs_thread_mutex_unlock(ogs_mem_get_mutex());
return ret;
}
char *ogs_talloc_asprintf_append(char *s, const char *fmt, ...)
{
va_list ap;
ogs_thread_mutex_lock(ogs_mem_get_mutex());
va_start(ap, fmt);
s = talloc_vasprintf_append(s, fmt, ap);
ogs_expect(s);
va_end(ap);
ogs_thread_mutex_unlock(ogs_mem_get_mutex());
return s;
}
/*****************************************
* Memory Pool - Use pkbuf library
*****************************************/
char *ogs_strdup_debug(const char *s, const char *file_line)
{
char *res;
size_t len;
if (s == NULL)
return NULL;
len = strlen(s) + 1;
res = ogs_memdup_debug(s, len, file_line);
if (!res) {
ogs_error("ogs_memdup_debug[len:%d] failed", (int)len);
return res;
}
return res;
}
char *ogs_strndup_debug(
const char *s, size_t n, const char *file_line)
{
char *res;
const char *end;
if (s == NULL)
return NULL;
end = memchr(s, '\0', n);
if (end != NULL)
n = end - s;
res = ogs_malloc_debug(n + 1, file_line);
if (!res) {
ogs_error("ogs_malloc_debug[n:%d] failed", (int)n);
return res;
}
memcpy(res, s, n);
res[n] = '\0';
return res;
}
void *ogs_memdup_debug(
const void *m, size_t n, const char *file_line)
{
void *res;
if (m == NULL)
return NULL;
res = ogs_malloc_debug(n, file_line);
if (!res) {
ogs_error("ogs_malloc_debug[n:%d] failed", (int)n);
return res;
}
memcpy(res, m, n);
return res;
}
/*
* char *ogs_msprintf(const char *message, ...)
* char *mstrcatf(char *source, const char *message, ...)
*
* Orcania library
* Copyright 2015-2018 Nicolas Mora <mail@babelouest.org>
* License: LGPL-2.1
*
* https://github.com/babelouest/orcania.git
*/
char *ogs_msprintf_debug(
const char *file_line, const char *message, ...)
{
va_list argp, argp_cpy;
size_t out_len = 0;
char *out = NULL;
if (message != NULL) {
va_start(argp, message);
va_copy(argp_cpy, argp); /* We make a copy because
in some architectures,
vsnprintf can modify argp */
out_len = vsnprintf(NULL, 0, message, argp);
out = ogs_malloc_debug(out_len + sizeof(char), file_line);
if (out == NULL) {
va_end(argp);
va_end(argp_cpy);
return NULL;
}
vsnprintf(out, (out_len + sizeof(char)), message, argp_cpy);
va_end(argp);
va_end(argp_cpy);
}
return out;
}
char *ogs_mstrcatf_debug(
char *source, const char *file_line, const char *message, ...)
{
va_list argp, argp_cpy;
char *out = NULL, *message_formatted = NULL;
size_t message_formatted_len = 0, out_len = 0;
if (message != NULL) {
if (source != NULL) {
va_start(argp, message);
va_copy(argp_cpy, argp); /* We make a copy because
in some architectures,
vsnprintf can modify argp */
message_formatted_len = vsnprintf(NULL, 0, message, argp);
message_formatted = ogs_malloc(message_formatted_len+sizeof(char));
if (message_formatted != NULL) {
vsnprintf(message_formatted,
(message_formatted_len+sizeof(char)), message, argp_cpy);
out = ogs_msprintf_debug(
file_line, "%s%s", source, message_formatted);
ogs_free(message_formatted);
ogs_free(source);
}
va_end(argp);
va_end(argp_cpy);
} else {
va_start(argp, message);
va_copy(argp_cpy, argp); /* We make a copy because
in some architectures,
vsnprintf can modify argp */
out_len = vsnprintf(NULL, 0, message, argp);
out = ogs_malloc_debug(out_len+sizeof(char), file_line);
if (out != NULL) {
vsnprintf(out, (out_len+sizeof(char)), message, argp_cpy);
}
va_end(argp);
va_end(argp_cpy);
}
}
return out;
}
char *ogs_trimwhitespace(char *str)
{
char *end;
if (str == NULL) {
return NULL;
} else if (*str == 0) {
return str;
}
while (isspace((unsigned char)*str)) str++;
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) {
end--;
}
*(end+1) = 0;
return str;
}
char *ogs_left_trimcharacter(char *str, char to_remove)
{
if (str == NULL) {
return NULL;
} else if (*str == 0) {
return str;
}
while(*str == to_remove) str++;
return str;
}
char *ogs_right_trimcharacter(char *str, char to_remove)
{
char *end;
if (str == NULL) {
return NULL;
} else if (*str == 0) {
return str;
}
end = str + strlen(str) - 1;
while(end > str && (*end == to_remove)) {
end--;
}
*(end+1) = 0;
return str;
}
char *ogs_trimcharacter(char *str, char to_remove)
{
return ogs_right_trimcharacter(
ogs_left_trimcharacter(str, to_remove), to_remove);
}
char *ogs_strrstr(const char *haystack, const char *needle)
{
char *result = NULL;
char *p = (char *)haystack;
if (!haystack || !needle)
return NULL;
if (*needle == '\0')
return (char *)haystack;
while ((p = strstr(p, needle)) != NULL) {
result = p;
p++;
}
return result;
}