mirror of
https://github.com/open5gs/open5gs.git
synced 2025-10-23 07:41:57 +00:00
[SCTP] Support setting local address (#3344)
Added support for binding to local IP addresses in ogs_sctp_client and ogs_sctp_server, and correct SGsAP configuration Implemented the ability to bind to one or multiple local IP addresses using `sctp_bindx()` in both the `ogs_sctp_client()` and `ogs_sctp_server()` APIs. Users can now specify local addresses in the configuration files under the new `local_addresses` field, reducing unnecessary complexity and signaling caused by binding to `ANY_ADDR`. This update addresses issue https://osmocom.org/issues/6509 by ensuring correct operation in multi-interface and complex networking setups. Additionally, corrected the `sgsap` configuration by changing it from `server` to `client`, and added support for specifying `local_addresses` for local binding as follows: ``` sgsap: client: - address: msc.open5gs.org # SCTP server address configured on the MSC/VL local_address: 127.0.0.2 # SCTP local IP addresses to be bound in the M ```
This commit is contained in:
@@ -59,7 +59,7 @@ mme:
|
||||
smf:
|
||||
- address: 127.0.0.4
|
||||
sgsap:
|
||||
server:
|
||||
client:
|
||||
- address: 127.0.0.2
|
||||
map:
|
||||
tai:
|
||||
|
@@ -164,8 +164,9 @@ mme:
|
||||
################################################################################
|
||||
# o MSC/VLR
|
||||
# sgsap:
|
||||
# server:
|
||||
# - address: 127.0.0.2
|
||||
# client:
|
||||
# - address: msc.open5gs.org # SCTP server address configured on the MSC/VLR
|
||||
# local_address: 127.0.0.2 # SCTP local IP addresses to be bound in the MME
|
||||
# map:
|
||||
# tai:
|
||||
# plmn_id:
|
||||
@@ -188,7 +189,15 @@ mme:
|
||||
# mcc: 002
|
||||
# mnc: 02
|
||||
# lac: 43692
|
||||
# - address: msc.open5gs.org
|
||||
# - address: # SCTP server address configured on the MSC/VLR
|
||||
# - 127.0.0.88
|
||||
# - 10.0.0.88
|
||||
# - 172.16.0.88
|
||||
# - 2001:db8:babe::88
|
||||
# local_address: # SCTP local IP addresses to be bound in the MME
|
||||
# - 127.0.0.2
|
||||
# - 192.168.1.4
|
||||
# - 2001:db8:cafe::2
|
||||
# map:
|
||||
# tai:
|
||||
# plmn_id:
|
||||
|
@@ -53,138 +53,332 @@ ogs_sock_t *ogs_sctp_socket(int family, int type)
|
||||
return new;
|
||||
}
|
||||
|
||||
ogs_sock_t *ogs_sctp_server(
|
||||
int type, ogs_sockaddr_t *sa_list, ogs_sockopt_t *socket_option)
|
||||
/**
|
||||
* @brief
|
||||
* 1) Count the number of addresses in sa_list and determine the total
|
||||
* buffer size.
|
||||
* 2) Allocate a single continuous buffer (unsigned char).
|
||||
* 3) Copy each address (sockaddr_in or sockaddr_in6) into this continuous
|
||||
* buffer.
|
||||
*
|
||||
* @param sa_list Linked list of ogs_sockaddr_t structures.
|
||||
* @param out_count [OUT] Receives the number of addresses.
|
||||
* @param out_total_len [OUT] Receives the total bytes for the continuous
|
||||
* buffer.
|
||||
*
|
||||
* @return
|
||||
* On success, returns a pointer to the allocated buffer containing all
|
||||
* addresses. On failure, logs an error and returns NULL.
|
||||
*/
|
||||
static unsigned char *create_continuous_address_buffer(
|
||||
ogs_sockaddr_t *sa_list,
|
||||
int *out_count,
|
||||
int *out_total_len)
|
||||
{
|
||||
int rv;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
||||
ogs_sock_t *new = NULL;
|
||||
ogs_sockaddr_t *addr;
|
||||
ogs_sockopt_t option;
|
||||
int addr_count = 0;
|
||||
int total_len = 0;
|
||||
unsigned char *addr_buf = NULL;
|
||||
int offset = 0;
|
||||
|
||||
ogs_assert(sa_list);
|
||||
|
||||
ogs_sockopt_init(&option);
|
||||
if (socket_option)
|
||||
memcpy(&option, socket_option, sizeof option);
|
||||
|
||||
addr = sa_list;
|
||||
while (addr) {
|
||||
new = ogs_sctp_socket(addr->ogs_sa_family, type);
|
||||
if (new) {
|
||||
rv = ogs_sctp_peer_addr_params(new, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_rto_info(new, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_initmsg(new, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
if (option.sctp_nodelay == true) {
|
||||
rv = ogs_sctp_nodelay(new, true);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
} else
|
||||
ogs_warn("SCTP NO_DELAY Disabled");
|
||||
|
||||
if (option.so_linger.l_onoff == true) {
|
||||
rv = ogs_sctp_so_linger(new, option.so_linger.l_linger);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
rv = ogs_listen_reusable(new->fd, true);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
if (ogs_sock_bind(new, addr) == OGS_OK) {
|
||||
ogs_debug("sctp_server() [%s]:%d",
|
||||
OGS_ADDR(addr, buf), OGS_PORT(addr));
|
||||
break;
|
||||
}
|
||||
|
||||
ogs_sock_destroy(new);
|
||||
}
|
||||
|
||||
addr = addr->next;
|
||||
/* 1) Count addresses and total buffer size needed. */
|
||||
for (addr = sa_list; addr; addr = addr->next) {
|
||||
addr_count++;
|
||||
/* E.g., sizeof(sockaddr_in) or sizeof(sockaddr_in6). */
|
||||
total_len += ogs_sockaddr_len(addr);
|
||||
}
|
||||
|
||||
if (addr == NULL) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_server() [%s]:%d failed",
|
||||
OGS_ADDR(sa_list, buf), OGS_PORT(sa_list));
|
||||
if (addr_count == 0) {
|
||||
ogs_error("No valid address in sa_list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ogs_assert(new);
|
||||
/* 2) Allocate the continuous buffer (unsigned char). */
|
||||
addr_buf = ogs_calloc(1, total_len);
|
||||
if (!addr_buf) {
|
||||
ogs_error("Failed to allocate memory for addr_buf");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rv = ogs_sock_listen(new);
|
||||
/* 3) Copy each address structure into addr_buf. */
|
||||
offset = 0;
|
||||
for (addr = sa_list; addr; addr = addr->next) {
|
||||
socklen_t socklen = ogs_sockaddr_len(addr);
|
||||
memcpy(addr_buf + offset, &addr->sa, socklen);
|
||||
offset += socklen;
|
||||
}
|
||||
|
||||
/* Pass back the number of addresses and total length. */
|
||||
*out_count = addr_count;
|
||||
*out_total_len = total_len;
|
||||
|
||||
return addr_buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create an SCTP server socket and bind multiple addresses at once
|
||||
* using sctp_bindx().
|
||||
*
|
||||
* @param type SCTP socket type (e.g., SOCK_SEQPACKET or SOCK_STREAM)
|
||||
* @param sa_list Linked list of ogs_sockaddr_t structures
|
||||
* @param socket_option Additional socket/SCTP options
|
||||
*
|
||||
* @return
|
||||
* On success, returns a pointer to an ogs_sock_t instance; on failure,
|
||||
* returns NULL.
|
||||
*/
|
||||
ogs_sock_t *ogs_sctp_server(
|
||||
int type,
|
||||
ogs_sockaddr_t *sa_list,
|
||||
ogs_sockopt_t *socket_option)
|
||||
{
|
||||
int rv;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
ogs_sock_t *new_sock = NULL;
|
||||
ogs_sockopt_t option;
|
||||
|
||||
/* Variables for sctp_bindx() usage. */
|
||||
unsigned char *addr_buf = NULL;
|
||||
int addr_count = 0;
|
||||
int total_len = 0;
|
||||
|
||||
ogs_assert(sa_list);
|
||||
|
||||
/* Initialize socket options. */
|
||||
ogs_sockopt_init(&option);
|
||||
if (socket_option)
|
||||
memcpy(&option, socket_option, sizeof(option));
|
||||
|
||||
/*
|
||||
* Obtain a contiguous buffer for all addresses:
|
||||
* 1) Count the addresses.
|
||||
* 2) Allocate the buffer.
|
||||
* 3) Copy the addresses into the buffer.
|
||||
*/
|
||||
addr_buf = create_continuous_address_buffer(
|
||||
sa_list, &addr_count, &total_len);
|
||||
if (!addr_buf) {
|
||||
/* The helper logs errors, so just return. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an SCTP socket using the family of the first address
|
||||
* in sa_list.
|
||||
*/
|
||||
new_sock = ogs_sctp_socket(sa_list->ogs_sa_family, type);
|
||||
if (!new_sock) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_server() Failed to create SCTP socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Configure SCTP-specific options. */
|
||||
rv = ogs_sctp_peer_addr_params(new_sock, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
return new;
|
||||
rv = ogs_sctp_rto_info(new_sock, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_initmsg(new_sock, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
if (option.sctp_nodelay == true) {
|
||||
rv = ogs_sctp_nodelay(new_sock, true);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
} else {
|
||||
ogs_warn("SCTP NO_DELAY Disabled");
|
||||
}
|
||||
|
||||
if (option.so_linger.l_onoff == true) {
|
||||
rv = ogs_sctp_so_linger(new_sock, option.so_linger.l_linger);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
/* Enable address reuse if needed. */
|
||||
rv = ogs_listen_reusable(new_sock->fd, true);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
/*
|
||||
* Bind all addresses at once using sctp_bindx().
|
||||
* (struct sockaddr *)addr_buf points to the contiguous buffer.
|
||||
*/
|
||||
rv = sctp_bindx(new_sock->fd, (struct sockaddr *)addr_buf,
|
||||
addr_count, SCTP_BINDX_ADD_ADDR);
|
||||
if (rv < 0) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_bindx() failed to bind multiple addresses");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log debug info: only the first address is shown here as an example.
|
||||
*/
|
||||
ogs_debug("sctp_server() [%s]:%d (bound %d addresses)",
|
||||
OGS_ADDR(sa_list, buf), OGS_PORT(sa_list), addr_count);
|
||||
|
||||
/* Start listening for connections. */
|
||||
rv = ogs_sock_listen(new_sock);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
/* Success: free the buffer and return the socket. */
|
||||
ogs_free(addr_buf);
|
||||
return new_sock;
|
||||
|
||||
err:
|
||||
if (addr_buf)
|
||||
ogs_free(addr_buf);
|
||||
if (new_sock)
|
||||
ogs_sock_destroy(new_sock);
|
||||
|
||||
/*
|
||||
* On failure, log an error based on the first address
|
||||
* in sa_list (customize as needed).
|
||||
*/
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_server() [%s]:%d failed",
|
||||
OGS_ADDR(sa_list, buf), OGS_PORT(sa_list));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ogs_sock_t *ogs_sctp_client(
|
||||
int type, ogs_sockaddr_t *sa_list, ogs_sockopt_t *socket_option)
|
||||
int type,
|
||||
ogs_sockaddr_t *sa_list,
|
||||
ogs_sockaddr_t *local_sa_list,
|
||||
ogs_sockopt_t *socket_option)
|
||||
{
|
||||
int rv;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
||||
ogs_sock_t *new = NULL;
|
||||
ogs_sockaddr_t *addr;
|
||||
ogs_sock_t *new_sock = NULL;
|
||||
ogs_sockopt_t option;
|
||||
|
||||
/* Buffers and counters for remote addresses. */
|
||||
unsigned char *remote_buf = NULL;
|
||||
int remote_count = 0;
|
||||
int remote_len = 0;
|
||||
|
||||
/* Buffers and counters for local addresses (if provided). */
|
||||
unsigned char *local_buf = NULL;
|
||||
int local_count = 0;
|
||||
int local_len = 0;
|
||||
|
||||
ogs_assert(sa_list);
|
||||
|
||||
/* Initialize socket options and copy user-provided options if present. */
|
||||
ogs_sockopt_init(&option);
|
||||
if (socket_option)
|
||||
memcpy(&option, socket_option, sizeof option);
|
||||
memcpy(&option, socket_option, sizeof(option));
|
||||
|
||||
addr = sa_list;
|
||||
while (addr) {
|
||||
new = ogs_sctp_socket(addr->ogs_sa_family, type);
|
||||
if (new) {
|
||||
rv = ogs_sctp_peer_addr_params(new, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_rto_info(new, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_initmsg(new, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
if (option.sctp_nodelay == true) {
|
||||
rv = ogs_sctp_nodelay(new, true);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
} else
|
||||
ogs_warn("SCTP NO_DELAY Disabled");
|
||||
|
||||
if (option.so_linger.l_onoff == true) {
|
||||
rv = ogs_sctp_so_linger(new, option.so_linger.l_linger);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
if (ogs_sock_connect(new, addr) == OGS_OK) {
|
||||
ogs_debug("sctp_client() [%s]:%d",
|
||||
OGS_ADDR(addr, buf), OGS_PORT(addr));
|
||||
break;
|
||||
}
|
||||
|
||||
ogs_sock_destroy(new);
|
||||
}
|
||||
|
||||
addr = addr->next;
|
||||
}
|
||||
|
||||
if (addr == NULL) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_client() [%s]:%d failed",
|
||||
OGS_ADDR(sa_list, buf), OGS_PORT(sa_list));
|
||||
/*
|
||||
* Build the contiguous buffer for REMOTE addresses using our helper
|
||||
* function. This will be used later by sctp_connectx().
|
||||
*/
|
||||
remote_buf = create_continuous_address_buffer(
|
||||
sa_list, &remote_count, &remote_len);
|
||||
if (!remote_buf) {
|
||||
/* Logs and returns NULL on failure. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ogs_assert(new);
|
||||
/*
|
||||
* Create the SCTP socket using the address family of the first remote
|
||||
* address.
|
||||
*/
|
||||
new_sock = ogs_sctp_socket(sa_list->ogs_sa_family, type);
|
||||
if (!new_sock) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_client() Failed to create SCTP socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return new;
|
||||
/* Configure SCTP-specific options. */
|
||||
rv = ogs_sctp_peer_addr_params(new_sock, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_rto_info(new_sock, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
rv = ogs_sctp_initmsg(new_sock, &option);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
if (option.sctp_nodelay == true) {
|
||||
rv = ogs_sctp_nodelay(new_sock, true);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
} else {
|
||||
ogs_warn("SCTP NO_DELAY Disabled");
|
||||
}
|
||||
|
||||
if (option.so_linger.l_onoff == true) {
|
||||
rv = ogs_sctp_so_linger(new_sock, option.so_linger.l_linger);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* If local_sa_list is provided, bind those addresses before connecting.
|
||||
* (Optional: some clients do not need explicit local bind.)
|
||||
*/
|
||||
if (local_sa_list) {
|
||||
local_buf = create_continuous_address_buffer(
|
||||
local_sa_list, &local_count, &local_len);
|
||||
if (!local_buf) {
|
||||
/* Error already logged. */
|
||||
goto err;
|
||||
}
|
||||
/* We can bind them using sctp_bindx() if desired. */
|
||||
rv = sctp_bindx(new_sock->fd,
|
||||
(struct sockaddr *)local_buf,
|
||||
local_count,
|
||||
SCTP_BINDX_ADD_ADDR);
|
||||
if (rv < 0) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_client() bind local addresses failed");
|
||||
goto err;
|
||||
}
|
||||
ogs_debug("sctp_client() bound %d local addresses", local_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to the REMOTE addresses using sctp_connectx().
|
||||
* (struct sockaddr *)remote_buf is the contiguous buffer.
|
||||
*/
|
||||
rv = sctp_connectx(new_sock->fd,
|
||||
(struct sockaddr *)remote_buf,
|
||||
remote_count,
|
||||
NULL /* assoc_id */);
|
||||
if (rv < 0) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_connectx() failed to connect");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Debug log for the first remote address. */
|
||||
ogs_debug("sctp_client() connected to [%s]:%d",
|
||||
OGS_ADDR(sa_list, buf), OGS_PORT(sa_list));
|
||||
|
||||
/* Success: free buffers and return the new socket. */
|
||||
if (local_buf)
|
||||
ogs_free(local_buf);
|
||||
if (remote_buf)
|
||||
ogs_free(remote_buf);
|
||||
return new_sock;
|
||||
|
||||
err:
|
||||
if (local_buf)
|
||||
ogs_free(local_buf);
|
||||
if (remote_buf)
|
||||
ogs_free(remote_buf);
|
||||
if (new_sock)
|
||||
ogs_sock_destroy(new_sock);
|
||||
|
||||
/*
|
||||
* On failure, log an error based on the first remote address.
|
||||
* Adjust to your needs, e.g., log local too if necessary.
|
||||
*/
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"sctp_client() [%s]:%d failed",
|
||||
OGS_ADDR(sa_list, buf),
|
||||
OGS_PORT(sa_list));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ogs_sctp_connect(ogs_sock_t *sock, ogs_sockaddr_t *sa_list)
|
||||
|
@@ -109,7 +109,9 @@ ogs_sock_t *ogs_sctp_socket(int family, int type);
|
||||
ogs_sock_t *ogs_sctp_server(
|
||||
int type, ogs_sockaddr_t *sa_list, ogs_sockopt_t *socket_option);
|
||||
ogs_sock_t *ogs_sctp_client(
|
||||
int type, ogs_sockaddr_t *sa_list, ogs_sockopt_t *socket_option);
|
||||
int type,
|
||||
ogs_sockaddr_t *sa_list, ogs_sockaddr_t *local_sa_list,
|
||||
ogs_sockopt_t *socket_option);
|
||||
|
||||
int ogs_sctp_bind(ogs_sock_t *sock, ogs_sockaddr_t *sa_list);
|
||||
int ogs_sctp_connect(ogs_sock_t *sock, ogs_sockaddr_t *sa_list);
|
||||
|
@@ -156,7 +156,9 @@ ogs_sock_t *ogs_sctp_server(
|
||||
}
|
||||
|
||||
ogs_sock_t *ogs_sctp_client(
|
||||
int type, ogs_sockaddr_t *sa_list, ogs_sockopt_t *socket_option)
|
||||
int type,
|
||||
ogs_sockaddr_t *sa_list, ogs_sockaddr_t *local_sa_list,
|
||||
ogs_sockopt_t *socket_option)
|
||||
{
|
||||
int rv;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
@@ -2050,9 +2050,9 @@ int mme_context_parse_config(void)
|
||||
while (ogs_yaml_iter_next(&sgsap_iter)) {
|
||||
const char *sgsap_key = ogs_yaml_iter_key(&sgsap_iter);
|
||||
ogs_assert(sgsap_key);
|
||||
if (!strcmp(sgsap_key, "server")) {
|
||||
ogs_yaml_iter_t server_iter, server_array;
|
||||
ogs_yaml_iter_recurse(&sgsap_iter, &server_array);
|
||||
if (!strcmp(sgsap_key, "client")) {
|
||||
ogs_yaml_iter_t client_iter, client_array;
|
||||
ogs_yaml_iter_recurse(&sgsap_iter, &client_array);
|
||||
do {
|
||||
mme_vlr_t *vlr = NULL;
|
||||
ogs_plmn_id_t plmn_id;
|
||||
@@ -2063,38 +2063,39 @@ int mme_context_parse_config(void)
|
||||
const char *tac, *lac;
|
||||
} map[MAX_NUM_OF_CSMAP];
|
||||
int map_num = 0;
|
||||
ogs_sockaddr_t *addr = NULL;
|
||||
ogs_sockaddr_t *addr = NULL, *local_addr = NULL;
|
||||
int family = AF_UNSPEC;
|
||||
int i, hostname_num = 0;
|
||||
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
|
||||
int i, hostname_num = 0, local_hostname_num = 0;
|
||||
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME],
|
||||
*local_hostname[OGS_MAX_NUM_OF_HOSTNAME];
|
||||
uint16_t port = self.sgsap_port;
|
||||
|
||||
ogs_sockopt_t option;
|
||||
bool is_option = false;
|
||||
|
||||
if (ogs_yaml_iter_type(&server_array) ==
|
||||
if (ogs_yaml_iter_type(&client_array) ==
|
||||
YAML_MAPPING_NODE) {
|
||||
memcpy(&server_iter, &server_array,
|
||||
memcpy(&client_iter, &client_array,
|
||||
sizeof(ogs_yaml_iter_t));
|
||||
} else if (ogs_yaml_iter_type(&server_array) ==
|
||||
} else if (ogs_yaml_iter_type(&client_array) ==
|
||||
YAML_SEQUENCE_NODE) {
|
||||
if (!ogs_yaml_iter_next(&server_array))
|
||||
if (!ogs_yaml_iter_next(&client_array))
|
||||
break;
|
||||
ogs_yaml_iter_recurse(
|
||||
&server_array, &server_iter);
|
||||
} else if (ogs_yaml_iter_type(&server_array) ==
|
||||
&client_array, &client_iter);
|
||||
} else if (ogs_yaml_iter_type(&client_array) ==
|
||||
YAML_SCALAR_NODE) {
|
||||
break;
|
||||
} else
|
||||
ogs_assert_if_reached();
|
||||
|
||||
while (ogs_yaml_iter_next(&server_iter)) {
|
||||
const char *server_key =
|
||||
ogs_yaml_iter_key(&server_iter);
|
||||
ogs_assert(server_key);
|
||||
if (!strcmp(server_key, "family")) {
|
||||
while (ogs_yaml_iter_next(&client_iter)) {
|
||||
const char *client_key =
|
||||
ogs_yaml_iter_key(&client_iter);
|
||||
ogs_assert(client_key);
|
||||
if (!strcmp(client_key, "family")) {
|
||||
const char *v =
|
||||
ogs_yaml_iter_value(&server_iter);
|
||||
ogs_yaml_iter_value(&client_iter);
|
||||
if (v) family = atoi(v);
|
||||
if (family != AF_UNSPEC &&
|
||||
family != AF_INET &&
|
||||
@@ -2106,9 +2107,9 @@ int mme_context_parse_config(void)
|
||||
AF_UNSPEC, AF_INET, AF_INET6);
|
||||
family = AF_UNSPEC;
|
||||
}
|
||||
} else if (!strcmp(server_key, "address")) {
|
||||
} else if (!strcmp(client_key, "address")) {
|
||||
ogs_yaml_iter_t hostname_iter;
|
||||
ogs_yaml_iter_recurse(&server_iter,
|
||||
ogs_yaml_iter_recurse(&client_iter,
|
||||
&hostname_iter);
|
||||
ogs_assert(ogs_yaml_iter_type(
|
||||
&hostname_iter) !=
|
||||
@@ -2131,26 +2132,53 @@ int mme_context_parse_config(void)
|
||||
} while (ogs_yaml_iter_type(
|
||||
&hostname_iter) ==
|
||||
YAML_SEQUENCE_NODE);
|
||||
} else if (!strcmp(server_key, "port")) {
|
||||
} else if (!strcmp(client_key,
|
||||
"local_address")) {
|
||||
ogs_yaml_iter_t local_hostname_iter;
|
||||
ogs_yaml_iter_recurse(&client_iter,
|
||||
&local_hostname_iter);
|
||||
ogs_assert(ogs_yaml_iter_type(
|
||||
&local_hostname_iter) !=
|
||||
YAML_MAPPING_NODE);
|
||||
|
||||
do {
|
||||
if (ogs_yaml_iter_type(
|
||||
&local_hostname_iter) ==
|
||||
YAML_SEQUENCE_NODE) {
|
||||
if (!ogs_yaml_iter_next(
|
||||
&local_hostname_iter))
|
||||
break;
|
||||
}
|
||||
|
||||
ogs_assert(local_hostname_num <
|
||||
OGS_MAX_NUM_OF_HOSTNAME);
|
||||
local_hostname
|
||||
[local_hostname_num++] =
|
||||
ogs_yaml_iter_value(
|
||||
&local_hostname_iter);
|
||||
} while (ogs_yaml_iter_type(
|
||||
&local_hostname_iter) ==
|
||||
YAML_SEQUENCE_NODE);
|
||||
} else if (!strcmp(client_key, "port")) {
|
||||
const char *v =
|
||||
ogs_yaml_iter_value(&server_iter);
|
||||
ogs_yaml_iter_value(&client_iter);
|
||||
if (v) {
|
||||
port = atoi(v);
|
||||
self.sgsap_port = port;
|
||||
}
|
||||
} else if (!strcmp(server_key, "option")) {
|
||||
} else if (!strcmp(client_key, "option")) {
|
||||
rv = ogs_app_parse_sockopt_config(
|
||||
&server_iter, &option);
|
||||
&client_iter, &option);
|
||||
if (rv != OGS_OK) {
|
||||
ogs_error("ogs_app_parse_sockopt_"
|
||||
"config() failed");
|
||||
return rv;
|
||||
}
|
||||
is_option = true;
|
||||
} else if (!strcmp(server_key, "map")) {
|
||||
} else if (!strcmp(client_key, "map")) {
|
||||
ogs_yaml_iter_t map_iter;
|
||||
ogs_yaml_iter_recurse(
|
||||
&server_iter, &map_iter);
|
||||
&client_iter, &map_iter);
|
||||
|
||||
map[map_num].tai_mcc = NULL;
|
||||
map[map_num].tai_mnc = NULL;
|
||||
@@ -2320,13 +2348,13 @@ int mme_context_parse_config(void)
|
||||
|
||||
map_num++;
|
||||
|
||||
} else if (!strcmp(server_key, "tai")) {
|
||||
} else if (!strcmp(client_key, "tai")) {
|
||||
ogs_error(
|
||||
"tai/lai configuraton changed to "
|
||||
"map.tai/map.lai");
|
||||
ogs_log_print(OGS_LOG_ERROR,
|
||||
"sgsap:\n"
|
||||
" server\n"
|
||||
" client\n"
|
||||
" address: 127.0.0.2\n"
|
||||
" map:\n"
|
||||
" tai:\n"
|
||||
@@ -2340,13 +2368,13 @@ int mme_context_parse_config(void)
|
||||
" mnc: 01\n"
|
||||
" lac: 43691\n");
|
||||
return OGS_ERROR;
|
||||
} else if (!strcmp(server_key, "lai")) {
|
||||
} else if (!strcmp(client_key, "lai")) {
|
||||
ogs_error(
|
||||
"tai/lai configuraton changed to "
|
||||
"map.tai/map.lai");
|
||||
ogs_log_print(OGS_LOG_ERROR,
|
||||
"sgsap:\n"
|
||||
" server\n"
|
||||
" client\n"
|
||||
" address: 127.0.0.2\n"
|
||||
" map:\n"
|
||||
" tai:\n"
|
||||
@@ -2362,7 +2390,7 @@ int mme_context_parse_config(void)
|
||||
return OGS_ERROR;
|
||||
} else
|
||||
ogs_warn("unknown key `%s`",
|
||||
server_key);
|
||||
client_key);
|
||||
|
||||
}
|
||||
|
||||
@@ -2386,7 +2414,20 @@ int mme_context_parse_config(void)
|
||||
|
||||
if (addr == NULL) continue;
|
||||
|
||||
vlr = mme_vlr_add(addr,
|
||||
local_addr = NULL;
|
||||
for (i = 0; i < local_hostname_num; i++) {
|
||||
rv = ogs_addaddrinfo(&local_addr,
|
||||
family, local_hostname[i], port, 0);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
ogs_filter_ip_version(&local_addr,
|
||||
ogs_global_conf()->parameter.no_ipv4,
|
||||
ogs_global_conf()->parameter.no_ipv6,
|
||||
ogs_global_conf()->parameter.
|
||||
prefer_ipv4);
|
||||
|
||||
vlr = mme_vlr_add(addr, local_addr,
|
||||
is_option ? &option : NULL);
|
||||
ogs_assert(vlr);
|
||||
|
||||
@@ -2409,7 +2450,7 @@ int mme_context_parse_config(void)
|
||||
&csmap->lai.nas_plmn_id, &plmn_id);
|
||||
csmap->lai.lac = atoi(map[i].lac);
|
||||
}
|
||||
} while (ogs_yaml_iter_type(&server_array) ==
|
||||
} while (ogs_yaml_iter_type(&client_array) ==
|
||||
YAML_SEQUENCE_NODE);
|
||||
} else
|
||||
ogs_warn("unknown key `%s`", sgsap_key);
|
||||
@@ -2737,7 +2778,10 @@ ogs_sockaddr_t *mme_pgw_addr_find_by_apn_enb(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mme_vlr_t *mme_vlr_add(ogs_sockaddr_t *sa_list, ogs_sockopt_t *option)
|
||||
mme_vlr_t *mme_vlr_add(
|
||||
ogs_sockaddr_t *sa_list,
|
||||
ogs_sockaddr_t *local_sa_list,
|
||||
ogs_sockopt_t *option)
|
||||
{
|
||||
mme_vlr_t *vlr = NULL;
|
||||
|
||||
@@ -2751,6 +2795,7 @@ mme_vlr_t *mme_vlr_add(ogs_sockaddr_t *sa_list, ogs_sockopt_t *option)
|
||||
vlr->ostream_id = 0;
|
||||
|
||||
vlr->sa_list = sa_list;
|
||||
vlr->local_sa_list = local_sa_list;
|
||||
if (option) {
|
||||
vlr->max_num_of_ostreams = option->sctp.sinit_num_ostreams;
|
||||
vlr->option = ogs_memdup(option, sizeof *option);
|
||||
@@ -2770,6 +2815,7 @@ void mme_vlr_remove(mme_vlr_t *vlr)
|
||||
mme_vlr_close(vlr);
|
||||
|
||||
ogs_freeaddrinfo(vlr->sa_list);
|
||||
ogs_freeaddrinfo(vlr->local_sa_list);
|
||||
if (vlr->option)
|
||||
ogs_free(vlr->option);
|
||||
|
||||
|
@@ -216,6 +216,7 @@ typedef struct mme_vlr_s {
|
||||
uint16_t ostream_id; /* vlr_ostream_id generator */
|
||||
|
||||
ogs_sockaddr_t *sa_list; /* VLR SGsAP Socket Address List */
|
||||
ogs_sockaddr_t *local_sa_list; /* VLR SGsAP Socket Local Address List */
|
||||
|
||||
ogs_sock_t *sock; /* VLR SGsAP Socket */
|
||||
ogs_sockaddr_t *addr; /* VLR SGsAP Connected Socket Address */
|
||||
@@ -938,7 +939,10 @@ void mme_pgw_remove_all(void);
|
||||
ogs_sockaddr_t *mme_pgw_addr_find_by_apn_enb(
|
||||
ogs_list_t *list, int family, const mme_sess_t *sess);
|
||||
|
||||
mme_vlr_t *mme_vlr_add(ogs_sockaddr_t *sa_list, ogs_sockopt_t *option);
|
||||
mme_vlr_t *mme_vlr_add(
|
||||
ogs_sockaddr_t *sa_list,
|
||||
ogs_sockaddr_t *local_sa_list,
|
||||
ogs_sockopt_t *option);
|
||||
void mme_vlr_remove(mme_vlr_t *vlr);
|
||||
void mme_vlr_remove_all(void);
|
||||
void mme_vlr_close(mme_vlr_t *vlr);
|
||||
|
@@ -39,7 +39,8 @@ ogs_sock_t *sgsap_client(mme_vlr_t *vlr)
|
||||
|
||||
ogs_assert(vlr);
|
||||
|
||||
sock = ogs_sctp_client(SOCK_SEQPACKET, vlr->sa_list, vlr->option);
|
||||
sock = ogs_sctp_client(SOCK_SEQPACKET,
|
||||
vlr->sa_list, vlr->local_sa_list, vlr->option);
|
||||
if (sock) {
|
||||
vlr->sock = sock;
|
||||
#if HAVE_USRSCTP
|
||||
@@ -47,7 +48,23 @@ ogs_sock_t *sgsap_client(mme_vlr_t *vlr)
|
||||
usrsctp_set_non_blocking((struct socket *)sock, 1);
|
||||
usrsctp_set_upcall((struct socket *)sock, usrsctp_recv_handler, NULL);
|
||||
#else
|
||||
vlr->addr = &sock->remote_addr;
|
||||
|
||||
/*
|
||||
* Originally, the code assigned vlr->addr to the address of sock->remote_addr:
|
||||
* vlr->addr = &sock->remote_addr;
|
||||
* However, when using sctp_connectx, it was not easy to set remote_addr.
|
||||
* Therefore, at this point, vlr->addr is now assigned to vlr->sa_list,
|
||||
* utilizing the initially used address:
|
||||
* vlr->addr = vlr->sa_list;
|
||||
*
|
||||
* This approach may lead to issues when connecting to multiple addresses,
|
||||
* as subsequent addresses cannot be accurately compared using the 'from'
|
||||
* parameter in sctp_recvmsg.
|
||||
*
|
||||
* Since a proper solution is deferred, it is recommended to avoid using
|
||||
* sctp_connectx with multiple addresses for the time being.
|
||||
*/
|
||||
vlr->addr = vlr->sa_list;
|
||||
vlr->poll = ogs_pollset_add(ogs_app()->pollset,
|
||||
OGS_POLLIN, sock->fd, lksctp_recv_handler, sock);
|
||||
ogs_assert(vlr->poll);
|
||||
|
@@ -54,7 +54,7 @@ ogs_socknode_t *testsctp_client(const char *ipstr, int port)
|
||||
node = ogs_socknode_new(addr);
|
||||
ogs_assert(node);
|
||||
|
||||
sock = ogs_sctp_client(SOCK_STREAM, node->addr, NULL);
|
||||
sock = ogs_sctp_client(SOCK_STREAM, node->addr, NULL, NULL);
|
||||
ogs_assert(sock);
|
||||
|
||||
node->sock = sock;
|
||||
@@ -82,7 +82,7 @@ ogs_socknode_t *tests1ap_client(int family)
|
||||
node = ogs_socknode_new(addr);
|
||||
ogs_assert(node);
|
||||
|
||||
sock = ogs_sctp_client(SOCK_STREAM, node->addr, NULL);
|
||||
sock = ogs_sctp_client(SOCK_STREAM, node->addr, NULL, NULL);
|
||||
ogs_assert(sock);
|
||||
|
||||
node->sock = sock;
|
||||
@@ -121,7 +121,7 @@ ogs_socknode_t *testngap_client(int index, int family)
|
||||
node = ogs_socknode_new(addr);
|
||||
ogs_assert(node);
|
||||
|
||||
sock = ogs_sctp_client(SOCK_STREAM, node->addr, NULL);
|
||||
sock = ogs_sctp_client(SOCK_STREAM, node->addr, NULL, NULL);
|
||||
ogs_assert(sock);
|
||||
|
||||
node->sock = sock;
|
||||
|
@@ -53,7 +53,7 @@ static void test1_func(abts_case *tc, void *data)
|
||||
rv = ogs_freeaddrinfo(addr);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, NULL, TEST1_PORT2, AI_PASSIVE);
|
||||
rv = ogs_getaddrinfo(&addr, AF_INET6, NULL, TEST1_PORT2, AI_PASSIVE);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
sctp = ogs_sctp_server(SOCK_SEQPACKET, addr, NULL);
|
||||
ABTS_PTR_NOTNULL(tc, sctp);
|
||||
@@ -77,7 +77,7 @@ static void test2_main(void *data)
|
||||
|
||||
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, NULL, TEST2_PORT, 0);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
sctp = ogs_sctp_client(SOCK_SEQPACKET, addr, NULL);
|
||||
sctp = ogs_sctp_client(SOCK_SEQPACKET, addr, NULL, NULL);
|
||||
ABTS_PTR_NOTNULL(tc, sctp);
|
||||
|
||||
size = ogs_sctp_recvdata(sctp, str, STRLEN, &from, &sinfo);
|
||||
@@ -192,7 +192,7 @@ static void test4_main(void *data)
|
||||
|
||||
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, NULL, TEST4_PORT, 0);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
sctp = ogs_sctp_client(SOCK_STREAM, addr, NULL);
|
||||
sctp = ogs_sctp_client(SOCK_STREAM, addr, NULL, NULL);
|
||||
ABTS_PTR_NOTNULL(tc, sctp);
|
||||
|
||||
size = ogs_sctp_sendmsg(sctp, DATASTR, strlen(DATASTR), NULL, PPID, 0);
|
||||
|
Reference in New Issue
Block a user