diff --git a/configs/csfb.yaml.in b/configs/csfb.yaml.in index 9538a580e..53f19af8d 100644 --- a/configs/csfb.yaml.in +++ b/configs/csfb.yaml.in @@ -59,7 +59,7 @@ mme: smf: - address: 127.0.0.4 sgsap: - server: + client: - address: 127.0.0.2 map: tai: diff --git a/configs/open5gs/mme.yaml.in b/configs/open5gs/mme.yaml.in index b3daf838d..39b2a0071 100644 --- a/configs/open5gs/mme.yaml.in +++ b/configs/open5gs/mme.yaml.in @@ -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: diff --git a/lib/sctp/ogs-lksctp.c b/lib/sctp/ogs-lksctp.c index 89a6b985c..f9a0a27ec 100644 --- a/lib/sctp/ogs-lksctp.c +++ b/lib/sctp/ogs-lksctp.c @@ -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) diff --git a/lib/sctp/ogs-sctp.h b/lib/sctp/ogs-sctp.h index 3384a98df..f698bf6af 100644 --- a/lib/sctp/ogs-sctp.h +++ b/lib/sctp/ogs-sctp.h @@ -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); diff --git a/lib/sctp/ogs-usrsctp.c b/lib/sctp/ogs-usrsctp.c index 60675ca93..066fecafa 100644 --- a/lib/sctp/ogs-usrsctp.c +++ b/lib/sctp/ogs-usrsctp.c @@ -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]; diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index b27c9977e..547a1419e 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -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); diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index c58e94587..957140d89 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -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); diff --git a/src/mme/sgsap-sctp.c b/src/mme/sgsap-sctp.c index d14c9287e..99704022c 100644 --- a/src/mme/sgsap-sctp.c +++ b/src/mme/sgsap-sctp.c @@ -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); diff --git a/tests/common/sctp.c b/tests/common/sctp.c index a08bcca7c..575d8ca08 100644 --- a/tests/common/sctp.c +++ b/tests/common/sctp.c @@ -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; diff --git a/tests/sctp/sctp-test.c b/tests/sctp/sctp-test.c index 288e06b44..436185293 100644 --- a/tests/sctp/sctp-test.c +++ b/tests/sctp/sctp-test.c @@ -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);