/src/open5gs/lib/sbi/context.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com> |
3 | | * |
4 | | * This file is part of Open5GS. |
5 | | * |
6 | | * This program is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Affero General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "ogs-sbi.h" |
21 | | |
22 | | int __ogs_sbi_domain; |
23 | | static ogs_sbi_context_t self; |
24 | | static int context_initialized = 0; |
25 | | |
26 | | static OGS_POOL(nf_instance_pool, ogs_sbi_nf_instance_t); |
27 | | static OGS_POOL(nf_service_pool, ogs_sbi_nf_service_t); |
28 | | static OGS_POOL(xact_pool, ogs_sbi_xact_t); |
29 | | static OGS_POOL(subscription_spec_pool, ogs_sbi_subscription_spec_t); |
30 | | static OGS_POOL(subscription_data_pool, ogs_sbi_subscription_data_t); |
31 | | static OGS_POOL(nf_info_pool, ogs_sbi_nf_info_t); |
32 | | |
33 | | void ogs_sbi_context_init(OpenAPI_nf_type_e nf_type) |
34 | 0 | { |
35 | 0 | char nf_instance_id[OGS_UUID_FORMATTED_LENGTH + 1]; |
36 | |
|
37 | 0 | ogs_assert(nf_type); |
38 | | |
39 | 0 | ogs_assert(context_initialized == 0); |
40 | | |
41 | | /* Initialize SBI context */ |
42 | 0 | memset(&self, 0, sizeof(ogs_sbi_context_t)); |
43 | |
|
44 | 0 | ogs_log_install_domain(&__ogs_sbi_domain, "sbi", ogs_core()->log.level); |
45 | |
|
46 | 0 | ogs_sbi_message_init(ogs_app()->pool.message, ogs_app()->pool.message); |
47 | 0 | ogs_sbi_server_init(ogs_app()->pool.event, ogs_app()->pool.event); |
48 | 0 | ogs_sbi_client_init(ogs_app()->pool.event, ogs_app()->pool.event); |
49 | |
|
50 | 0 | ogs_list_init(&self.nf_instance_list); |
51 | 0 | ogs_pool_init(&nf_instance_pool, ogs_app()->pool.nf); |
52 | 0 | ogs_pool_init(&nf_service_pool, ogs_app()->pool.nf_service); |
53 | | |
54 | 0 | ogs_pool_init(&xact_pool, ogs_app()->pool.xact); |
55 | | |
56 | 0 | ogs_list_init(&self.subscription_spec_list); |
57 | 0 | ogs_pool_init(&subscription_spec_pool, ogs_app()->pool.subscription); |
58 | | |
59 | 0 | ogs_list_init(&self.subscription_data_list); |
60 | 0 | ogs_pool_init(&subscription_data_pool, ogs_app()->pool.subscription); |
61 | | |
62 | 0 | ogs_pool_init(&nf_info_pool, ogs_app()->pool.nf * OGS_MAX_NUM_OF_NF_INFO); |
63 | | |
64 | | /* Add SELF NF-Instance */ |
65 | 0 | self.nf_instance = ogs_sbi_nf_instance_add(); |
66 | 0 | ogs_assert(self.nf_instance); |
67 | | |
68 | 0 | ogs_uuid_get(&self.uuid); |
69 | 0 | ogs_uuid_format(nf_instance_id, &self.uuid); |
70 | 0 | ogs_sbi_nf_instance_set_id(self.nf_instance, nf_instance_id); |
71 | 0 | ogs_sbi_nf_instance_set_type(self.nf_instance, nf_type); |
72 | | |
73 | | /* Add NRF NF-Instance */ |
74 | 0 | if (nf_type != OpenAPI_nf_type_NRF) { |
75 | 0 | self.nrf_instance = ogs_sbi_nf_instance_add(); |
76 | 0 | ogs_assert(self.nrf_instance); |
77 | 0 | ogs_sbi_nf_instance_set_type(self.nrf_instance, OpenAPI_nf_type_NRF); |
78 | 0 | } |
79 | | |
80 | | /* Add SCP NF-Instance */ |
81 | 0 | if (nf_type != OpenAPI_nf_type_NRF) { |
82 | 0 | self.scp_instance = ogs_sbi_nf_instance_add(); |
83 | 0 | ogs_assert(self.scp_instance); |
84 | 0 | ogs_sbi_nf_instance_set_type(self.scp_instance, OpenAPI_nf_type_SCP); |
85 | 0 | } |
86 | | |
87 | 0 | context_initialized = 1; |
88 | 0 | } |
89 | | |
90 | | void ogs_sbi_context_final(void) |
91 | 0 | { |
92 | 0 | ogs_assert(context_initialized == 1); |
93 | | |
94 | 0 | ogs_sbi_subscription_data_remove_all(); |
95 | 0 | ogs_pool_final(&subscription_data_pool); |
96 | | |
97 | 0 | ogs_sbi_subscription_spec_remove_all(); |
98 | 0 | ogs_pool_final(&subscription_spec_pool); |
99 | | |
100 | 0 | ogs_pool_final(&xact_pool); |
101 | | |
102 | 0 | ogs_sbi_nf_instance_remove_all(); |
103 | |
|
104 | 0 | ogs_pool_final(&nf_instance_pool); |
105 | 0 | ogs_pool_final(&nf_service_pool); |
106 | 0 | ogs_pool_final(&nf_info_pool); |
107 | | |
108 | 0 | ogs_sbi_client_final(); |
109 | 0 | ogs_sbi_server_final(); |
110 | 0 | ogs_sbi_message_final(); |
111 | |
|
112 | 0 | context_initialized = 0; |
113 | 0 | } |
114 | | |
115 | | ogs_sbi_context_t *ogs_sbi_self(void) |
116 | 0 | { |
117 | 0 | return &self; |
118 | 0 | } |
119 | | |
120 | | static int ogs_sbi_context_prepare(void) |
121 | 0 | { |
122 | | #if ENABLE_ACCEPT_ENCODING |
123 | | self.content_encoding = "gzip"; |
124 | | #endif |
125 | |
|
126 | 0 | self.tls.server.scheme = OpenAPI_uri_scheme_http; |
127 | 0 | self.tls.client.scheme = OpenAPI_uri_scheme_http; |
128 | | |
129 | | /* Initialize delegated config with defaults */ |
130 | 0 | self.client_delegated_config.nrf.nfm = OGS_SBI_CLIENT_DELEGATED_AUTO; |
131 | 0 | self.client_delegated_config.nrf.disc = OGS_SBI_CLIENT_DELEGATED_AUTO; |
132 | 0 | self.client_delegated_config.scp.next = OGS_SBI_CLIENT_DELEGATED_AUTO; |
133 | |
|
134 | 0 | return OGS_OK; |
135 | 0 | } |
136 | | |
137 | | static int ogs_sbi_context_validation( |
138 | | const char *local, const char *nrf, const char *scp) |
139 | 0 | { |
140 | 0 | #define MAX_MODE 3 |
141 | 0 | int i; |
142 | 0 | ogs_sbi_client_delegated_mode_e mode[MAX_MODE]; |
143 | |
|
144 | 0 | ogs_assert(context_initialized == 1); |
145 | | |
146 | | /* If SMF is only used in 4G EPC, or the EIR only serves S13, |
147 | | * no SBI interface is required. */ |
148 | 0 | if (local && strcmp(local, "smf") != 0 && strcmp(local, "eir") != 0 && |
149 | 0 | ogs_sbi_server_first() == NULL) { |
150 | 0 | ogs_error("No %s.sbi.address: in '%s'", local, ogs_app()->file); |
151 | 0 | return OGS_ERROR; |
152 | 0 | } |
153 | | |
154 | 0 | mode[0] = self.client_delegated_config.nrf.nfm; |
155 | 0 | mode[1] = self.client_delegated_config.nrf.disc; |
156 | 0 | mode[2] = self.client_delegated_config.scp.next; |
157 | |
|
158 | 0 | for (i = 0; i < MAX_MODE; i++) { |
159 | 0 | switch (mode[i]) { |
160 | 0 | case OGS_SBI_CLIENT_DELEGATED_AUTO: |
161 | 0 | if (local && strcmp(local, "nrf") == 0) { |
162 | | /* Skip NRF */ |
163 | 0 | } else if (local && strcmp(local, "scp") == 0) { |
164 | | /* Skip SCP */ |
165 | 0 | } else if (local && strcmp(local, "smf") == 0) { |
166 | | /* Skip SMF since SMF can run 4G */ |
167 | 0 | } else if (local && strcmp(local, "eir") == 0 && |
168 | 0 | ogs_sbi_server_first() == NULL) { |
169 | | /* Skip EIR when it only serves S13 */ |
170 | 0 | } else { |
171 | 0 | if (NF_INSTANCE_CLIENT(self.nrf_instance) || |
172 | 0 | NF_INSTANCE_CLIENT(self.scp_instance)) { |
173 | 0 | } else { |
174 | 0 | ogs_error("[%d] DELEGATED_AUTO - " |
175 | 0 | "Both NRF and %s are unavailable", |
176 | 0 | i, scp && strcmp(scp, "next_scp") == 0 ? |
177 | 0 | "Next-hop SCP" : "SCP"); |
178 | 0 | return OGS_ERROR; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | break; |
182 | 0 | case OGS_SBI_CLIENT_DELEGATED_YES: |
183 | 0 | if (NF_INSTANCE_CLIENT(self.scp_instance) == NULL) { |
184 | 0 | ogs_error("[%d] DELEGATED_YES - no %s available", |
185 | 0 | i, scp && strcmp(scp, "next_scp") == 0 ? |
186 | 0 | "Next-hop SCP" : "SCP"); |
187 | 0 | return OGS_ERROR; |
188 | 0 | } |
189 | 0 | break; |
190 | 0 | case OGS_SBI_CLIENT_DELEGATED_NO: |
191 | 0 | if (NF_INSTANCE_CLIENT(self.nrf_instance) == NULL) { |
192 | 0 | ogs_error("[%d] DELEGATED_NO - no NRF available", i); |
193 | 0 | return OGS_ERROR; |
194 | 0 | } |
195 | 0 | break; |
196 | 0 | default: |
197 | 0 | ogs_fatal("[%d] Invalid dicovery-config delegated [%d]", |
198 | 0 | i, mode[i]); |
199 | 0 | ogs_assert_if_reached(); |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | 0 | if (ogs_sbi_self()->tls.server.scheme == OpenAPI_uri_scheme_https) { |
204 | 0 | if (!ogs_sbi_self()->tls.server.private_key) { |
205 | 0 | ogs_error("HTTPS scheme enabled but no server key"); |
206 | 0 | return OGS_ERROR; |
207 | 0 | } |
208 | 0 | if (!ogs_sbi_self()->tls.server.cert) { |
209 | 0 | ogs_error("HTTPS scheme enabled but no server certificate"); |
210 | 0 | return OGS_ERROR; |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | 0 | if (ogs_sbi_self()->tls.server.verify_client) { |
215 | 0 | if (!ogs_sbi_self()->tls.server.verify_client_cacert) { |
216 | 0 | ogs_error("CLIENT verification enabled but no CA certificate"); |
217 | 0 | return OGS_ERROR; |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | 0 | return OGS_OK; |
222 | 0 | } |
223 | | |
224 | | int ogs_sbi_context_parse_config( |
225 | | const char *local, const char *nrf, const char *scp) |
226 | 0 | { |
227 | 0 | int rv; |
228 | 0 | yaml_document_t *document = NULL; |
229 | 0 | ogs_yaml_iter_t root_iter; |
230 | 0 | int idx = 0; |
231 | |
|
232 | 0 | document = ogs_app()->document; |
233 | 0 | ogs_assert(document); |
234 | | |
235 | 0 | rv = ogs_sbi_context_prepare(); |
236 | 0 | if (rv != OGS_OK) return rv; |
237 | | |
238 | 0 | ogs_yaml_iter_init(&root_iter, document); |
239 | 0 | while (ogs_yaml_iter_next(&root_iter)) { |
240 | 0 | const char *root_key = ogs_yaml_iter_key(&root_iter); |
241 | 0 | ogs_assert(root_key); |
242 | 0 | if (local && !strcmp(root_key, local) && |
243 | 0 | idx++ == ogs_app()->config_section_id) { |
244 | 0 | ogs_yaml_iter_t local_iter; |
245 | 0 | ogs_yaml_iter_recurse(&root_iter, &local_iter); |
246 | 0 | while (ogs_yaml_iter_next(&local_iter)) { |
247 | 0 | const char *local_key = ogs_yaml_iter_key(&local_iter); |
248 | 0 | ogs_assert(local_key); |
249 | 0 | if (!strcmp(local_key, "default")) { |
250 | 0 | ogs_yaml_iter_t default_iter; |
251 | 0 | ogs_yaml_iter_recurse(&local_iter, &default_iter); |
252 | 0 | while (ogs_yaml_iter_next(&default_iter)) { |
253 | 0 | const char *default_key = |
254 | 0 | ogs_yaml_iter_key(&default_iter); |
255 | 0 | ogs_assert(default_key); |
256 | 0 | if (!strcmp(default_key, "interface")) { |
257 | 0 | self.local_if = ogs_yaml_iter_value(&default_iter); |
258 | 0 | } else if (!strcmp(default_key, "tls")) { |
259 | 0 | ogs_yaml_iter_t tls_iter; |
260 | 0 | ogs_yaml_iter_recurse(&default_iter, &tls_iter); |
261 | 0 | while (ogs_yaml_iter_next(&tls_iter)) { |
262 | 0 | const char *tls_key = |
263 | 0 | ogs_yaml_iter_key(&tls_iter); |
264 | 0 | ogs_assert(tls_key); |
265 | 0 | if (!strcmp(tls_key, "server")) { |
266 | 0 | ogs_yaml_iter_t server_iter; |
267 | 0 | ogs_yaml_iter_recurse( |
268 | 0 | &tls_iter, &server_iter); |
269 | 0 | while (ogs_yaml_iter_next(&server_iter)) { |
270 | 0 | const char *server_key = |
271 | 0 | ogs_yaml_iter_key(&server_iter); |
272 | 0 | ogs_assert(server_key); |
273 | 0 | if (!strcmp(server_key, "scheme")) { |
274 | 0 | const char *v = ogs_yaml_iter_value( |
275 | 0 | &server_iter); |
276 | 0 | if (v) { |
277 | 0 | if (!ogs_strcasecmp( |
278 | 0 | v, "https")) |
279 | 0 | self.tls.server.scheme = |
280 | 0 | OpenAPI_uri_scheme_https; |
281 | 0 | else if (!ogs_strcasecmp( |
282 | 0 | v, "http")) |
283 | 0 | self.tls.server.scheme = |
284 | 0 | OpenAPI_uri_scheme_http; |
285 | 0 | else |
286 | 0 | ogs_warn( |
287 | 0 | "unknown scheme `%s`", |
288 | 0 | v); |
289 | 0 | } |
290 | 0 | } else if (!strcmp(server_key, |
291 | 0 | "private_key")) { |
292 | 0 | self.tls.server.private_key = |
293 | 0 | ogs_yaml_iter_value( |
294 | 0 | &server_iter); |
295 | 0 | } else if (!strcmp(server_key, |
296 | 0 | "cert")) { |
297 | 0 | self.tls.server.cert = |
298 | 0 | ogs_yaml_iter_value( |
299 | 0 | &server_iter); |
300 | 0 | } else if (!strcmp(server_key, |
301 | 0 | "sslkeylogfile")) { |
302 | 0 | self.tls.server.sslkeylog = |
303 | 0 | ogs_yaml_iter_value( |
304 | 0 | &server_iter); |
305 | 0 | } else if (!strcmp(server_key, |
306 | 0 | "verify_client")) { |
307 | 0 | self.tls.server.verify_client = |
308 | 0 | ogs_yaml_iter_bool( |
309 | 0 | &server_iter); |
310 | 0 | } else if (!strcmp(server_key, |
311 | 0 | "verify_client_cacert")) { |
312 | 0 | self.tls.server. |
313 | 0 | verify_client_cacert = |
314 | 0 | ogs_yaml_iter_value( |
315 | 0 | &server_iter); |
316 | 0 | } |
317 | 0 | } |
318 | 0 | } else if (!strcmp(tls_key, "client")) { |
319 | 0 | ogs_yaml_iter_t client_iter; |
320 | 0 | ogs_yaml_iter_recurse( |
321 | 0 | &tls_iter, &client_iter); |
322 | 0 | while (ogs_yaml_iter_next(&client_iter)) { |
323 | 0 | const char *client_key = |
324 | 0 | ogs_yaml_iter_key(&client_iter); |
325 | 0 | ogs_assert(client_key); |
326 | 0 | if (!strcmp(client_key, "scheme")) { |
327 | 0 | const char *v = ogs_yaml_iter_value( |
328 | 0 | &client_iter); |
329 | 0 | if (v) { |
330 | 0 | if (!ogs_strcasecmp( |
331 | 0 | v, "https")) |
332 | 0 | self.tls.client.scheme = |
333 | 0 | OpenAPI_uri_scheme_https; |
334 | 0 | else if (!ogs_strcasecmp( |
335 | 0 | v, "http")) |
336 | 0 | self.tls.client.scheme = |
337 | 0 | OpenAPI_uri_scheme_http; |
338 | 0 | else |
339 | 0 | ogs_warn( |
340 | 0 | "unknown scheme `%s`", |
341 | 0 | v); |
342 | 0 | } |
343 | 0 | } else if (!strcmp(client_key, |
344 | 0 | "insecure_skip_verify")) { |
345 | 0 | self.tls.client. |
346 | 0 | insecure_skip_verify = |
347 | 0 | ogs_yaml_iter_bool( |
348 | 0 | &client_iter); |
349 | 0 | } else if (!strcmp(client_key, |
350 | 0 | "cacert")) { |
351 | 0 | self.tls.client.cacert = |
352 | 0 | ogs_yaml_iter_value( |
353 | 0 | &client_iter); |
354 | 0 | } else if (!strcmp(client_key, |
355 | 0 | "client_private_key")) { |
356 | 0 | self.tls.client.private_key = |
357 | 0 | ogs_yaml_iter_value( |
358 | 0 | &client_iter); |
359 | 0 | } else if (!strcmp(client_key, |
360 | 0 | "client_cert")) { |
361 | 0 | self.tls.client.cert = |
362 | 0 | ogs_yaml_iter_value( |
363 | 0 | &client_iter); |
364 | 0 | } else if (!strcmp(client_key, |
365 | 0 | "client_sslkeylogfile")) { |
366 | 0 | self.tls.client.sslkeylog = |
367 | 0 | ogs_yaml_iter_value( |
368 | 0 | &client_iter); |
369 | 0 | } |
370 | 0 | } |
371 | 0 | } |
372 | 0 | } |
373 | 0 | } |
374 | 0 | } |
375 | 0 | } |
376 | 0 | } |
377 | 0 | } |
378 | 0 | } |
379 | | |
380 | 0 | idx = 0; |
381 | 0 | ogs_yaml_iter_init(&root_iter, document); |
382 | 0 | while (ogs_yaml_iter_next(&root_iter)) { |
383 | 0 | const char *root_key = ogs_yaml_iter_key(&root_iter); |
384 | 0 | ogs_assert(root_key); |
385 | 0 | if (local && !strcmp(root_key, local) && |
386 | 0 | idx++ == ogs_app()->config_section_id) { |
387 | 0 | ogs_yaml_iter_t local_iter; |
388 | 0 | ogs_yaml_iter_recurse(&root_iter, &local_iter); |
389 | 0 | while (ogs_yaml_iter_next(&local_iter)) { |
390 | 0 | const char *local_key = ogs_yaml_iter_key(&local_iter); |
391 | 0 | ogs_assert(local_key); |
392 | 0 | if (!strcmp(local_key, "sbi")) { |
393 | 0 | ogs_yaml_iter_t sbi_iter; |
394 | 0 | ogs_yaml_iter_recurse(&local_iter, &sbi_iter); |
395 | 0 | while (ogs_yaml_iter_next(&sbi_iter)) { |
396 | 0 | const char *sbi_key = ogs_yaml_iter_key(&sbi_iter); |
397 | 0 | ogs_assert(sbi_key); |
398 | 0 | if (!strcmp(sbi_key, "server")) { |
399 | 0 | rv = ogs_sbi_context_parse_server_config( |
400 | 0 | &sbi_iter, NULL); |
401 | 0 | if (rv != OGS_OK) { |
402 | 0 | ogs_error("ogs_sbi_context_parse_server_" |
403 | 0 | "config() failed"); |
404 | 0 | return rv; |
405 | 0 | } |
406 | 0 | } else if (!strcmp(sbi_key, "client")) { |
407 | 0 | ogs_yaml_iter_t client_iter; |
408 | 0 | ogs_yaml_iter_recurse(&sbi_iter, &client_iter); |
409 | 0 | while (ogs_yaml_iter_next(&client_iter)) { |
410 | 0 | const char *client_key = |
411 | 0 | ogs_yaml_iter_key(&client_iter); |
412 | 0 | ogs_assert(client_key); |
413 | 0 | if (ogs_global_conf()-> |
414 | 0 | parameter.no_nrf == false && |
415 | 0 | nrf && !strcmp(client_key, nrf)) { |
416 | 0 | ogs_yaml_iter_t nrf_array, nrf_iter; |
417 | 0 | ogs_yaml_iter_recurse(&client_iter, |
418 | 0 | &nrf_array); |
419 | 0 | do { |
420 | 0 | ogs_sbi_client_t *client = NULL; |
421 | |
|
422 | 0 | if (ogs_yaml_iter_type(&nrf_array) == |
423 | 0 | YAML_MAPPING_NODE) { |
424 | 0 | memcpy(&nrf_iter, &nrf_array, |
425 | 0 | sizeof(ogs_yaml_iter_t)); |
426 | 0 | } else if (ogs_yaml_iter_type( |
427 | 0 | &nrf_array) == |
428 | 0 | YAML_SEQUENCE_NODE) { |
429 | 0 | if (!ogs_yaml_iter_next(&nrf_array)) |
430 | 0 | break; |
431 | 0 | ogs_yaml_iter_recurse( |
432 | 0 | &nrf_array, &nrf_iter); |
433 | 0 | } else if (ogs_yaml_iter_type( |
434 | 0 | &nrf_array) == |
435 | 0 | YAML_SCALAR_NODE) { |
436 | 0 | break; |
437 | 0 | } else |
438 | 0 | ogs_assert_if_reached(); |
439 | | |
440 | 0 | if (NF_INSTANCE_CLIENT( |
441 | 0 | self.nrf_instance)) { |
442 | 0 | ogs_error("Only one NRF client " |
443 | 0 | "can be set"); |
444 | 0 | return OGS_ERROR; |
445 | 0 | } |
446 | | |
447 | 0 | client = |
448 | 0 | ogs_sbi_context_parse_client_config( |
449 | 0 | &nrf_iter); |
450 | 0 | if (!client) { |
451 | 0 | ogs_error("ogs_sbi_context_parse_" |
452 | 0 | "client_config() failed"); |
453 | 0 | return OGS_ERROR; |
454 | 0 | } |
455 | | |
456 | 0 | OGS_SBI_SETUP_CLIENT( |
457 | 0 | self.nrf_instance, client); |
458 | |
|
459 | 0 | } while (ogs_yaml_iter_type(&nrf_array) == |
460 | 0 | YAML_SEQUENCE_NODE); |
461 | 0 | } else if (ogs_global_conf()-> |
462 | 0 | parameter.no_scp == false && |
463 | 0 | scp && !strcmp(client_key, scp)) { |
464 | 0 | ogs_yaml_iter_t scp_array, scp_iter; |
465 | 0 | ogs_yaml_iter_recurse( |
466 | 0 | &client_iter, &scp_array); |
467 | 0 | do { |
468 | 0 | ogs_sbi_client_t *client = NULL; |
469 | |
|
470 | 0 | if (ogs_yaml_iter_type(&scp_array) == |
471 | 0 | YAML_MAPPING_NODE) { |
472 | 0 | memcpy(&scp_iter, &scp_array, |
473 | 0 | sizeof(ogs_yaml_iter_t)); |
474 | 0 | } else if (ogs_yaml_iter_type( |
475 | 0 | &scp_array) == |
476 | 0 | YAML_SEQUENCE_NODE) { |
477 | 0 | if (!ogs_yaml_iter_next(&scp_array)) |
478 | 0 | break; |
479 | 0 | ogs_yaml_iter_recurse( |
480 | 0 | &scp_array, &scp_iter); |
481 | 0 | } else if (ogs_yaml_iter_type( |
482 | 0 | &scp_array) == |
483 | 0 | YAML_SCALAR_NODE) { |
484 | 0 | break; |
485 | 0 | } else |
486 | 0 | ogs_assert_if_reached(); |
487 | | |
488 | 0 | if (NF_INSTANCE_CLIENT( |
489 | 0 | self.scp_instance)) { |
490 | 0 | ogs_error("Only one SCP client " |
491 | 0 | "can be set"); |
492 | 0 | return OGS_ERROR; |
493 | 0 | } |
494 | | |
495 | 0 | client = |
496 | 0 | ogs_sbi_context_parse_client_config( |
497 | 0 | &scp_iter); |
498 | 0 | if (!client) { |
499 | 0 | ogs_error("ogs_sbi_context_parse_" |
500 | 0 | "client_config() failed"); |
501 | 0 | return OGS_ERROR; |
502 | 0 | } |
503 | | |
504 | 0 | OGS_SBI_SETUP_CLIENT( |
505 | 0 | self.scp_instance, client); |
506 | |
|
507 | 0 | } while (ogs_yaml_iter_type(&scp_array) == |
508 | 0 | YAML_SEQUENCE_NODE); |
509 | 0 | } |
510 | | /* Parse delegated section */ |
511 | 0 | else if (!strcmp(client_key, "delegated")) { |
512 | 0 | ogs_yaml_iter_t delegated_iter; |
513 | 0 | ogs_yaml_iter_recurse(&client_iter, |
514 | 0 | &delegated_iter); |
515 | |
|
516 | 0 | while (ogs_yaml_iter_next( |
517 | 0 | &delegated_iter)) { |
518 | 0 | const char *del_key = |
519 | 0 | ogs_yaml_iter_key( |
520 | 0 | &delegated_iter); |
521 | 0 | if (!strcmp(del_key, "nrf")) { |
522 | 0 | ogs_yaml_iter_t nrf_iter; |
523 | 0 | ogs_yaml_iter_recurse( |
524 | 0 | &delegated_iter, &nrf_iter); |
525 | 0 | while (ogs_yaml_iter_next( |
526 | 0 | &nrf_iter)) { |
527 | 0 | const char *nrf_key = |
528 | 0 | ogs_yaml_iter_key( |
529 | 0 | &nrf_iter); |
530 | 0 | const char *nrf_val = |
531 | 0 | ogs_yaml_iter_value( |
532 | 0 | &nrf_iter); |
533 | 0 | ogs_assert(nrf_key); |
534 | | |
535 | 0 | if (!strcmp(nrf_key,"nfm")) { |
536 | 0 | if (!strcmp(nrf_val,"no")) { |
537 | 0 | self.client_delegated_config.nrf.nfm = |
538 | 0 | OGS_SBI_CLIENT_DELEGATED_NO; |
539 | 0 | } else if (!strcmp( |
540 | 0 | nrf_val,"yes")) { |
541 | 0 | self.client_delegated_config.nrf.nfm = |
542 | 0 | OGS_SBI_CLIENT_DELEGATED_YES; |
543 | 0 | } else if (!strcmp( |
544 | 0 | nrf_val,"auto")) { |
545 | 0 | self.client_delegated_config.nrf.nfm = |
546 | 0 | OGS_SBI_CLIENT_DELEGATED_AUTO; |
547 | 0 | } else { |
548 | 0 | ogs_warn("unknown " |
549 | 0 | "'nfm' `%s`", |
550 | 0 | nrf_val); |
551 | 0 | } |
552 | 0 | } else if (!strcmp( |
553 | 0 | nrf_key,"disc")) { |
554 | 0 | if (!strcmp(nrf_val,"no")) { |
555 | 0 | self.client_delegated_config.nrf.disc = |
556 | 0 | OGS_SBI_CLIENT_DELEGATED_NO; |
557 | 0 | } else if (!strcmp( |
558 | 0 | nrf_val,"yes")) { |
559 | 0 | self.client_delegated_config.nrf.disc = |
560 | 0 | OGS_SBI_CLIENT_DELEGATED_YES; |
561 | 0 | } else if (!strcmp( |
562 | 0 | nrf_val,"auto")) { |
563 | 0 | self.client_delegated_config.nrf.disc = |
564 | 0 | OGS_SBI_CLIENT_DELEGATED_AUTO; |
565 | 0 | } else { |
566 | 0 | ogs_warn("unknown " |
567 | 0 | "'disc' `%s`", |
568 | 0 | nrf_val); |
569 | 0 | } |
570 | 0 | } else { |
571 | 0 | ogs_warn("unknown nrf " |
572 | 0 | "delegated key `%s`", |
573 | 0 | nrf_key); |
574 | 0 | } |
575 | 0 | } |
576 | 0 | } else if (!strcmp(del_key, "scp")) { |
577 | 0 | ogs_yaml_iter_t scp_iter; |
578 | 0 | ogs_yaml_iter_recurse( |
579 | 0 | &delegated_iter, &scp_iter); |
580 | 0 | while (ogs_yaml_iter_next( |
581 | 0 | &scp_iter)) { |
582 | 0 | const char *scp_key = |
583 | 0 | ogs_yaml_iter_key( |
584 | 0 | &scp_iter); |
585 | 0 | const char *scp_val = |
586 | 0 | ogs_yaml_iter_value( |
587 | 0 | &scp_iter); |
588 | 0 | ogs_assert(scp_key); |
589 | | |
590 | 0 | if (!strcmp(scp_key,"next")) { |
591 | 0 | if (!strcmp(scp_val,"no")) { |
592 | 0 | self.client_delegated_config.scp.next = |
593 | 0 | OGS_SBI_CLIENT_DELEGATED_NO; |
594 | 0 | } else if (!strcmp( |
595 | 0 | scp_val,"yes")) { |
596 | 0 | self.client_delegated_config.scp.next = |
597 | 0 | OGS_SBI_CLIENT_DELEGATED_YES; |
598 | 0 | } else if (!strcmp( |
599 | 0 | scp_val,"auto")) { |
600 | 0 | self.client_delegated_config.scp.next = |
601 | 0 | OGS_SBI_CLIENT_DELEGATED_AUTO; |
602 | 0 | } else { |
603 | 0 | ogs_warn("unknown " |
604 | 0 | "'next' `%s`", |
605 | 0 | scp_val); |
606 | 0 | } |
607 | 0 | } else { |
608 | 0 | ogs_warn("unknown scp " |
609 | 0 | "delegated key `%s`", |
610 | 0 | scp_key); |
611 | 0 | } |
612 | 0 | } |
613 | 0 | } else { |
614 | 0 | ogs_warn("unknown delegated " |
615 | 0 | "key `%s`", del_key); |
616 | 0 | } |
617 | 0 | } |
618 | 0 | } |
619 | 0 | } |
620 | 0 | } else |
621 | 0 | ogs_warn("unknown key `%s`", sbi_key); |
622 | 0 | } |
623 | 0 | } else if (!strcmp(local_key, "service_name")) { |
624 | 0 | ogs_yaml_iter_t service_name_iter; |
625 | 0 | ogs_yaml_iter_recurse(&local_iter, &service_name_iter); |
626 | 0 | ogs_assert(ogs_yaml_iter_type( |
627 | 0 | &service_name_iter) != YAML_MAPPING_NODE); |
628 | | |
629 | 0 | do { |
630 | 0 | const char *v = NULL; |
631 | |
|
632 | 0 | if (ogs_yaml_iter_type(&service_name_iter) == |
633 | 0 | YAML_SEQUENCE_NODE) { |
634 | 0 | if (!ogs_yaml_iter_next(&service_name_iter)) |
635 | 0 | break; |
636 | 0 | } |
637 | | |
638 | 0 | v = ogs_yaml_iter_value(&service_name_iter); |
639 | 0 | if (v && strlen(v)) { |
640 | 0 | OpenAPI_service_name_e name = |
641 | 0 | OpenAPI_service_name_FromString((char *)v); |
642 | 0 | if (name) |
643 | 0 | self.service_name[self.num_of_service_name++] = |
644 | 0 | name; |
645 | 0 | else |
646 | 0 | ogs_warn("unknown service-name `%s`", v); |
647 | 0 | } |
648 | |
|
649 | 0 | } while (ogs_yaml_iter_type( |
650 | 0 | &service_name_iter) == YAML_SEQUENCE_NODE); |
651 | |
|
652 | 0 | } |
653 | 0 | } |
654 | 0 | } |
655 | 0 | } |
656 | | |
657 | 0 | rv = ogs_sbi_context_validation(local, nrf, scp); |
658 | 0 | if (rv != OGS_OK) return rv; |
659 | | |
660 | 0 | return OGS_OK; |
661 | 0 | } |
662 | | |
663 | | int ogs_sbi_context_parse_hnet_config(ogs_yaml_iter_t *root_iter) |
664 | 0 | { |
665 | 0 | int rv; |
666 | 0 | ogs_yaml_iter_t hnet_array, hnet_iter; |
667 | |
|
668 | 0 | ogs_assert(root_iter); |
669 | 0 | ogs_yaml_iter_recurse(root_iter, &hnet_array); |
670 | 0 | do { |
671 | 0 | uint8_t id = 0, scheme = 0; |
672 | 0 | const char *filename = NULL; |
673 | |
|
674 | 0 | if (ogs_yaml_iter_type(&hnet_array) == YAML_MAPPING_NODE) { |
675 | 0 | memcpy(&hnet_iter, &hnet_array, sizeof(ogs_yaml_iter_t)); |
676 | 0 | } else if (ogs_yaml_iter_type(&hnet_array) == YAML_SEQUENCE_NODE) { |
677 | 0 | if (!ogs_yaml_iter_next(&hnet_array)) |
678 | 0 | break; |
679 | 0 | ogs_yaml_iter_recurse(&hnet_array, &hnet_iter); |
680 | 0 | } else if (ogs_yaml_iter_type(&hnet_array) == YAML_SCALAR_NODE) { |
681 | 0 | break; |
682 | 0 | } else |
683 | 0 | ogs_assert_if_reached(); |
684 | | |
685 | 0 | while (ogs_yaml_iter_next(&hnet_iter)) { |
686 | 0 | const char *hnet_key = ogs_yaml_iter_key(&hnet_iter); |
687 | 0 | ogs_assert(hnet_key); |
688 | 0 | if (!strcmp(hnet_key, "id")) { |
689 | 0 | const char *v = ogs_yaml_iter_value(&hnet_iter); |
690 | 0 | if (v) { |
691 | 0 | if (atoi(v) >= 1 && atoi(v) <= 254) |
692 | 0 | id = atoi(v); |
693 | 0 | } |
694 | 0 | } else if (!strcmp(hnet_key, "scheme")) { |
695 | 0 | const char *v = ogs_yaml_iter_value(&hnet_iter); |
696 | 0 | if (v) { |
697 | 0 | if (atoi(v) == 1 || atoi(v) == 2) |
698 | 0 | scheme = atoi(v); |
699 | 0 | } |
700 | 0 | } else if (!strcmp(hnet_key, "key")) { |
701 | 0 | filename = ogs_yaml_iter_value(&hnet_iter); |
702 | 0 | } else |
703 | 0 | ogs_warn("unknown key `%s`", hnet_key); |
704 | 0 | } |
705 | | |
706 | 0 | if (id >= OGS_HOME_NETWORK_PKI_VALUE_MIN && |
707 | 0 | id <= OGS_HOME_NETWORK_PKI_VALUE_MAX && |
708 | 0 | filename) { |
709 | 0 | if (scheme == OGS_PROTECTION_SCHEME_PROFILE_A) { |
710 | 0 | rv = ogs_pem_decode_curve25519_key( |
711 | 0 | filename, self.hnet[id].key); |
712 | 0 | if (rv == OGS_OK) { |
713 | 0 | self.hnet[id].avail = true; |
714 | 0 | self.hnet[id].scheme = scheme; |
715 | 0 | } else { |
716 | 0 | ogs_error("ogs_pem_decode_curve25519_key" |
717 | 0 | "[%s] failed", filename); |
718 | 0 | } |
719 | 0 | } else if (scheme == OGS_PROTECTION_SCHEME_PROFILE_B) { |
720 | 0 | rv = ogs_pem_decode_secp256r1_key( |
721 | 0 | filename, self.hnet[id].key); |
722 | 0 | if (rv == OGS_OK) { |
723 | 0 | self.hnet[id].avail = true; |
724 | 0 | self.hnet[id].scheme = scheme; |
725 | 0 | } else { |
726 | 0 | ogs_error("ogs_pem_decode_secp256r1_key[%s]" |
727 | 0 | " failed", filename); |
728 | 0 | } |
729 | 0 | } else |
730 | 0 | ogs_error("Invalid scheme [%d]", scheme); |
731 | 0 | } else |
732 | 0 | ogs_error("Invalid home network configuration " |
733 | 0 | "[id:%d, filename:%s]", id, filename); |
734 | 0 | } while (ogs_yaml_iter_type(&hnet_array) == YAML_SEQUENCE_NODE); |
735 | | |
736 | 0 | return OGS_OK; |
737 | 0 | } |
738 | | |
739 | | int ogs_sbi_context_parse_server_config( |
740 | | ogs_yaml_iter_t *parent, const char *interface) |
741 | 0 | { |
742 | 0 | int rv; |
743 | 0 | ogs_sbi_server_t *server = NULL; |
744 | 0 | OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; |
745 | 0 | ogs_list_t list, list6; |
746 | 0 | ogs_socknode_t *node = NULL, *node6 = NULL; |
747 | |
|
748 | 0 | ogs_assert(parent); |
749 | | |
750 | 0 | ogs_yaml_iter_t server_iter, server_array; |
751 | 0 | ogs_yaml_iter_recurse(parent, &server_array); |
752 | 0 | do { |
753 | 0 | int i, family = AF_UNSPEC; |
754 | 0 | int num = 0; |
755 | 0 | const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; |
756 | 0 | int num_of_advertise = 0; |
757 | 0 | const char *advertise[OGS_MAX_NUM_OF_HOSTNAME]; |
758 | |
|
759 | 0 | uint16_t port = 0; |
760 | 0 | const char *dev = NULL; |
761 | 0 | ogs_sockaddr_t *addr = NULL; |
762 | |
|
763 | 0 | const char *private_key = NULL, *cert = NULL, *sslkeylog = NULL; |
764 | |
|
765 | 0 | bool verify_client = false; |
766 | 0 | const char *verify_client_cacert = NULL; |
767 | |
|
768 | 0 | ogs_sockopt_t option; |
769 | 0 | bool is_option = false; |
770 | |
|
771 | 0 | if (ogs_yaml_iter_type(&server_array) == YAML_MAPPING_NODE) { |
772 | 0 | memcpy(&server_iter, &server_array, sizeof(ogs_yaml_iter_t)); |
773 | 0 | } else if (ogs_yaml_iter_type(&server_array) == YAML_SEQUENCE_NODE) { |
774 | 0 | if (!ogs_yaml_iter_next(&server_array)) |
775 | 0 | break; |
776 | 0 | ogs_yaml_iter_recurse(&server_array, &server_iter); |
777 | 0 | } else if (ogs_yaml_iter_type(&server_array) == YAML_SCALAR_NODE) { |
778 | 0 | break; |
779 | 0 | } else |
780 | 0 | ogs_assert_if_reached(); |
781 | | |
782 | 0 | while (ogs_yaml_iter_next(&server_iter)) { |
783 | 0 | const char *server_key = ogs_yaml_iter_key(&server_iter); |
784 | 0 | ogs_assert(server_key); |
785 | 0 | if (!strcmp(server_key, OGS_SBI_INTERFACE_NAME_N32F)) { |
786 | 0 | rv = ogs_sbi_context_parse_server_config( |
787 | 0 | &server_iter, server_key); |
788 | 0 | if (rv != OGS_OK) { |
789 | 0 | ogs_error("ogs_sbi_context_parse_server_config() " |
790 | 0 | "failed[key:%s]", server_key); |
791 | 0 | return rv; |
792 | 0 | } |
793 | 0 | } else if (!strcmp(server_key, "family")) { |
794 | 0 | const char *v = ogs_yaml_iter_value(&server_iter); |
795 | 0 | if (v) family = atoi(v); |
796 | 0 | if (family != AF_UNSPEC && family != AF_INET && |
797 | 0 | family != AF_INET6) { |
798 | 0 | ogs_warn("Ignore family(%d) : AF_UNSPEC(%d), " |
799 | 0 | "AF_INET(%d), AF_INET6(%d) ", |
800 | 0 | family, AF_UNSPEC, AF_INET, AF_INET6); |
801 | 0 | family = AF_UNSPEC; |
802 | 0 | } |
803 | 0 | } else if (!strcmp(server_key, "address")) { |
804 | 0 | ogs_yaml_iter_t hostname_iter; |
805 | 0 | ogs_yaml_iter_recurse(&server_iter, &hostname_iter); |
806 | 0 | ogs_assert(ogs_yaml_iter_type( |
807 | 0 | &hostname_iter) != YAML_MAPPING_NODE); |
808 | | |
809 | 0 | do { |
810 | 0 | if (ogs_yaml_iter_type( |
811 | 0 | &hostname_iter) == YAML_SEQUENCE_NODE) { |
812 | 0 | if (!ogs_yaml_iter_next(&hostname_iter)) |
813 | 0 | break; |
814 | 0 | } |
815 | | |
816 | 0 | ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); |
817 | 0 | hostname[num++] = ogs_yaml_iter_value(&hostname_iter); |
818 | 0 | } while (ogs_yaml_iter_type( |
819 | 0 | &hostname_iter) == YAML_SEQUENCE_NODE); |
820 | 0 | } else if (!strcmp(server_key, "advertise")) { |
821 | 0 | ogs_yaml_iter_t advertise_iter; |
822 | 0 | ogs_yaml_iter_recurse(&server_iter, &advertise_iter); |
823 | 0 | ogs_assert(ogs_yaml_iter_type( |
824 | 0 | &advertise_iter) != YAML_MAPPING_NODE); |
825 | | |
826 | 0 | do { |
827 | 0 | if (ogs_yaml_iter_type( |
828 | 0 | &advertise_iter) == YAML_SEQUENCE_NODE) { |
829 | 0 | if (!ogs_yaml_iter_next(&advertise_iter)) |
830 | 0 | break; |
831 | 0 | } |
832 | | |
833 | 0 | ogs_assert(num_of_advertise < OGS_MAX_NUM_OF_HOSTNAME); |
834 | 0 | advertise[num_of_advertise++] = |
835 | 0 | ogs_yaml_iter_value(&advertise_iter); |
836 | 0 | } while (ogs_yaml_iter_type( |
837 | 0 | &advertise_iter) == YAML_SEQUENCE_NODE); |
838 | 0 | } else if (!strcmp(server_key, "port")) { |
839 | 0 | const char *v = ogs_yaml_iter_value(&server_iter); |
840 | 0 | if (v) |
841 | 0 | port = atoi(v); |
842 | 0 | } else if (!strcmp(server_key, "dev")) { |
843 | 0 | dev = ogs_yaml_iter_value(&server_iter); |
844 | 0 | } else if (!strcmp(server_key, "scheme")) { |
845 | 0 | const char *v = ogs_yaml_iter_value(&server_iter); |
846 | 0 | if (v) { |
847 | 0 | if (!ogs_strcasecmp(v, "https")) |
848 | 0 | scheme = OpenAPI_uri_scheme_https; |
849 | 0 | else if (!ogs_strcasecmp(v, "http")) |
850 | 0 | scheme = OpenAPI_uri_scheme_http; |
851 | 0 | else |
852 | 0 | ogs_warn("unknown scheme `%s`", v); |
853 | 0 | } |
854 | 0 | } else if (!strcmp(server_key, "private_key")) { |
855 | 0 | private_key = ogs_yaml_iter_value(&server_iter); |
856 | 0 | } else if (!strcmp(server_key, "cert")) { |
857 | 0 | cert = ogs_yaml_iter_value(&server_iter); |
858 | 0 | } else if (!strcmp(server_key, "sslkeylogfile")) { |
859 | 0 | sslkeylog = ogs_yaml_iter_value(&server_iter); |
860 | 0 | } else if (!strcmp(server_key, "verify_client")) { |
861 | 0 | verify_client = ogs_yaml_iter_bool(&server_iter); |
862 | 0 | } else if (!strcmp(server_key, "verify_client_cacert")) { |
863 | 0 | verify_client_cacert = ogs_yaml_iter_value(&server_iter); |
864 | 0 | } else if (!strcmp(server_key, "option")) { |
865 | 0 | rv = ogs_app_parse_sockopt_config(&server_iter, &option); |
866 | 0 | if (rv != OGS_OK) { |
867 | 0 | ogs_error("ogs_app_parse_sockopt_config() failed"); |
868 | 0 | return rv; |
869 | 0 | } |
870 | 0 | is_option = true; |
871 | 0 | } |
872 | 0 | } |
873 | | |
874 | 0 | if (scheme == OpenAPI_uri_scheme_NULL) |
875 | 0 | scheme = ogs_sbi_self()->tls.server.scheme; |
876 | |
|
877 | 0 | if (!port) { |
878 | 0 | if (scheme == OpenAPI_uri_scheme_https) |
879 | 0 | port = OGS_SBI_HTTPS_PORT; |
880 | 0 | else if (scheme == OpenAPI_uri_scheme_http) |
881 | 0 | port = OGS_SBI_HTTP_PORT; |
882 | 0 | else |
883 | 0 | ogs_assert_if_reached(); |
884 | 0 | } |
885 | | |
886 | 0 | addr = NULL; |
887 | 0 | for (i = 0; i < num; i++) { |
888 | 0 | rv = ogs_addaddrinfo(&addr, family, hostname[i], port, 0); |
889 | 0 | ogs_assert(rv == OGS_OK); |
890 | 0 | } |
891 | | |
892 | 0 | ogs_list_init(&list); |
893 | 0 | ogs_list_init(&list6); |
894 | |
|
895 | 0 | if (addr) { |
896 | 0 | if (ogs_global_conf()->parameter.no_ipv4 == 0) |
897 | 0 | ogs_socknode_add(&list, AF_INET, addr, NULL); |
898 | 0 | if (ogs_global_conf()->parameter.no_ipv6 == 0) |
899 | 0 | ogs_socknode_add(&list6, AF_INET6, addr, NULL); |
900 | 0 | ogs_freeaddrinfo(addr); |
901 | 0 | } |
902 | |
|
903 | 0 | if (dev) { |
904 | 0 | rv = ogs_socknode_probe( |
905 | 0 | ogs_global_conf()->parameter.no_ipv4 ? NULL : &list, |
906 | 0 | ogs_global_conf()->parameter.no_ipv6 ? NULL : &list6, |
907 | 0 | dev, port, NULL); |
908 | 0 | ogs_assert(rv == OGS_OK); |
909 | 0 | } |
910 | | |
911 | 0 | addr = NULL; |
912 | | /* ----- Process advertise (Host+Port Parsing Logic) ----- */ |
913 | 0 | for (i = 0; i < num_of_advertise; i++) { |
914 | 0 | uint16_t adv_port = port; /* Default to server's port */ |
915 | 0 | char *hostbuf = NULL; |
916 | 0 | const char *colon_pos = strchr(advertise[i], ':'); |
917 | |
|
918 | 0 | if (colon_pos) { |
919 | | /* If a colon exists, split host and port */ |
920 | 0 | size_t host_len = colon_pos - advertise[i]; |
921 | | |
922 | | /* Allocate memory for the host part */ |
923 | 0 | hostbuf = (char *)ogs_malloc(host_len + 1); |
924 | 0 | ogs_assert(hostbuf); |
925 | | |
926 | | /* Copy the host part into hostbuf */ |
927 | 0 | memcpy(hostbuf, advertise[i], host_len); |
928 | 0 | hostbuf[host_len] = '\0'; |
929 | | |
930 | | /* Parse the port part */ |
931 | 0 | adv_port = (uint16_t)atoi(colon_pos + 1); |
932 | 0 | } else { |
933 | | /* If no colon, treat the entire string as the host */ |
934 | 0 | hostbuf = ogs_strdup(advertise[i]); |
935 | 0 | ogs_assert(hostbuf); |
936 | 0 | } |
937 | | |
938 | | /* Add the parsed address info */ |
939 | 0 | rv = ogs_addaddrinfo(&addr, family, hostbuf, adv_port, 0); |
940 | 0 | ogs_assert(rv == OGS_OK); |
941 | | |
942 | | /* Free the allocated memory */ |
943 | 0 | ogs_free(hostbuf); |
944 | 0 | } |
945 | | |
946 | 0 | node = ogs_list_first(&list); |
947 | 0 | if (node) { |
948 | 0 | server = ogs_sbi_server_add( |
949 | 0 | interface, scheme, node->addr, is_option ? &option : NULL); |
950 | 0 | ogs_assert(server); |
951 | | |
952 | 0 | if (addr && ogs_global_conf()->parameter.no_ipv4 == 0) |
953 | 0 | ogs_sbi_server_set_advertise(server, AF_INET, addr); |
954 | |
|
955 | 0 | if (verify_client == true) |
956 | 0 | server->verify_client = true; |
957 | |
|
958 | 0 | if (verify_client_cacert) { |
959 | 0 | if (server->verify_client_cacert) |
960 | 0 | ogs_free(server->verify_client_cacert); |
961 | 0 | server->verify_client_cacert = ogs_strdup(verify_client_cacert); |
962 | 0 | ogs_assert(server->verify_client_cacert); |
963 | 0 | } |
964 | | |
965 | 0 | if (server->verify_client == true && |
966 | 0 | !server->verify_client_cacert) { |
967 | 0 | ogs_error("CLIENT verification enabled but no CA certificate"); |
968 | 0 | return OGS_ERROR; |
969 | 0 | } |
970 | | |
971 | 0 | if (private_key) { |
972 | 0 | if (server->private_key) |
973 | 0 | ogs_free(server->private_key); |
974 | 0 | server->private_key = ogs_strdup(private_key); |
975 | 0 | ogs_assert(server->private_key); |
976 | 0 | } |
977 | 0 | if (cert) { |
978 | 0 | if (server->cert) |
979 | 0 | ogs_free(server->cert); |
980 | 0 | server->cert = ogs_strdup(cert); |
981 | 0 | ogs_assert(server->cert); |
982 | 0 | } |
983 | 0 | if (sslkeylog) { |
984 | 0 | if (server->sslkeylog) |
985 | 0 | ogs_free(server->sslkeylog); |
986 | 0 | server->sslkeylog = ogs_strdup(sslkeylog); |
987 | 0 | ogs_assert(server->sslkeylog); |
988 | 0 | } |
989 | | |
990 | 0 | if (scheme == OpenAPI_uri_scheme_https) { |
991 | 0 | if (!server->private_key) { |
992 | 0 | ogs_error("HTTPS scheme enabled but no server key"); |
993 | 0 | return OGS_ERROR; |
994 | 0 | } |
995 | 0 | if (!server->cert) { |
996 | 0 | ogs_error("HTTPS scheme enabled but no server certificate"); |
997 | 0 | return OGS_ERROR; |
998 | 0 | } |
999 | 0 | } |
1000 | 0 | } |
1001 | 0 | node6 = ogs_list_first(&list6); |
1002 | 0 | if (node6) { |
1003 | 0 | server = ogs_sbi_server_add( |
1004 | 0 | interface, scheme, node6->addr, is_option ? &option : NULL); |
1005 | 0 | ogs_assert(server); |
1006 | | |
1007 | 0 | if (addr && ogs_global_conf()->parameter.no_ipv6 == 0) |
1008 | 0 | ogs_sbi_server_set_advertise(server, AF_INET6, addr); |
1009 | |
|
1010 | 0 | if (verify_client == true) |
1011 | 0 | server->verify_client = true; |
1012 | |
|
1013 | 0 | if (verify_client_cacert) { |
1014 | 0 | if (server->verify_client_cacert) |
1015 | 0 | ogs_free(server->verify_client_cacert); |
1016 | 0 | server->verify_client_cacert = ogs_strdup(verify_client_cacert); |
1017 | 0 | ogs_assert(server->verify_client_cacert); |
1018 | 0 | } |
1019 | | |
1020 | 0 | if (server->verify_client == true && |
1021 | 0 | !server->verify_client_cacert) { |
1022 | 0 | ogs_error("CLIENT verification enabled but no CA certificate"); |
1023 | 0 | return OGS_ERROR; |
1024 | 0 | } |
1025 | | |
1026 | 0 | if (private_key) { |
1027 | 0 | if (server->private_key) |
1028 | 0 | ogs_free(server->private_key); |
1029 | 0 | server->private_key = ogs_strdup(private_key); |
1030 | 0 | ogs_assert(server->private_key); |
1031 | 0 | } |
1032 | 0 | if (cert) { |
1033 | 0 | if (server->cert) |
1034 | 0 | ogs_free(server->cert); |
1035 | 0 | server->cert = ogs_strdup(cert); |
1036 | 0 | ogs_assert(server->cert); |
1037 | 0 | } |
1038 | 0 | if (sslkeylog) { |
1039 | 0 | if (server->sslkeylog) |
1040 | 0 | ogs_free(server->sslkeylog); |
1041 | 0 | server->sslkeylog = ogs_strdup(sslkeylog); |
1042 | 0 | ogs_assert(server->sslkeylog); |
1043 | 0 | } |
1044 | | |
1045 | 0 | if (scheme == OpenAPI_uri_scheme_https) { |
1046 | 0 | if (!server->private_key) { |
1047 | 0 | ogs_error("HTTPS scheme enabled but no server key"); |
1048 | 0 | return OGS_ERROR; |
1049 | 0 | } |
1050 | 0 | if (!server->cert) { |
1051 | 0 | ogs_error("HTTPS scheme enabled but no server certificate"); |
1052 | 0 | return OGS_ERROR; |
1053 | 0 | } |
1054 | 0 | } |
1055 | 0 | } |
1056 | | |
1057 | 0 | if (addr) |
1058 | 0 | ogs_freeaddrinfo(addr); |
1059 | |
|
1060 | 0 | ogs_socknode_remove_all(&list); |
1061 | 0 | ogs_socknode_remove_all(&list6); |
1062 | |
|
1063 | 0 | } while (ogs_yaml_iter_type(&server_array) == YAML_SEQUENCE_NODE); |
1064 | | |
1065 | 0 | return OGS_OK; |
1066 | 0 | } |
1067 | | |
1068 | | ogs_sbi_client_t *ogs_sbi_context_parse_client_config(ogs_yaml_iter_t *iter) |
1069 | 0 | { |
1070 | 0 | ogs_sbi_client_t *client = NULL; |
1071 | 0 | const char *uri = NULL; |
1072 | |
|
1073 | 0 | int num_of_resolve = 0; |
1074 | 0 | const char *resolve[OGS_MAX_NUM_OF_HOSTNAME]; |
1075 | |
|
1076 | 0 | bool insecure_skip_verify = false; |
1077 | 0 | const char *cacert = NULL; |
1078 | |
|
1079 | 0 | const char *client_private_key = NULL; |
1080 | 0 | const char *client_cert = NULL; |
1081 | 0 | const char *client_sslkeylog = NULL; |
1082 | 0 | const char *local_if = NULL; |
1083 | |
|
1084 | 0 | bool rc; |
1085 | |
|
1086 | 0 | OpenAPI_uri_scheme_e scheme = |
1087 | 0 | OpenAPI_uri_scheme_NULL; |
1088 | |
|
1089 | 0 | char *fqdn = NULL; |
1090 | 0 | uint16_t fqdn_port = 0; |
1091 | 0 | ogs_sockaddr_t *addr = NULL; |
1092 | 0 | ogs_sockaddr_t *addr6 = NULL; |
1093 | |
|
1094 | 0 | ogs_assert(iter); |
1095 | | |
1096 | 0 | while (ogs_yaml_iter_next(iter)) { |
1097 | 0 | const char *key = ogs_yaml_iter_key(iter); |
1098 | 0 | ogs_assert(key); |
1099 | 0 | if (!strcmp(key, "uri")) { |
1100 | 0 | uri = ogs_yaml_iter_value(iter); |
1101 | 0 | } else if (!strcmp(key, "resolve")) { |
1102 | 0 | ogs_yaml_iter_t resolve_iter; |
1103 | 0 | ogs_yaml_iter_recurse(iter, &resolve_iter); |
1104 | 0 | ogs_assert(ogs_yaml_iter_type(&resolve_iter) != YAML_MAPPING_NODE); |
1105 | | |
1106 | 0 | do { |
1107 | 0 | if (ogs_yaml_iter_type(&resolve_iter) == YAML_SEQUENCE_NODE) { |
1108 | 0 | if (!ogs_yaml_iter_next(&resolve_iter)) |
1109 | 0 | break; |
1110 | 0 | } |
1111 | | |
1112 | 0 | ogs_assert(num_of_resolve < OGS_MAX_NUM_OF_HOSTNAME); |
1113 | 0 | resolve[num_of_resolve++] = ogs_yaml_iter_value(&resolve_iter); |
1114 | 0 | } while (ogs_yaml_iter_type(&resolve_iter) == YAML_SEQUENCE_NODE); |
1115 | |
|
1116 | 0 | } else if (!strcmp(key, "insecure_skip_verify")) { |
1117 | 0 | insecure_skip_verify = ogs_yaml_iter_bool(iter); |
1118 | 0 | } else if (!strcmp(key, "cacert")) { |
1119 | 0 | cacert = ogs_yaml_iter_value(iter); |
1120 | 0 | } else if (!strcmp(key, "client_private_key")) { |
1121 | 0 | client_private_key = ogs_yaml_iter_value(iter); |
1122 | 0 | } else if (!strcmp(key, "client_cert")) { |
1123 | 0 | client_cert = ogs_yaml_iter_value(iter); |
1124 | 0 | } else if (!strcmp(key, "client_sslkeylogfile")) { |
1125 | 0 | client_sslkeylog = ogs_yaml_iter_value(iter); |
1126 | 0 | } else if (!strcmp(key, "interface")) { |
1127 | 0 | local_if = ogs_yaml_iter_value(iter); |
1128 | 0 | } |
1129 | 0 | } |
1130 | | |
1131 | 0 | if (!uri) { |
1132 | 0 | ogs_error("URI[%s] is required", uri ? uri : "NULL"); |
1133 | 0 | return NULL; |
1134 | 0 | } |
1135 | | |
1136 | 0 | rc = ogs_sbi_getaddr_from_uri( |
1137 | 0 | &scheme, &fqdn, &fqdn_port, &addr, &addr6, (char *)uri); |
1138 | 0 | if (rc == false) { |
1139 | 0 | if (!scheme) |
1140 | 0 | ogs_error("Invalid Scheme in URI[%s]", uri); |
1141 | 0 | else |
1142 | 0 | ogs_error("Invalid URI[%s]", uri); |
1143 | |
|
1144 | 0 | return NULL; |
1145 | 0 | } |
1146 | | |
1147 | 0 | switch (scheme) { |
1148 | 0 | case OpenAPI_uri_scheme_https: |
1149 | 0 | if (!fqdn) { |
1150 | 0 | ogs_error("HTTPS(TLS) must be set to FQDN [uri:%s]", uri); |
1151 | |
|
1152 | 0 | ogs_freeaddrinfo(addr); |
1153 | 0 | ogs_freeaddrinfo(addr6); |
1154 | |
|
1155 | 0 | return NULL; |
1156 | 0 | } |
1157 | 0 | client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, NULL, NULL); |
1158 | 0 | ogs_assert(client); |
1159 | 0 | break; |
1160 | 0 | case OpenAPI_uri_scheme_http: |
1161 | 0 | client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6); |
1162 | 0 | ogs_assert(client); |
1163 | 0 | break; |
1164 | 0 | default: |
1165 | 0 | ogs_fatal("Invalid Scheme[%d]", scheme); |
1166 | 0 | ogs_assert_if_reached(); |
1167 | 0 | } |
1168 | | |
1169 | 0 | if (num_of_resolve) |
1170 | 0 | client->resolve = ogs_sbi_client_resolve( |
1171 | 0 | scheme, fqdn, fqdn_port, resolve, num_of_resolve); |
1172 | |
|
1173 | 0 | if (insecure_skip_verify == true) |
1174 | 0 | client->insecure_skip_verify = true; |
1175 | |
|
1176 | 0 | if (cacert) { |
1177 | 0 | if (client->cacert) |
1178 | 0 | ogs_free(client->cacert); |
1179 | 0 | client->cacert = ogs_strdup(cacert); |
1180 | 0 | ogs_assert(client->cacert); |
1181 | 0 | } |
1182 | | |
1183 | 0 | if (client_private_key) { |
1184 | 0 | if (client->private_key) |
1185 | 0 | ogs_free(client->private_key); |
1186 | 0 | client->private_key = ogs_strdup(client_private_key); |
1187 | 0 | ogs_assert(client->private_key); |
1188 | 0 | } |
1189 | | |
1190 | 0 | if (client_cert) { |
1191 | 0 | if (client->cert) |
1192 | 0 | ogs_free(client->cert); |
1193 | 0 | client->cert = ogs_strdup(client_cert); |
1194 | 0 | ogs_assert(client->cert); |
1195 | 0 | } |
1196 | | |
1197 | 0 | if (client_sslkeylog) { |
1198 | 0 | if (client->sslkeylog) |
1199 | 0 | ogs_free(client->sslkeylog); |
1200 | 0 | client->sslkeylog = ogs_strdup(client_sslkeylog); |
1201 | 0 | ogs_assert(client->sslkeylog); |
1202 | 0 | } |
1203 | | |
1204 | 0 | if (local_if) { |
1205 | 0 | if (client->local_if) |
1206 | 0 | ogs_free(client->local_if); |
1207 | 0 | client->local_if = ogs_strdup(local_if); |
1208 | 0 | ogs_assert(client->local_if); |
1209 | 0 | } |
1210 | | |
1211 | 0 | if ((!client_private_key && client_cert) || |
1212 | 0 | (client_private_key && !client_cert)) { |
1213 | 0 | ogs_error("Either the private key or certificate is missing."); |
1214 | 0 | ogs_sbi_client_remove(client); |
1215 | 0 | return NULL; |
1216 | 0 | } |
1217 | | |
1218 | 0 | ogs_free(fqdn); |
1219 | 0 | ogs_freeaddrinfo(addr); |
1220 | 0 | ogs_freeaddrinfo(addr6); |
1221 | |
|
1222 | 0 | return client; |
1223 | 0 | } |
1224 | | |
1225 | | bool ogs_sbi_nf_service_is_available(const OpenAPI_service_name_e name) |
1226 | 0 | { |
1227 | 0 | int i; |
1228 | |
|
1229 | 0 | ogs_assert(name); |
1230 | | |
1231 | 0 | if (self.num_of_service_name == 0) |
1232 | | /* If no service name is configured, all services are available */ |
1233 | 0 | return true; |
1234 | | |
1235 | 0 | for (i = 0; i < self.num_of_service_name; i++) |
1236 | | /* Only services in the configuration are available */ |
1237 | 0 | if (self.service_name[i] == name) |
1238 | 0 | return true; |
1239 | | |
1240 | 0 | return false; |
1241 | 0 | } |
1242 | | |
1243 | | ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_add(void) |
1244 | 0 | { |
1245 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL; |
1246 | |
|
1247 | 0 | ogs_pool_alloc(&nf_instance_pool, &nf_instance); |
1248 | 0 | if (!nf_instance) { |
1249 | 0 | ogs_error("OVERFLOW nf_instance_pool [pool:%llu]", |
1250 | 0 | (unsigned long long)ogs_app()->pool.nf); |
1251 | 0 | return NULL; |
1252 | 0 | } |
1253 | 0 | memset(nf_instance, 0, sizeof(ogs_sbi_nf_instance_t)); |
1254 | |
|
1255 | 0 | nf_instance->pool_id = OGS_NEXT_ID( |
1256 | 0 | nf_instance_pool.id, OGS_MIN_POOL_ID, OGS_MAX_POOL_ID); |
1257 | 0 | ogs_hash_set(nf_instance_pool.id_hash, |
1258 | 0 | &nf_instance->pool_id, sizeof(ogs_pool_id_t), nf_instance); |
1259 | |
|
1260 | 0 | nf_instance->time.heartbeat_interval = |
1261 | 0 | ogs_local_conf()->time.nf_instance.heartbeat_interval; |
1262 | |
|
1263 | 0 | nf_instance->priority = OGS_SBI_DEFAULT_PRIORITY; |
1264 | 0 | nf_instance->capacity = OGS_SBI_DEFAULT_CAPACITY; |
1265 | 0 | nf_instance->load = OGS_SBI_DEFAULT_LOAD; |
1266 | |
|
1267 | 0 | ogs_list_add(&ogs_sbi_self()->nf_instance_list, nf_instance); |
1268 | |
|
1269 | 0 | ogs_debug("[%s] NFInstance added with Ref [%s]", |
1270 | 0 | nf_instance->nf_type ? |
1271 | 0 | OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", |
1272 | 0 | nf_instance->id); |
1273 | |
|
1274 | 0 | return nf_instance; |
1275 | 0 | } |
1276 | | |
1277 | | void ogs_sbi_nf_instance_set_id(ogs_sbi_nf_instance_t *nf_instance, char *id) |
1278 | 0 | { |
1279 | 0 | ogs_assert(nf_instance); |
1280 | 0 | ogs_assert(id); |
1281 | | |
1282 | 0 | nf_instance->id = ogs_strdup(id); |
1283 | 0 | ogs_assert(nf_instance->id); |
1284 | 0 | } |
1285 | | |
1286 | | void ogs_sbi_nf_instance_set_type( |
1287 | | ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e nf_type) |
1288 | 0 | { |
1289 | 0 | ogs_assert(nf_instance); |
1290 | 0 | ogs_assert(nf_type); |
1291 | | |
1292 | 0 | nf_instance->nf_type = nf_type; |
1293 | 0 | } |
1294 | | |
1295 | | void ogs_sbi_nf_instance_set_status( |
1296 | | ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_status_e nf_status) |
1297 | 0 | { |
1298 | 0 | ogs_assert(nf_instance); |
1299 | 0 | ogs_assert(nf_status); |
1300 | | |
1301 | 0 | nf_instance->nf_status = nf_status; |
1302 | 0 | } |
1303 | | |
1304 | | void ogs_sbi_nf_instance_add_allowed_nf_type( |
1305 | | ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e allowed_nf_type) |
1306 | 0 | { |
1307 | 0 | ogs_assert(nf_instance); |
1308 | 0 | ogs_assert(allowed_nf_type); |
1309 | | |
1310 | 0 | if (nf_instance->num_of_allowed_nf_type < OGS_SBI_MAX_NUM_OF_NF_TYPE) { |
1311 | 0 | nf_instance->allowed_nf_type[nf_instance->num_of_allowed_nf_type] = |
1312 | 0 | allowed_nf_type; |
1313 | 0 | nf_instance->num_of_allowed_nf_type++; |
1314 | 0 | } |
1315 | 0 | } |
1316 | | |
1317 | | bool ogs_sbi_nf_instance_is_allowed_nf_type( |
1318 | | ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e allowed_nf_type) |
1319 | 0 | { |
1320 | 0 | int i; |
1321 | |
|
1322 | 0 | ogs_assert(nf_instance); |
1323 | 0 | ogs_assert(allowed_nf_type); |
1324 | | |
1325 | 0 | if (!nf_instance->num_of_allowed_nf_type) { |
1326 | 0 | return true; |
1327 | 0 | } |
1328 | | |
1329 | 0 | for (i = 0; i < nf_instance->num_of_allowed_nf_type; i++) { |
1330 | 0 | if (nf_instance->allowed_nf_type[i] == allowed_nf_type) |
1331 | 0 | return true; |
1332 | 0 | } |
1333 | | |
1334 | 0 | ogs_error("Not allowed nf-type[%s] in nf-instance[%s]", |
1335 | 0 | OpenAPI_nf_type_ToString(allowed_nf_type), |
1336 | 0 | OpenAPI_nf_type_ToString(nf_instance->nf_type)); |
1337 | 0 | return false; |
1338 | 0 | } |
1339 | | |
1340 | | void ogs_sbi_nf_instance_clear(ogs_sbi_nf_instance_t *nf_instance) |
1341 | 0 | { |
1342 | 0 | int i; |
1343 | |
|
1344 | 0 | ogs_assert(nf_instance); |
1345 | | |
1346 | 0 | if (nf_instance->fqdn) |
1347 | 0 | ogs_free(nf_instance->fqdn); |
1348 | 0 | nf_instance->fqdn = NULL; |
1349 | |
|
1350 | 0 | for (i = 0; i < nf_instance->num_of_ipv4; i++) { |
1351 | 0 | if (nf_instance->ipv4[i]) |
1352 | 0 | ogs_freeaddrinfo(nf_instance->ipv4[i]); |
1353 | 0 | } |
1354 | 0 | nf_instance->num_of_ipv4 = 0; |
1355 | |
|
1356 | 0 | for (i = 0; i < nf_instance->num_of_ipv6; i++) { |
1357 | 0 | if (nf_instance->ipv6[i]) |
1358 | 0 | ogs_freeaddrinfo(nf_instance->ipv6[i]); |
1359 | 0 | } |
1360 | 0 | nf_instance->num_of_ipv6 = 0; |
1361 | |
|
1362 | 0 | nf_instance->num_of_allowed_nf_type = 0; |
1363 | |
|
1364 | 0 | nf_instance->num_of_s_nssai = 0; |
1365 | 0 | nf_instance->num_of_allowed_nssai = 0; |
1366 | 0 | } |
1367 | | |
1368 | | void ogs_sbi_nf_instance_remove(ogs_sbi_nf_instance_t *nf_instance) |
1369 | 0 | { |
1370 | 0 | ogs_assert(nf_instance); |
1371 | | |
1372 | 0 | ogs_debug("[%s] NFInstance removed [%s]", |
1373 | 0 | nf_instance->nf_type ? |
1374 | 0 | OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", |
1375 | 0 | nf_instance->id); |
1376 | |
|
1377 | 0 | ogs_list_remove(&ogs_sbi_self()->nf_instance_list, nf_instance); |
1378 | |
|
1379 | 0 | ogs_sbi_nf_info_remove_all(&nf_instance->nf_info_list); |
1380 | |
|
1381 | 0 | ogs_sbi_nf_service_remove_all(nf_instance); |
1382 | |
|
1383 | 0 | ogs_sbi_nf_instance_clear(nf_instance); |
1384 | |
|
1385 | 0 | if (nf_instance->id) { |
1386 | 0 | ogs_sbi_subscription_data_remove_all_by_nf_instance_id(nf_instance->id); |
1387 | 0 | ogs_free(nf_instance->id); |
1388 | 0 | } |
1389 | |
|
1390 | 0 | if (nf_instance->hnrf_uri) |
1391 | 0 | ogs_free(nf_instance->hnrf_uri); |
1392 | |
|
1393 | 0 | if (nf_instance->client) |
1394 | 0 | ogs_sbi_client_remove(nf_instance->client); |
1395 | |
|
1396 | 0 | ogs_hash_set(nf_instance_pool.id_hash, |
1397 | 0 | &nf_instance->pool_id, sizeof(ogs_pool_id_t), NULL); |
1398 | 0 | ogs_pool_free(&nf_instance_pool, nf_instance); |
1399 | 0 | } |
1400 | | |
1401 | | void ogs_sbi_nf_instance_remove_all(void) |
1402 | 0 | { |
1403 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL, *next_nf_instance = NULL; |
1404 | |
|
1405 | 0 | ogs_list_for_each_safe( |
1406 | 0 | &ogs_sbi_self()->nf_instance_list, next_nf_instance, nf_instance) |
1407 | 0 | ogs_sbi_nf_instance_remove(nf_instance); |
1408 | 0 | } |
1409 | | |
1410 | | ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find(char *id) |
1411 | 0 | { |
1412 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL; |
1413 | | |
1414 | | /* |
1415 | | * This is related to Issue #3093. |
1416 | | * |
1417 | | * We want to be able to use 'ogs_sbi_nf_instance_id_find(char *id)' |
1418 | | * even if the 'id' is NULL as in the use case below. |
1419 | | * |
1420 | | * ogs_sbi_nf_instance_find( |
1421 | | * sess->sbi.service_name_array[service_name].nf_instance_id)); |
1422 | | * |
1423 | | * To do so, we changed the 'assert(id)' to 'if (!id) return NULL', |
1424 | | * as shown below. |
1425 | | */ |
1426 | 0 | if (!id) return NULL; |
1427 | | |
1428 | 0 | ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) { |
1429 | 0 | if (nf_instance->id && strcmp(nf_instance->id, id) == 0) |
1430 | 0 | break; |
1431 | 0 | } |
1432 | |
|
1433 | 0 | return nf_instance; |
1434 | 0 | } |
1435 | | |
1436 | | ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_pool_id(ogs_pool_id_t id) |
1437 | 0 | { |
1438 | 0 | return ogs_pool_find_by_id(&nf_instance_pool, id); |
1439 | 0 | } |
1440 | | |
1441 | | ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_discovery_param( |
1442 | | OpenAPI_nf_type_e target_nf_type, |
1443 | | OpenAPI_nf_type_e requester_nf_type, |
1444 | | ogs_sbi_discovery_option_t *discovery_option) |
1445 | 0 | { |
1446 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL; |
1447 | |
|
1448 | 0 | ogs_assert(target_nf_type); |
1449 | 0 | ogs_assert(requester_nf_type); |
1450 | | |
1451 | 0 | ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) { |
1452 | 0 | if (ogs_sbi_discovery_param_is_matched( |
1453 | 0 | nf_instance, target_nf_type, requester_nf_type, |
1454 | 0 | discovery_option) == false) |
1455 | 0 | continue; |
1456 | | |
1457 | 0 | return nf_instance; |
1458 | 0 | } |
1459 | | |
1460 | 0 | return NULL; |
1461 | 0 | } |
1462 | | |
1463 | | ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_service( |
1464 | | OpenAPI_service_name_e service_name, |
1465 | | OpenAPI_nf_type_e requester_nf_type) |
1466 | 0 | { |
1467 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL; |
1468 | 0 | ogs_sbi_discovery_option_t *discovery_option = NULL; |
1469 | |
|
1470 | 0 | OpenAPI_nf_type_e target_nf_type = OpenAPI_nf_type_NULL; |
1471 | |
|
1472 | 0 | ogs_assert(requester_nf_type); |
1473 | 0 | ogs_assert(service_name); |
1474 | 0 | target_nf_type = ogs_sbi_service_name_to_nf_type(service_name); |
1475 | 0 | ogs_assert(target_nf_type); |
1476 | | |
1477 | 0 | discovery_option = ogs_sbi_discovery_option_new(); |
1478 | 0 | ogs_assert(discovery_option); |
1479 | 0 | ogs_sbi_discovery_option_add_service_names(discovery_option, service_name); |
1480 | |
|
1481 | 0 | nf_instance = ogs_sbi_nf_instance_find_by_discovery_param( |
1482 | 0 | target_nf_type, requester_nf_type, discovery_option); |
1483 | |
|
1484 | 0 | ogs_sbi_discovery_option_free(discovery_option); |
1485 | |
|
1486 | 0 | return nf_instance; |
1487 | 0 | } |
1488 | | |
1489 | | |
1490 | | ogs_sbi_nf_service_t *ogs_sbi_nf_service_add( |
1491 | | ogs_sbi_nf_instance_t *nf_instance, |
1492 | | char *id, |
1493 | | const OpenAPI_service_name_e name, |
1494 | | OpenAPI_uri_scheme_e scheme) |
1495 | 0 | { |
1496 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
1497 | |
|
1498 | 0 | ogs_assert(nf_instance); |
1499 | 0 | ogs_assert(id); |
1500 | 0 | ogs_assert(name); |
1501 | | |
1502 | 0 | ogs_pool_alloc(&nf_service_pool, &nf_service); |
1503 | 0 | if (!nf_service) { |
1504 | 0 | ogs_error("OVERFLOW nf_service_pool [pool:%llu]", |
1505 | 0 | (unsigned long long)ogs_app()->pool.nf_service); |
1506 | 0 | return NULL; |
1507 | 0 | } |
1508 | 0 | memset(nf_service, 0, sizeof(ogs_sbi_nf_service_t)); |
1509 | |
|
1510 | 0 | nf_service->id = ogs_strdup(id); |
1511 | 0 | if (!nf_service->id) { |
1512 | 0 | ogs_error("ogs_strdup() failed for nf_service->id"); |
1513 | 0 | ogs_pool_free(&nf_service_pool, nf_service); |
1514 | 0 | return NULL; |
1515 | 0 | } |
1516 | 0 | nf_service->name = name; |
1517 | 0 | if (!nf_service->name) { |
1518 | 0 | ogs_error("ogs_strdup() failed for nf_service->name"); |
1519 | 0 | ogs_free(nf_service->id); |
1520 | 0 | ogs_pool_free(&nf_service_pool, nf_service); |
1521 | 0 | return NULL; |
1522 | 0 | } |
1523 | 0 | nf_service->scheme = scheme; |
1524 | 0 | ogs_assert(nf_service->scheme); |
1525 | | |
1526 | 0 | nf_service->status = OpenAPI_nf_service_status_REGISTERED; |
1527 | |
|
1528 | 0 | nf_service->priority = OGS_SBI_DEFAULT_PRIORITY; |
1529 | 0 | nf_service->capacity = OGS_SBI_DEFAULT_CAPACITY; |
1530 | 0 | nf_service->load = OGS_SBI_DEFAULT_LOAD; |
1531 | |
|
1532 | 0 | nf_service->nf_instance = nf_instance; |
1533 | |
|
1534 | 0 | ogs_list_add(&nf_instance->nf_service_list, nf_service); |
1535 | |
|
1536 | 0 | return nf_service; |
1537 | 0 | } |
1538 | | |
1539 | | void ogs_sbi_nf_service_add_version(ogs_sbi_nf_service_t *nf_service, |
1540 | | const char *in_uri, const char *full, const char *expiry) |
1541 | 0 | { |
1542 | 0 | ogs_assert(nf_service); |
1543 | | |
1544 | 0 | ogs_assert(in_uri); |
1545 | 0 | ogs_assert(full); |
1546 | | |
1547 | 0 | if (nf_service->num_of_version < OGS_SBI_MAX_NUM_OF_SERVICE_VERSION) { |
1548 | 0 | nf_service->version[nf_service->num_of_version].in_uri = |
1549 | 0 | ogs_strdup(in_uri); |
1550 | 0 | ogs_assert(nf_service->version[nf_service->num_of_version].in_uri); |
1551 | 0 | nf_service->version[nf_service->num_of_version].full = |
1552 | 0 | ogs_strdup(full); |
1553 | 0 | ogs_assert(nf_service->version[nf_service->num_of_version].full); |
1554 | 0 | if (expiry) { |
1555 | 0 | nf_service->version[nf_service->num_of_version].expiry = |
1556 | 0 | ogs_strdup(expiry); |
1557 | 0 | ogs_assert( |
1558 | 0 | nf_service->version[nf_service->num_of_version].expiry); |
1559 | |
|
1560 | 0 | } |
1561 | 0 | nf_service->num_of_version++; |
1562 | 0 | } |
1563 | 0 | } |
1564 | | |
1565 | | void ogs_sbi_nf_service_add_allowed_nf_type( |
1566 | | ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_type_e allowed_nf_type) |
1567 | 0 | { |
1568 | 0 | ogs_assert(nf_service); |
1569 | 0 | ogs_assert(allowed_nf_type); |
1570 | | |
1571 | 0 | if (nf_service->num_of_allowed_nf_type < OGS_SBI_MAX_NUM_OF_NF_TYPE) { |
1572 | 0 | nf_service->allowed_nf_type[nf_service->num_of_allowed_nf_type] = |
1573 | 0 | allowed_nf_type; |
1574 | 0 | nf_service->num_of_allowed_nf_type++; |
1575 | 0 | } |
1576 | 0 | } |
1577 | | |
1578 | | bool ogs_sbi_nf_service_is_allowed_nf_type( |
1579 | | ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_type_e allowed_nf_type) |
1580 | 0 | { |
1581 | 0 | int i; |
1582 | |
|
1583 | 0 | ogs_assert(nf_service); |
1584 | 0 | ogs_assert(allowed_nf_type); |
1585 | | |
1586 | 0 | if (!nf_service->num_of_allowed_nf_type) { |
1587 | 0 | return true; |
1588 | 0 | } |
1589 | | |
1590 | 0 | for (i = 0; i < nf_service->num_of_allowed_nf_type; i++) { |
1591 | 0 | if (nf_service->allowed_nf_type[i] == allowed_nf_type) |
1592 | 0 | return true; |
1593 | 0 | } |
1594 | | |
1595 | 0 | ogs_error("Not allowed nf-type[%s] in nf-service[%s]", |
1596 | 0 | OpenAPI_nf_type_ToString(allowed_nf_type), |
1597 | 0 | OpenAPI_service_name_ToString(nf_service->name)); |
1598 | 0 | return false; |
1599 | 0 | } |
1600 | | |
1601 | | void ogs_sbi_nf_service_clear(ogs_sbi_nf_service_t *nf_service) |
1602 | 0 | { |
1603 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL; |
1604 | 0 | int i; |
1605 | |
|
1606 | 0 | ogs_assert(nf_service); |
1607 | 0 | nf_instance = nf_service->nf_instance; |
1608 | 0 | ogs_assert(nf_instance); |
1609 | | |
1610 | 0 | if (nf_service->fqdn) |
1611 | 0 | ogs_free(nf_service->fqdn); |
1612 | 0 | nf_service->fqdn = NULL; |
1613 | |
|
1614 | 0 | for (i = 0; i < nf_service->num_of_version; i++) { |
1615 | 0 | if (nf_service->version[i].in_uri) |
1616 | 0 | ogs_free(nf_service->version[i].in_uri); |
1617 | 0 | if (nf_service->version[i].full) |
1618 | 0 | ogs_free(nf_service->version[i].full); |
1619 | 0 | if (nf_service->version[i].expiry) |
1620 | 0 | ogs_free(nf_service->version[i].expiry); |
1621 | 0 | } |
1622 | 0 | nf_service->num_of_version = 0; |
1623 | |
|
1624 | 0 | for (i = 0; i < nf_service->num_of_addr; i++) { |
1625 | 0 | if (nf_service->addr[i].ipv4) |
1626 | 0 | ogs_freeaddrinfo(nf_service->addr[i].ipv4); |
1627 | 0 | if (nf_service->addr[i].ipv6) |
1628 | 0 | ogs_freeaddrinfo(nf_service->addr[i].ipv6); |
1629 | 0 | } |
1630 | 0 | nf_service->num_of_addr = 0; |
1631 | |
|
1632 | 0 | nf_service->num_of_allowed_nf_type = 0; |
1633 | 0 | } |
1634 | | |
1635 | | void ogs_sbi_nf_service_remove(ogs_sbi_nf_service_t *nf_service) |
1636 | 0 | { |
1637 | 0 | ogs_sbi_nf_instance_t *nf_instance = NULL; |
1638 | |
|
1639 | 0 | ogs_assert(nf_service); |
1640 | 0 | nf_instance = nf_service->nf_instance; |
1641 | 0 | ogs_assert(nf_instance); |
1642 | | |
1643 | 0 | ogs_list_remove(&nf_instance->nf_service_list, nf_service); |
1644 | |
|
1645 | 0 | ogs_assert(nf_service->id); |
1646 | 0 | ogs_free(nf_service->id); |
1647 | |
|
1648 | 0 | ogs_sbi_nf_service_clear(nf_service); |
1649 | |
|
1650 | 0 | if (nf_service->client) |
1651 | 0 | ogs_sbi_client_remove(nf_service->client); |
1652 | |
|
1653 | 0 | ogs_pool_free(&nf_service_pool, nf_service); |
1654 | 0 | } |
1655 | | |
1656 | | void ogs_sbi_nf_service_remove_all(ogs_sbi_nf_instance_t *nf_instance) |
1657 | 0 | { |
1658 | 0 | ogs_sbi_nf_service_t *nf_service = NULL, *next_nf_service = NULL; |
1659 | |
|
1660 | 0 | ogs_assert(nf_instance); |
1661 | | |
1662 | 0 | ogs_list_for_each_safe(&nf_instance->nf_service_list, |
1663 | 0 | next_nf_service, nf_service) |
1664 | 0 | ogs_sbi_nf_service_remove(nf_service); |
1665 | 0 | } |
1666 | | |
1667 | | ogs_sbi_nf_service_t *ogs_sbi_nf_service_find_by_id( |
1668 | | ogs_sbi_nf_instance_t *nf_instance, char *id) |
1669 | 0 | { |
1670 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
1671 | |
|
1672 | 0 | ogs_assert(nf_instance); |
1673 | 0 | ogs_assert(id); |
1674 | | |
1675 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { |
1676 | 0 | ogs_assert(nf_service->id); |
1677 | 0 | if (strcmp(nf_service->id, id) == 0) |
1678 | 0 | break; |
1679 | 0 | } |
1680 | | |
1681 | 0 | return nf_service; |
1682 | 0 | } |
1683 | | |
1684 | | ogs_sbi_nf_service_t *ogs_sbi_nf_service_find_by_name( |
1685 | | ogs_sbi_nf_instance_t *nf_instance, OpenAPI_service_name_e name) |
1686 | 0 | { |
1687 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
1688 | |
|
1689 | 0 | ogs_assert(nf_instance); |
1690 | 0 | ogs_assert(name); |
1691 | | |
1692 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { |
1693 | 0 | if (nf_service->name == name) |
1694 | 0 | return nf_service; |
1695 | 0 | } |
1696 | | |
1697 | 0 | return NULL; |
1698 | 0 | } |
1699 | | |
1700 | | ogs_sbi_nf_info_t *ogs_sbi_nf_info_add( |
1701 | | ogs_list_t *list, OpenAPI_nf_type_e nf_type) |
1702 | 0 | { |
1703 | 0 | ogs_sbi_nf_info_t *nf_info = NULL; |
1704 | |
|
1705 | 0 | ogs_assert(list); |
1706 | 0 | ogs_assert(nf_type); |
1707 | | |
1708 | 0 | ogs_pool_alloc(&nf_info_pool, &nf_info); |
1709 | 0 | if (!nf_info) { |
1710 | 0 | ogs_error("OVERFLOW nf_info_pool [pool:%llu]", |
1711 | 0 | (unsigned long long)(ogs_app()->pool.nf * |
1712 | 0 | OGS_MAX_NUM_OF_NF_INFO)); |
1713 | 0 | return NULL; |
1714 | 0 | } |
1715 | 0 | memset(nf_info, 0, sizeof(*nf_info)); |
1716 | |
|
1717 | 0 | nf_info->nf_type = nf_type; |
1718 | |
|
1719 | 0 | ogs_list_add(list, nf_info); |
1720 | |
|
1721 | 0 | return nf_info; |
1722 | 0 | } |
1723 | | |
1724 | | static void amf_info_free(ogs_sbi_amf_info_t *amf_info) |
1725 | 0 | { |
1726 | 0 | ogs_assert(amf_info); |
1727 | | |
1728 | 0 | amf_info->num_of_guami = 0; |
1729 | 0 | amf_info->num_of_nr_tai = 0; |
1730 | 0 | amf_info->num_of_nr_tai_range = 0; |
1731 | 0 | } |
1732 | | |
1733 | | static void smf_info_free(ogs_sbi_smf_info_t *smf_info) |
1734 | 0 | { |
1735 | 0 | int i, j; |
1736 | 0 | ogs_assert(smf_info); |
1737 | | |
1738 | 0 | for (i = 0; i < smf_info->num_of_slice; i++) { |
1739 | 0 | for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) |
1740 | 0 | ogs_free(smf_info->slice[i].dnn[j]); |
1741 | 0 | smf_info->slice[i].num_of_dnn = 0; |
1742 | 0 | } |
1743 | 0 | smf_info->num_of_slice = 0; |
1744 | 0 | smf_info->num_of_nr_tai = 0; |
1745 | 0 | smf_info->num_of_nr_tai_range = 0; |
1746 | 0 | } |
1747 | | |
1748 | | static void scp_info_free(ogs_sbi_scp_info_t *scp_info) |
1749 | 0 | { |
1750 | 0 | int i; |
1751 | 0 | for (i = 0; i < scp_info->num_of_domain; i++) { |
1752 | 0 | if (scp_info->domain[i].name) |
1753 | 0 | ogs_free(scp_info->domain[i].name); |
1754 | 0 | if (scp_info->domain[i].fqdn) |
1755 | 0 | ogs_free(scp_info->domain[i].fqdn); |
1756 | 0 | } |
1757 | 0 | scp_info->num_of_domain = 0; |
1758 | 0 | } |
1759 | | |
1760 | | static void sepp_info_free(ogs_sbi_sepp_info_t *sepp_info) |
1761 | 0 | { |
1762 | 0 | } |
1763 | | |
1764 | | void ogs_sbi_nf_info_remove(ogs_list_t *list, ogs_sbi_nf_info_t *nf_info) |
1765 | 0 | { |
1766 | 0 | ogs_assert(list); |
1767 | 0 | ogs_assert(nf_info); |
1768 | | |
1769 | 0 | ogs_list_remove(list, nf_info); |
1770 | |
|
1771 | 0 | switch(nf_info->nf_type) { |
1772 | 0 | case OpenAPI_nf_type_AMF: |
1773 | 0 | amf_info_free(&nf_info->amf); |
1774 | 0 | break; |
1775 | 0 | case OpenAPI_nf_type_SMF: |
1776 | 0 | smf_info_free(&nf_info->smf); |
1777 | 0 | break; |
1778 | 0 | case OpenAPI_nf_type_SCP: |
1779 | 0 | scp_info_free(&nf_info->scp); |
1780 | 0 | break; |
1781 | 0 | case OpenAPI_nf_type_SEPP: |
1782 | 0 | sepp_info_free(&nf_info->sepp); |
1783 | 0 | break; |
1784 | 0 | default: |
1785 | 0 | ogs_fatal("Not implemented NF-type[%s]", |
1786 | 0 | OpenAPI_nf_type_ToString(nf_info->nf_type)); |
1787 | 0 | ogs_assert_if_reached(); |
1788 | 0 | } |
1789 | | |
1790 | 0 | ogs_pool_free(&nf_info_pool, nf_info); |
1791 | 0 | } |
1792 | | |
1793 | | void ogs_sbi_nf_info_remove_all(ogs_list_t *list) |
1794 | 0 | { |
1795 | 0 | ogs_sbi_nf_info_t *nf_info = NULL, *next_nf_info = NULL; |
1796 | |
|
1797 | 0 | ogs_assert(list); |
1798 | | |
1799 | 0 | ogs_list_for_each_safe(list, next_nf_info, nf_info) |
1800 | 0 | ogs_sbi_nf_info_remove(list, nf_info); |
1801 | 0 | } |
1802 | | |
1803 | | ogs_sbi_nf_info_t *ogs_sbi_nf_info_find( |
1804 | | ogs_list_t *list, OpenAPI_nf_type_e nf_type) |
1805 | 0 | { |
1806 | 0 | ogs_sbi_nf_info_t *nf_info = NULL; |
1807 | |
|
1808 | 0 | ogs_assert(list); |
1809 | 0 | ogs_assert(nf_type); |
1810 | | |
1811 | 0 | ogs_list_for_each(list, nf_info) { |
1812 | 0 | if (nf_info->nf_type == nf_type) |
1813 | 0 | return nf_info; |
1814 | 0 | } |
1815 | | |
1816 | 0 | return NULL; |
1817 | 0 | } |
1818 | | |
1819 | | bool ogs_sbi_check_amf_info_guami( |
1820 | | ogs_sbi_amf_info_t *amf_info, ogs_guami_t *guami) |
1821 | 0 | { |
1822 | 0 | int i; |
1823 | |
|
1824 | 0 | ogs_assert(amf_info); |
1825 | 0 | ogs_assert(guami); |
1826 | | |
1827 | 0 | for (i = 0; i < amf_info->num_of_guami; i++) { |
1828 | 0 | if ((memcmp(&amf_info->guami[i].amf_id, &guami->amf_id, |
1829 | 0 | sizeof(ogs_amf_id_t)) == 0) && |
1830 | 0 | (memcmp(&amf_info->guami[i].plmn_id, &guami->plmn_id, |
1831 | 0 | OGS_PLMN_ID_LEN) == 0)) { |
1832 | 0 | return true; |
1833 | 0 | } |
1834 | 0 | } |
1835 | | |
1836 | 0 | return false; |
1837 | 0 | } |
1838 | | |
1839 | | bool ogs_sbi_check_smf_info_slice( |
1840 | | ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn) |
1841 | 0 | { |
1842 | 0 | int i, j; |
1843 | |
|
1844 | 0 | ogs_assert(smf_info); |
1845 | 0 | ogs_assert(s_nssai); |
1846 | 0 | ogs_assert(dnn); |
1847 | | |
1848 | 0 | for (i = 0; i < smf_info->num_of_slice; i++) { |
1849 | 0 | if (s_nssai->sst == smf_info->slice[i].s_nssai.sst && |
1850 | 0 | s_nssai->sd.v == smf_info->slice[i].s_nssai.sd.v) { |
1851 | |
|
1852 | 0 | for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) { |
1853 | 0 | if (ogs_strcasecmp(dnn, smf_info->slice[i].dnn[j]) == 0) |
1854 | 0 | return true; |
1855 | 0 | } |
1856 | 0 | } |
1857 | 0 | } |
1858 | | |
1859 | 0 | return false; |
1860 | 0 | } |
1861 | | bool ogs_sbi_check_smf_info_tai( |
1862 | | ogs_sbi_smf_info_t *smf_info, ogs_5gs_tai_t *tai) |
1863 | 0 | { |
1864 | 0 | int i, j; |
1865 | |
|
1866 | 0 | ogs_assert(smf_info); |
1867 | 0 | ogs_assert(tai); |
1868 | | |
1869 | 0 | if (smf_info->num_of_nr_tai == 0 && smf_info->num_of_nr_tai_range == 0) |
1870 | 0 | return true; |
1871 | | |
1872 | 0 | for (i = 0; i < smf_info->num_of_nr_tai; i++) { |
1873 | 0 | if (memcmp(&tai->plmn_id, |
1874 | 0 | &smf_info->nr_tai[i].plmn_id, OGS_PLMN_ID_LEN) == 0) { |
1875 | 0 | if (tai->tac.v == smf_info->nr_tai[i].tac.v) |
1876 | 0 | return true; |
1877 | 0 | } |
1878 | 0 | } |
1879 | | |
1880 | 0 | for (i = 0; i < smf_info->num_of_nr_tai_range; i++) { |
1881 | 0 | if (memcmp(&tai->plmn_id, |
1882 | 0 | &smf_info->nr_tai_range[i].plmn_id, OGS_PLMN_ID_LEN) == 0) { |
1883 | 0 | for (j = 0; j < smf_info->nr_tai_range[i].num_of_tac_range; j++) { |
1884 | 0 | if (tai->tac.v >= smf_info->nr_tai_range[i].start[j].v && |
1885 | 0 | tai->tac.v <= smf_info->nr_tai_range[i].end[j].v) { |
1886 | 0 | return true; |
1887 | 0 | } |
1888 | 0 | } |
1889 | 0 | } |
1890 | 0 | } |
1891 | | |
1892 | 0 | return false; |
1893 | 0 | } |
1894 | | |
1895 | | void ogs_sbi_nf_instance_build_default(ogs_sbi_nf_instance_t *nf_instance) |
1896 | 0 | { |
1897 | 0 | ogs_sbi_server_t *server = NULL; |
1898 | 0 | char *hostname = NULL; |
1899 | |
|
1900 | 0 | ogs_assert(nf_instance); |
1901 | | |
1902 | 0 | ogs_sbi_nf_instance_set_status(nf_instance, OpenAPI_nf_status_REGISTERED); |
1903 | |
|
1904 | 0 | hostname = NULL; |
1905 | 0 | for (server = ogs_sbi_server_first(); |
1906 | 0 | server; server = ogs_sbi_server_next(server)) { |
1907 | 0 | ogs_sockaddr_t *advertise = NULL; |
1908 | |
|
1909 | 0 | advertise = server->advertise; |
1910 | 0 | if (!advertise) |
1911 | 0 | advertise = server->node.addr; |
1912 | 0 | ogs_assert(advertise); |
1913 | | |
1914 | | /* First FQDN is selected */ |
1915 | 0 | if (!hostname) |
1916 | 0 | hostname = ogs_gethostname(advertise); |
1917 | |
|
1918 | 0 | if (nf_instance->num_of_ipv4 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { |
1919 | 0 | ogs_sockaddr_t *addr = NULL; |
1920 | 0 | ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise)); |
1921 | 0 | ogs_assert(addr); |
1922 | | |
1923 | 0 | if (addr->ogs_sa_family == AF_INET) { |
1924 | 0 | nf_instance->ipv4[nf_instance->num_of_ipv4] = addr; |
1925 | 0 | nf_instance->num_of_ipv4++; |
1926 | 0 | } else if (addr->ogs_sa_family == AF_INET6) { |
1927 | 0 | nf_instance->ipv6[nf_instance->num_of_ipv6] = addr; |
1928 | 0 | nf_instance->num_of_ipv6++; |
1929 | 0 | } else |
1930 | 0 | ogs_assert_if_reached(); |
1931 | 0 | } |
1932 | 0 | } |
1933 | | |
1934 | 0 | if (hostname) { |
1935 | 0 | nf_instance->fqdn = ogs_strdup(hostname); |
1936 | 0 | ogs_assert(nf_instance->fqdn); |
1937 | 0 | } |
1938 | | |
1939 | 0 | nf_instance->time.heartbeat_interval = |
1940 | 0 | ogs_local_conf()->time.nf_instance.heartbeat_interval; |
1941 | |
|
1942 | 0 | if (ogs_local_conf()->num_of_serving_plmn_id) { |
1943 | 0 | memcpy(nf_instance->plmn_id, ogs_local_conf()->serving_plmn_id, |
1944 | 0 | sizeof(nf_instance->plmn_id)); |
1945 | 0 | nf_instance->num_of_plmn_id = ogs_local_conf()->num_of_serving_plmn_id; |
1946 | 0 | } |
1947 | 0 | } |
1948 | | |
1949 | | ogs_sbi_nf_service_t *ogs_sbi_nf_service_build_default( |
1950 | | ogs_sbi_nf_instance_t *nf_instance, OpenAPI_service_name_e name) |
1951 | 0 | { |
1952 | 0 | ogs_sbi_server_t *server = NULL; |
1953 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
1954 | 0 | ogs_uuid_t uuid; |
1955 | 0 | char id[OGS_UUID_FORMATTED_LENGTH + 1]; |
1956 | 0 | char *hostname = NULL; |
1957 | |
|
1958 | 0 | OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; |
1959 | |
|
1960 | 0 | ogs_assert(nf_instance); |
1961 | 0 | ogs_assert(name); |
1962 | | |
1963 | 0 | ogs_uuid_get(&uuid); |
1964 | 0 | ogs_uuid_format(id, &uuid); |
1965 | |
|
1966 | 0 | server = ogs_sbi_server_first(); |
1967 | 0 | ogs_assert(server); |
1968 | | |
1969 | 0 | scheme = server->scheme; |
1970 | 0 | ogs_assert(scheme); |
1971 | | |
1972 | 0 | nf_service = ogs_sbi_nf_service_add(nf_instance, id, name, scheme); |
1973 | 0 | if (!nf_service) { |
1974 | 0 | ogs_error("Cannot build default NF service [%s]: " |
1975 | 0 | "nf_service_pool exhausted at startup. " |
1976 | 0 | "Increase 'max.peer' (current pool capacity = " |
1977 | 0 | "max.peer * 16 = %llu).", |
1978 | 0 | OpenAPI_service_name_ToString(name), |
1979 | 0 | (unsigned long long)ogs_app()->pool.nf_service); |
1980 | 0 | return NULL; |
1981 | 0 | } |
1982 | | |
1983 | 0 | hostname = NULL; |
1984 | 0 | for (server = ogs_sbi_server_first(); |
1985 | 0 | server; server = ogs_sbi_server_next(server)) { |
1986 | 0 | ogs_sockaddr_t *advertise = NULL; |
1987 | |
|
1988 | 0 | advertise = server->advertise; |
1989 | 0 | if (!advertise) |
1990 | 0 | advertise = server->node.addr; |
1991 | 0 | ogs_assert(advertise); |
1992 | | |
1993 | | /* First FQDN is selected */ |
1994 | 0 | if (!hostname) |
1995 | 0 | hostname = ogs_gethostname(advertise); |
1996 | |
|
1997 | 0 | if (nf_service->num_of_addr < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { |
1998 | 0 | bool is_port = true; |
1999 | 0 | int port = 0; |
2000 | 0 | ogs_sockaddr_t *addr = NULL; |
2001 | 0 | ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise)); |
2002 | 0 | ogs_assert(addr); |
2003 | | |
2004 | 0 | port = OGS_PORT(addr); |
2005 | 0 | if (nf_service->scheme == OpenAPI_uri_scheme_https) { |
2006 | 0 | if (port == OGS_SBI_HTTPS_PORT) is_port = false; |
2007 | 0 | } else if (nf_service->scheme == OpenAPI_uri_scheme_http) { |
2008 | 0 | if (port == OGS_SBI_HTTP_PORT) is_port = false; |
2009 | 0 | } |
2010 | |
|
2011 | 0 | nf_service->addr[nf_service->num_of_addr].is_port = is_port; |
2012 | 0 | nf_service->addr[nf_service->num_of_addr].port = port; |
2013 | 0 | if (addr->ogs_sa_family == AF_INET) { |
2014 | 0 | nf_service->addr[nf_service->num_of_addr].ipv4 = addr; |
2015 | 0 | } else if (addr->ogs_sa_family == AF_INET6) { |
2016 | 0 | nf_service->addr[nf_service->num_of_addr].ipv6 = addr; |
2017 | 0 | } else |
2018 | 0 | ogs_assert_if_reached(); |
2019 | | |
2020 | 0 | nf_service->num_of_addr++; |
2021 | 0 | } |
2022 | 0 | } |
2023 | | |
2024 | 0 | if (hostname) { |
2025 | 0 | nf_service->fqdn = ogs_strdup(hostname); |
2026 | 0 | ogs_assert(nf_service->fqdn); |
2027 | 0 | } |
2028 | | |
2029 | 0 | ogs_info("NF Service [%s]", |
2030 | 0 | OpenAPI_service_name_ToString(nf_service->name)); |
2031 | |
|
2032 | 0 | return nf_service; |
2033 | 0 | } |
2034 | | |
2035 | | static ogs_sbi_client_t *nf_instance_find_client( |
2036 | | ogs_sbi_nf_instance_t *nf_instance) |
2037 | 0 | { |
2038 | 0 | ogs_sbi_client_t *client = NULL; |
2039 | 0 | ogs_sockaddr_t *addr = NULL, *addr6 = NULL; |
2040 | 0 | OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; |
2041 | |
|
2042 | 0 | ogs_sbi_nf_info_t *nf_info = NULL; |
2043 | 0 | uint16_t port = 0; |
2044 | |
|
2045 | 0 | scheme = ogs_sbi_self()->tls.client.scheme; |
2046 | 0 | ogs_assert(scheme); |
2047 | | |
2048 | 0 | switch (nf_instance->nf_type) { |
2049 | 0 | case OpenAPI_nf_type_SEPP: |
2050 | 0 | nf_info = ogs_sbi_nf_info_find( |
2051 | 0 | &nf_instance->nf_info_list, nf_instance->nf_type); |
2052 | 0 | if (nf_info) { |
2053 | 0 | if (scheme == OpenAPI_uri_scheme_https) |
2054 | 0 | port = nf_info->sepp.https.port; |
2055 | 0 | else if (scheme == OpenAPI_uri_scheme_http) |
2056 | 0 | port = nf_info->sepp.http.port; |
2057 | 0 | else |
2058 | 0 | ogs_error("Unknown scheme [%d]", scheme); |
2059 | 0 | } |
2060 | 0 | break; |
2061 | 0 | case OpenAPI_nf_type_SCP: |
2062 | 0 | nf_info = ogs_sbi_nf_info_find( |
2063 | 0 | &nf_instance->nf_info_list, nf_instance->nf_type); |
2064 | 0 | if (nf_info) { |
2065 | 0 | if (scheme == OpenAPI_uri_scheme_https) |
2066 | 0 | port = nf_info->scp.https.port; |
2067 | 0 | else if (scheme == OpenAPI_uri_scheme_http) |
2068 | 0 | port = nf_info->scp.http.port; |
2069 | 0 | else |
2070 | 0 | ogs_error("Unknown scheme [%d]", scheme); |
2071 | 0 | } |
2072 | 0 | break; |
2073 | 0 | default: |
2074 | 0 | break; |
2075 | 0 | } |
2076 | | |
2077 | | /* At this point, CLIENT selection method is very simple. */ |
2078 | 0 | if (nf_instance->num_of_ipv4) addr = nf_instance->ipv4[0]; |
2079 | 0 | if (nf_instance->num_of_ipv6) addr6 = nf_instance->ipv6[0]; |
2080 | |
|
2081 | 0 | if (port) { |
2082 | 0 | if (addr) |
2083 | 0 | addr->ogs_sin_port = htobe16(port); |
2084 | 0 | if (addr6) |
2085 | 0 | addr6->ogs_sin_port = htobe16(port); |
2086 | 0 | } |
2087 | |
|
2088 | 0 | if (nf_instance->fqdn || addr || addr6) { |
2089 | 0 | client = ogs_sbi_client_find( |
2090 | 0 | scheme, nf_instance->fqdn, port, addr, addr6); |
2091 | 0 | if (!client) { |
2092 | 0 | ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); |
2093 | 0 | client = ogs_sbi_client_add( |
2094 | 0 | scheme, nf_instance->fqdn, port, addr, addr6); |
2095 | 0 | if (!client) { |
2096 | 0 | ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC); |
2097 | 0 | return NULL; |
2098 | 0 | } |
2099 | 0 | } |
2100 | 0 | } else |
2101 | 0 | ogs_error("[%s] No instance-level endpoint, " |
2102 | 0 | "client association skipped [id:%s]", |
2103 | 0 | OpenAPI_nf_type_ToString(nf_instance->nf_type), |
2104 | 0 | nf_instance->id); |
2105 | | |
2106 | 0 | return client; |
2107 | 0 | } |
2108 | | |
2109 | | static void nf_service_associate_client(ogs_sbi_nf_service_t *nf_service) |
2110 | 0 | { |
2111 | 0 | ogs_sbi_client_t *client = NULL; |
2112 | 0 | ogs_sockaddr_t *addr = NULL, *addr6 = NULL; |
2113 | 0 | uint16_t port = 0; |
2114 | |
|
2115 | 0 | ogs_assert(nf_service->scheme); |
2116 | | |
2117 | | /* At this point, CLIENT selection method is very simple. */ |
2118 | 0 | if (nf_service->num_of_addr) { |
2119 | 0 | addr = nf_service->addr[0].ipv4; |
2120 | 0 | addr6 = nf_service->addr[0].ipv6; |
2121 | | |
2122 | | /* |
2123 | | * Added support for using custom port numbers with FQDN. |
2124 | | * |
2125 | | * This code checks if a user-defined port number is provided in the |
2126 | | * NFService structure. If the is_port flag is set, the port is |
2127 | | * assigned the specified value. |
2128 | | * |
2129 | | * This ensures that services using non-default ports can be accessed |
2130 | | * correctly, regardless of whether TLS is enabled or not. |
2131 | | */ |
2132 | 0 | if (nf_service->addr[0].is_port) |
2133 | 0 | port = nf_service->addr[0].port; |
2134 | 0 | } |
2135 | |
|
2136 | 0 | if (nf_service->fqdn || addr || addr6) { |
2137 | 0 | client = ogs_sbi_client_find( |
2138 | 0 | nf_service->scheme, nf_service->fqdn, port, addr, addr6); |
2139 | 0 | if (!client) { |
2140 | 0 | ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); |
2141 | 0 | client = ogs_sbi_client_add( |
2142 | 0 | nf_service->scheme, nf_service->fqdn, port, addr, addr6); |
2143 | 0 | if (!client) { |
2144 | 0 | ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC); |
2145 | 0 | return; |
2146 | 0 | } |
2147 | 0 | } |
2148 | 0 | } else |
2149 | 0 | ogs_error("[%s] No service-level endpoint, " |
2150 | 0 | "client association skipped [id:%s]", |
2151 | 0 | OpenAPI_service_name_ToString(nf_service->name), |
2152 | 0 | nf_service->id); |
2153 | | |
2154 | 0 | if (client) { |
2155 | 0 | ogs_info("[%s] NFService associated [%s]", |
2156 | 0 | OpenAPI_service_name_ToString(nf_service->name), |
2157 | 0 | nf_service->id); |
2158 | 0 | OGS_SBI_SETUP_CLIENT(nf_service, client); |
2159 | 0 | } |
2160 | 0 | } |
2161 | | |
2162 | | static void nf_service_associate_client_all(ogs_sbi_nf_instance_t *nf_instance) |
2163 | 0 | { |
2164 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
2165 | |
|
2166 | 0 | ogs_assert(nf_instance); |
2167 | | |
2168 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) |
2169 | 0 | nf_service_associate_client(nf_service); |
2170 | 0 | } |
2171 | | |
2172 | | bool ogs_sbi_discovery_option_is_matched( |
2173 | | ogs_sbi_nf_instance_t *nf_instance, |
2174 | | OpenAPI_nf_type_e requester_nf_type, |
2175 | | ogs_sbi_discovery_option_t *discovery_option) |
2176 | 0 | { |
2177 | 0 | ogs_sbi_nf_info_t *nf_info = NULL; |
2178 | 0 | bool smf_info_checked = false; |
2179 | 0 | bool smf_match_found = false; |
2180 | 0 | bool need_smf_slice = false; /* requires both S-NSSAI and DNN */ |
2181 | 0 | bool need_smf_tai = false; /* TAI filter present */ |
2182 | 0 | bool need_smf_any = false; /* any SMF-specific filter */ |
2183 | 0 | int i; |
2184 | |
|
2185 | 0 | ogs_assert(nf_instance); |
2186 | 0 | ogs_assert(requester_nf_type); |
2187 | 0 | ogs_assert(discovery_option); |
2188 | | |
2189 | | /* -------------------------------------------------------------- |
2190 | | * Step 1. Common pre-checks for all NF types |
2191 | | * -------------------------------------------------------------- */ |
2192 | 0 | if (discovery_option->target_nf_instance_id && |
2193 | 0 | nf_instance->id && |
2194 | 0 | strcmp(nf_instance->id, |
2195 | 0 | discovery_option->target_nf_instance_id) != 0) |
2196 | 0 | return false; |
2197 | | |
2198 | 0 | if (discovery_option->num_of_service_names && |
2199 | 0 | ogs_sbi_discovery_option_service_names_is_matched( |
2200 | 0 | nf_instance, requester_nf_type, discovery_option) == false) |
2201 | 0 | return false; |
2202 | | |
2203 | 0 | if (discovery_option->num_of_target_plmn_list && |
2204 | 0 | ogs_sbi_discovery_option_target_plmn_list_is_matched( |
2205 | 0 | nf_instance, discovery_option) == false) |
2206 | 0 | return false; |
2207 | | |
2208 | 0 | if (nf_instance->nf_type == OpenAPI_nf_type_NRF && |
2209 | 0 | ogs_sbi_discovery_option_hnrf_uri_is_matched( |
2210 | 0 | nf_instance, discovery_option) == false) |
2211 | 0 | return false; |
2212 | | |
2213 | | /* |
2214 | | * TS 33.518 4.2.2.2.1 - Target allowed_nssai filtering |
2215 | | * |
2216 | | * If the target NF registered with allowedNssais, it may only be |
2217 | | * discovered for queries whose S-NSSAI falls within that set. |
2218 | | */ |
2219 | 0 | if (nf_instance->num_of_allowed_nssai && |
2220 | 0 | discovery_option->num_of_snssais) { |
2221 | 0 | bool nssai_allowed = false; |
2222 | |
|
2223 | 0 | for (i = 0; i < discovery_option->num_of_snssais; i++) { |
2224 | 0 | int j; |
2225 | 0 | for (j = 0; j < nf_instance->num_of_allowed_nssai; j++) { |
2226 | 0 | if (discovery_option->snssais[i].sst == |
2227 | 0 | nf_instance->allowed_nssai[j].sst && |
2228 | 0 | discovery_option->snssais[i].sd.v == |
2229 | 0 | nf_instance->allowed_nssai[j].sd.v) { |
2230 | 0 | nssai_allowed = true; |
2231 | 0 | break; |
2232 | 0 | } |
2233 | 0 | } |
2234 | 0 | if (nssai_allowed) break; |
2235 | 0 | } |
2236 | |
|
2237 | 0 | if (!nssai_allowed) |
2238 | 0 | return false; |
2239 | 0 | } |
2240 | | |
2241 | | /* Determine which SMF filters are requested */ |
2242 | 0 | if (nf_instance->nf_type == OpenAPI_nf_type_SMF) { |
2243 | 0 | need_smf_slice = (discovery_option->num_of_snssais && |
2244 | 0 | discovery_option->dnn) ? true : false; |
2245 | 0 | need_smf_tai = discovery_option->tai_presence ? true : false; |
2246 | | |
2247 | | /* If more SMF filters are added later, OR them here */ |
2248 | 0 | need_smf_any = (need_smf_slice || need_smf_tai) ? true : false; |
2249 | 0 | } |
2250 | | |
2251 | | /* -------------------------------------------------------------- |
2252 | | * Step 2. NF-type specific matching |
2253 | | * -------------------------------------------------------------- */ |
2254 | 0 | ogs_list_for_each(&nf_instance->nf_info_list, nf_info) { |
2255 | 0 | if (nf_instance->nf_type != nf_info->nf_type) { |
2256 | 0 | ogs_error("Invalid NF-Type [%d:%d]", |
2257 | 0 | nf_instance->nf_type, nf_info->nf_type); |
2258 | 0 | return false; |
2259 | 0 | } |
2260 | | |
2261 | | /* --- AMF --- */ |
2262 | 0 | if (nf_info->nf_type == OpenAPI_nf_type_AMF) { |
2263 | 0 | if (requester_nf_type == OpenAPI_nf_type_AMF && |
2264 | 0 | discovery_option->guami_presence && |
2265 | 0 | ogs_sbi_check_amf_info_guami( |
2266 | 0 | &nf_info->amf, |
2267 | 0 | &discovery_option->guami) == false) |
2268 | 0 | return false; |
2269 | 0 | } |
2270 | | |
2271 | | /* --- SMF --- */ |
2272 | 0 | else if (nf_info->nf_type == OpenAPI_nf_type_SMF) { |
2273 | | /* Skip expensive checks if no SMF filter is requested */ |
2274 | 0 | smf_info_checked = true; |
2275 | | |
2276 | | /* Slice (S-NSSAI + DNN) filter */ |
2277 | 0 | if (need_smf_slice) { |
2278 | 0 | bool slice_ok = false; |
2279 | 0 | for (i = 0; i < discovery_option->num_of_snssais; i++) { |
2280 | 0 | if (ogs_sbi_check_smf_info_slice( |
2281 | 0 | &nf_info->smf, |
2282 | 0 | &discovery_option->snssais[i], |
2283 | 0 | discovery_option->dnn)) { |
2284 | 0 | slice_ok = true; |
2285 | 0 | break; |
2286 | 0 | } |
2287 | 0 | } |
2288 | 0 | if (slice_ok == false) |
2289 | 0 | continue; /* this smfInfo does not match slice */ |
2290 | 0 | } |
2291 | | |
2292 | | /* TAI filter (applied after slice if present) */ |
2293 | 0 | if (need_smf_tai) { |
2294 | 0 | if (ogs_sbi_check_smf_info_tai( |
2295 | 0 | &nf_info->smf, |
2296 | 0 | &discovery_option->tai) == false) |
2297 | 0 | continue; /* this smfInfo does not match TAI */ |
2298 | 0 | } |
2299 | | |
2300 | | /* If we reached here, all requested filters passed */ |
2301 | 0 | smf_match_found = true; |
2302 | 0 | break; /* OR logic across smfInfo blocks */ |
2303 | 0 | } |
2304 | | |
2305 | | /* Other NF types: no additional checks here */ |
2306 | 0 | } |
2307 | | |
2308 | | /* -------------------------------------------------------------- |
2309 | | * Step 3. Final validation for SMF |
2310 | | * -------------------------------------------------------------- */ |
2311 | 0 | if (nf_instance->nf_type == OpenAPI_nf_type_SMF && |
2312 | 0 | smf_info_checked && |
2313 | 0 | need_smf_any && |
2314 | 0 | smf_match_found == false) |
2315 | 0 | return false; |
2316 | | |
2317 | 0 | return true; |
2318 | 0 | } |
2319 | | |
2320 | | bool ogs_sbi_discovery_option_service_names_is_matched( |
2321 | | ogs_sbi_nf_instance_t *nf_instance, |
2322 | | OpenAPI_nf_type_e requester_nf_type, |
2323 | | ogs_sbi_discovery_option_t *discovery_option) |
2324 | 0 | { |
2325 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
2326 | 0 | int i; |
2327 | |
|
2328 | 0 | ogs_assert(nf_instance); |
2329 | 0 | ogs_assert(requester_nf_type); |
2330 | 0 | ogs_assert(discovery_option); |
2331 | | |
2332 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { |
2333 | 0 | for (i = 0; i < discovery_option->num_of_service_names; i++) { |
2334 | 0 | if (nf_service->name && |
2335 | 0 | discovery_option->service_names[i] && |
2336 | 0 | nf_service->name == discovery_option->service_names[i]) { |
2337 | 0 | if (ogs_sbi_nf_service_is_allowed_nf_type( |
2338 | 0 | nf_service, requester_nf_type) == true) { |
2339 | 0 | return true; |
2340 | 0 | } |
2341 | 0 | } |
2342 | 0 | } |
2343 | 0 | } |
2344 | 0 | return false; |
2345 | 0 | } |
2346 | | |
2347 | | bool ogs_sbi_discovery_param_serving_plmn_list_is_matched( |
2348 | | ogs_sbi_nf_instance_t *nf_instance) |
2349 | 0 | { |
2350 | 0 | int i, j; |
2351 | |
|
2352 | 0 | ogs_assert(nf_instance); |
2353 | | |
2354 | | /* |
2355 | | * The PLMN-ID is optional and may not be set. |
2356 | | * |
2357 | | * Does not compare if serving PLMN-ID is not set or NF-Instance is not set. |
2358 | | */ |
2359 | 0 | if (ogs_local_conf()->num_of_serving_plmn_id == 0 || |
2360 | 0 | nf_instance->num_of_plmn_id == 0) |
2361 | 0 | return true; |
2362 | | |
2363 | 0 | for (i = 0; i < nf_instance->num_of_plmn_id; i++) { |
2364 | 0 | for (j = 0; j < ogs_local_conf()->num_of_serving_plmn_id; j++) { |
2365 | 0 | if (memcmp(&nf_instance->plmn_id[i], |
2366 | 0 | &ogs_local_conf()->serving_plmn_id[j], |
2367 | 0 | OGS_PLMN_ID_LEN) == 0) { |
2368 | 0 | return true; |
2369 | 0 | } |
2370 | 0 | } |
2371 | 0 | } |
2372 | 0 | return false; |
2373 | 0 | } |
2374 | | |
2375 | | bool ogs_sbi_discovery_option_requester_plmn_list_is_matched( |
2376 | | ogs_sbi_nf_instance_t *nf_instance, |
2377 | | ogs_sbi_discovery_option_t *discovery_option) |
2378 | 0 | { |
2379 | 0 | int i, j; |
2380 | |
|
2381 | 0 | ogs_assert(nf_instance); |
2382 | 0 | ogs_assert(discovery_option); |
2383 | | |
2384 | 0 | for (i = 0; i < nf_instance->num_of_plmn_id; i++) { |
2385 | 0 | for (j = 0; j < discovery_option->num_of_requester_plmn_list; j++) { |
2386 | 0 | if (memcmp(&nf_instance->plmn_id[i], |
2387 | 0 | &discovery_option->requester_plmn_list[j], |
2388 | 0 | OGS_PLMN_ID_LEN) == 0) { |
2389 | 0 | return true; |
2390 | 0 | } |
2391 | 0 | } |
2392 | 0 | } |
2393 | 0 | return false; |
2394 | 0 | } |
2395 | | |
2396 | | bool ogs_sbi_discovery_option_target_plmn_list_is_matched( |
2397 | | ogs_sbi_nf_instance_t *nf_instance, |
2398 | | ogs_sbi_discovery_option_t *discovery_option) |
2399 | 0 | { |
2400 | 0 | int i, j; |
2401 | |
|
2402 | 0 | ogs_assert(nf_instance); |
2403 | 0 | ogs_assert(discovery_option); |
2404 | | |
2405 | 0 | for (i = 0; i < nf_instance->num_of_plmn_id; i++) { |
2406 | 0 | for (j = 0; j < discovery_option->num_of_target_plmn_list; j++) { |
2407 | 0 | if (memcmp(&nf_instance->plmn_id[i], |
2408 | 0 | &discovery_option->target_plmn_list[j], |
2409 | 0 | OGS_PLMN_ID_LEN) == 0) { |
2410 | 0 | return true; |
2411 | 0 | } |
2412 | 0 | } |
2413 | 0 | } |
2414 | 0 | return false; |
2415 | 0 | } |
2416 | | |
2417 | | bool ogs_sbi_discovery_option_hnrf_uri_is_matched( |
2418 | | ogs_sbi_nf_instance_t *nf_instance, |
2419 | | ogs_sbi_discovery_option_t *discovery_option) |
2420 | 0 | { |
2421 | 0 | ogs_assert(nf_instance); |
2422 | 0 | ogs_assert(discovery_option); |
2423 | | |
2424 | 0 | if (nf_instance->hnrf_uri == NULL && discovery_option->hnrf_uri == NULL) |
2425 | 0 | return true; |
2426 | 0 | else if (nf_instance->hnrf_uri == NULL || |
2427 | 0 | discovery_option->hnrf_uri == NULL) |
2428 | 0 | return false; |
2429 | | |
2430 | 0 | return ogs_strcasecmp(nf_instance->hnrf_uri, |
2431 | 0 | discovery_option->hnrf_uri) == 0; |
2432 | 0 | } |
2433 | | |
2434 | | bool ogs_sbi_discovery_param_is_matched( |
2435 | | ogs_sbi_nf_instance_t *nf_instance, |
2436 | | OpenAPI_nf_type_e target_nf_type, |
2437 | | OpenAPI_nf_type_e requester_nf_type, |
2438 | | ogs_sbi_discovery_option_t *discovery_option) |
2439 | 0 | { |
2440 | 0 | ogs_assert(nf_instance); |
2441 | 0 | ogs_assert(target_nf_type); |
2442 | 0 | ogs_assert(requester_nf_type); |
2443 | | |
2444 | 0 | if (NF_INSTANCE_EXCLUDED_FROM_DISCOVERY(nf_instance)) |
2445 | 0 | return false; |
2446 | | |
2447 | 0 | if (nf_instance->nf_type != target_nf_type) |
2448 | 0 | return false; |
2449 | | |
2450 | | /* |
2451 | | * For the same PLMN, The target-plmn-list may not be included |
2452 | | * in discovery request. |
2453 | | * |
2454 | | * If the Serving PLMN needs to be discovered, but the target-plmn-list |
2455 | | * is not included, the NF of the Home PLMN can be discovered. |
2456 | | * |
2457 | | * To avoid this situation, if the target-plmn-list is not included |
2458 | | * and the serving PLMN is known, it is compared first. |
2459 | | * |
2460 | | * Refer to the following standard for this issue. |
2461 | | * |
2462 | | * TS29.510 |
2463 | | * 6.2 Nnrf_NFDiscovery Service API |
2464 | | * 6.2.3 Resources |
2465 | | * Table 6.2.3.2.3.1-1: URI query parameters supported |
2466 | | * by the GET method on this resource |
2467 | | * |
2468 | | * NAME: target-plmn-list |
2469 | | * Data type: array(PlmnId) |
2470 | | * P: C |
2471 | | * Cardinality: 1..N |
2472 | | * |
2473 | | * This IE shall be included when NF services in a different PLMN, |
2474 | | * or NF services of specific PLMN ID(s) in a same PLMN |
2475 | | * comprising multiple PLMN IDs, need to be discovered. |
2476 | | * When included, this IE shall contain the PLMN ID of the target NF. |
2477 | | * If more than one PLMN ID is included, NFs from any PLMN ID present |
2478 | | * in the list matches the query parameter. This IE shall also |
2479 | | * be included in SNPN scenarios, when the entity owning |
2480 | | * the subscription, the Credentials Holder |
2481 | | * (see clause 5.30.2.9 in 3GPP TS 23.501 [2]) is a PLMN. |
2482 | | * |
2483 | | * For inter-PLMN service discovery, at most 1 PLMN ID shall |
2484 | | * be included in the list; it shall be included |
2485 | | * in the service discovery from the NF in the source PLMN sent |
2486 | | * to the NRF in the same PLMN, while it may be absent |
2487 | | * in the service discovery request sent from the source NRF |
2488 | | * to the target NRF. In such case, if the NRF receives more than |
2489 | | * 1 PLMN ID, it shall only consider the first element of the array, |
2490 | | * and ignore the rest. |
2491 | | */ |
2492 | 0 | if (!discovery_option || !discovery_option->num_of_target_plmn_list) { |
2493 | 0 | if (ogs_sbi_discovery_param_serving_plmn_list_is_matched( |
2494 | 0 | nf_instance) == false) |
2495 | 0 | return false; |
2496 | 0 | } |
2497 | | |
2498 | 0 | if (discovery_option) { |
2499 | 0 | if (ogs_sbi_discovery_option_is_matched( |
2500 | 0 | nf_instance, requester_nf_type, discovery_option) == false) |
2501 | 0 | return false; |
2502 | 0 | } |
2503 | | |
2504 | 0 | return true; |
2505 | 0 | } |
2506 | | |
2507 | | void ogs_sbi_client_associate(ogs_sbi_nf_instance_t *nf_instance) |
2508 | 0 | { |
2509 | 0 | ogs_sbi_client_t *client = NULL; |
2510 | |
|
2511 | 0 | ogs_assert(nf_instance); |
2512 | | |
2513 | 0 | client = nf_instance_find_client(nf_instance); |
2514 | 0 | if (client) { |
2515 | 0 | ogs_info("[%s] NFInstance associated [%s]", |
2516 | 0 | nf_instance->nf_type ? |
2517 | 0 | OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", |
2518 | 0 | nf_instance->id); |
2519 | |
|
2520 | 0 | OGS_SBI_SETUP_CLIENT(nf_instance, client); |
2521 | 0 | } |
2522 | | |
2523 | 0 | nf_service_associate_client_all(nf_instance); |
2524 | 0 | } |
2525 | | |
2526 | | bool nf_instance_has_usable_client(ogs_sbi_nf_instance_t *nf_instance) |
2527 | 0 | { |
2528 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
2529 | |
|
2530 | 0 | ogs_assert(nf_instance); |
2531 | | |
2532 | | /* Instance-level client */ |
2533 | 0 | if (NF_INSTANCE_CLIENT(nf_instance)) |
2534 | 0 | return true; |
2535 | | |
2536 | | /* Service-level clients */ |
2537 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { |
2538 | 0 | if (nf_service->client) |
2539 | 0 | return true; |
2540 | 0 | } |
2541 | | |
2542 | 0 | return false; |
2543 | 0 | } |
2544 | | |
2545 | | int ogs_sbi_default_client_port(OpenAPI_uri_scheme_e scheme) |
2546 | 0 | { |
2547 | 0 | if (scheme == OpenAPI_uri_scheme_NULL) |
2548 | 0 | scheme = ogs_sbi_self()->tls.client.scheme; |
2549 | |
|
2550 | 0 | return scheme == OpenAPI_uri_scheme_https ? |
2551 | 0 | OGS_SBI_HTTPS_PORT : OGS_SBI_HTTP_PORT; |
2552 | 0 | } |
2553 | | |
2554 | | ogs_sbi_client_t *ogs_sbi_client_find_by_service_name( |
2555 | | ogs_sbi_nf_instance_t *nf_instance, char *name, char *version) |
2556 | 0 | { |
2557 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
2558 | 0 | OpenAPI_service_name_e service_name = OpenAPI_service_name_NULL; |
2559 | 0 | int i; |
2560 | |
|
2561 | 0 | ogs_assert(nf_instance); |
2562 | 0 | ogs_assert(name); |
2563 | 0 | ogs_assert(version); |
2564 | | |
2565 | 0 | service_name = OpenAPI_service_name_FromString(name); |
2566 | 0 | if (!service_name) { |
2567 | 0 | ogs_error("Invalid service-name[%s]", name); |
2568 | 0 | return NULL; |
2569 | 0 | } |
2570 | | |
2571 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { |
2572 | 0 | ogs_assert(nf_service->name); |
2573 | 0 | if (nf_service->name == service_name) { |
2574 | 0 | for (i = 0; i < nf_service->num_of_version; i++) { |
2575 | 0 | if (strcmp(nf_service->version[i].in_uri, version) == 0) { |
2576 | 0 | return nf_service->client; |
2577 | 0 | } |
2578 | 0 | } |
2579 | 0 | } |
2580 | 0 | } |
2581 | | |
2582 | 0 | return NULL; |
2583 | 0 | } |
2584 | | |
2585 | | ogs_sbi_client_t *ogs_sbi_client_find_by_service( |
2586 | | ogs_sbi_nf_instance_t *nf_instance, |
2587 | | OpenAPI_service_name_e service_name) |
2588 | 0 | { |
2589 | 0 | ogs_sbi_nf_service_t *nf_service = NULL; |
2590 | |
|
2591 | 0 | ogs_assert(nf_instance); |
2592 | 0 | ogs_assert(service_name); |
2593 | | |
2594 | 0 | ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { |
2595 | 0 | if (nf_service->name == service_name) |
2596 | 0 | return nf_service->client; |
2597 | 0 | } |
2598 | | |
2599 | 0 | return NULL; |
2600 | 0 | } |
2601 | | |
2602 | | void ogs_sbi_object_free(ogs_sbi_object_t *sbi_object) |
2603 | 0 | { |
2604 | 0 | int i; |
2605 | |
|
2606 | 0 | ogs_assert(sbi_object); |
2607 | | |
2608 | 0 | if (ogs_list_count(&sbi_object->xact_list)) { |
2609 | 0 | ogs_sbi_xact_t *xact = NULL; \ |
2610 | 0 | ogs_error("SBI running [%d]", ogs_list_count(&sbi_object->xact_list)); |
2611 | 0 | ogs_list_for_each(&sbi_object->xact_list, xact) |
2612 | 0 | OGS_SBI_XACT_LOG(xact); |
2613 | 0 | } |
2614 | |
|
2615 | 0 | for (i = 0; i < OGS_SBI_MAX_NUM_OF_SERVICE_NAME; i++) { |
2616 | 0 | if (sbi_object->service_name_array[i].nf_instance_id) |
2617 | 0 | ogs_free(sbi_object->service_name_array[i].nf_instance_id); |
2618 | 0 | } |
2619 | 0 | for (i = 0; i < OGS_SBI_MAX_NUM_OF_NF_TYPE; i++) { |
2620 | 0 | if (sbi_object->nf_type_array[i].nf_instance_id) |
2621 | 0 | ogs_free(sbi_object->nf_type_array[i].nf_instance_id); |
2622 | 0 | } |
2623 | 0 | if (sbi_object->home_nsmf_pdusession.nf_instance_id) |
2624 | 0 | ogs_free(sbi_object->home_nsmf_pdusession.nf_instance_id); |
2625 | 0 | } |
2626 | | |
2627 | | ogs_sbi_xact_t *ogs_sbi_xact_add( |
2628 | | ogs_pool_id_t sbi_object_id, |
2629 | | ogs_sbi_object_t *sbi_object, |
2630 | | OpenAPI_service_name_e service_name, |
2631 | | ogs_sbi_discovery_option_t *discovery_option, |
2632 | | ogs_sbi_build_f build, void *context, void *data) |
2633 | 0 | { |
2634 | 0 | ogs_sbi_xact_t *xact = NULL; |
2635 | |
|
2636 | 0 | ogs_assert(sbi_object); |
2637 | | |
2638 | 0 | ogs_pool_id_calloc(&xact_pool, &xact); |
2639 | 0 | if (!xact) { |
2640 | 0 | ogs_error("ogs_pool_id_calloc() failed"); |
2641 | 0 | return NULL; |
2642 | 0 | } |
2643 | | |
2644 | 0 | xact->sbi_object_id = sbi_object_id; |
2645 | 0 | xact->sbi_object = sbi_object; |
2646 | 0 | xact->service_name = service_name; |
2647 | 0 | xact->requester_nf_type = NF_INSTANCE_TYPE(ogs_sbi_self()->nf_instance); |
2648 | 0 | ogs_assert(xact->requester_nf_type); |
2649 | | |
2650 | | /* |
2651 | | * Insert one service-name in the discovery option in the function below. |
2652 | | * |
2653 | | * - ogs_sbi_xact_add() |
2654 | | * - ogs_sbi_send_notification_request() |
2655 | | */ |
2656 | 0 | if (!discovery_option) { |
2657 | 0 | discovery_option = ogs_sbi_discovery_option_new(); |
2658 | 0 | ogs_assert(discovery_option); |
2659 | | |
2660 | | /* ALWAYS add Service-MAP to requester-features in Discovery Option */ |
2661 | 0 | OGS_SBI_FEATURES_SET(discovery_option->requester_features, |
2662 | 0 | OGS_SBI_NNRF_DISC_SERVICE_MAP); |
2663 | 0 | } |
2664 | | |
2665 | 0 | if (!discovery_option->num_of_service_names) { |
2666 | 0 | ogs_sbi_discovery_option_add_service_names( |
2667 | 0 | discovery_option, service_name); |
2668 | 0 | } |
2669 | 0 | xact->discovery_option = discovery_option; |
2670 | |
|
2671 | 0 | xact->t_response = ogs_timer_add( |
2672 | 0 | ogs_app()->timer_mgr, ogs_timer_sbi_client_wait_expire, |
2673 | 0 | OGS_UINT_TO_POINTER(xact->id)); |
2674 | 0 | if (!xact->t_response) { |
2675 | 0 | ogs_error("ogs_timer_add() failed"); |
2676 | |
|
2677 | 0 | if (xact->discovery_option) |
2678 | 0 | ogs_sbi_discovery_option_free(xact->discovery_option); |
2679 | 0 | ogs_pool_id_free(&xact_pool, xact); |
2680 | | |
2681 | 0 | return NULL; |
2682 | 0 | } |
2683 | | |
2684 | 0 | ogs_timer_start(xact->t_response, |
2685 | 0 | ogs_local_conf()->time.message.sbi.client_wait_duration); |
2686 | |
|
2687 | 0 | if (build) { |
2688 | 0 | xact->request = (*build)(context, data); |
2689 | 0 | if (!xact->request) { |
2690 | 0 | ogs_error("SBI build failed"); |
2691 | |
|
2692 | 0 | if (xact->discovery_option) |
2693 | 0 | ogs_sbi_discovery_option_free(xact->discovery_option); |
2694 | |
|
2695 | 0 | ogs_timer_delete(xact->t_response); |
2696 | 0 | ogs_pool_id_free(&xact_pool, xact); |
2697 | | |
2698 | 0 | return NULL; |
2699 | 0 | } |
2700 | 0 | if (!xact->request->h.uri) { |
2701 | 0 | const char *service_name = NULL; |
2702 | |
|
2703 | 0 | ogs_assert(xact->service_name); |
2704 | 0 | service_name = OpenAPI_service_name_ToString(xact->service_name); |
2705 | 0 | ogs_assert(service_name); |
2706 | 0 | ogs_assert(xact->request->h.service.name); |
2707 | | |
2708 | | /* |
2709 | | * Make sure the service matches |
2710 | | * between discover and build functions: |
2711 | | * |
2712 | | * DISCOVER : amf_ue_sbi_discover_and_send( |
2713 | | * OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL, |
2714 | | * BUILD : amf_npcf_am_policy_control_build_create() |
2715 | | * message.h.service.name = |
2716 | | * (char *)OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL; |
2717 | | */ |
2718 | | |
2719 | 0 | if (strcmp(service_name, xact->request->h.service.name) != 0) { |
2720 | 0 | ogs_fatal("[%s:%d] is not the same with [%s]", |
2721 | 0 | service_name, xact->service_name, |
2722 | 0 | xact->request->h.service.name); |
2723 | 0 | ogs_assert_if_reached(); |
2724 | 0 | } |
2725 | 0 | } |
2726 | 0 | } |
2727 | | |
2728 | 0 | ogs_list_add(&sbi_object->xact_list, xact); |
2729 | |
|
2730 | 0 | return xact; |
2731 | 0 | } |
2732 | | |
2733 | | void ogs_sbi_xact_remove(ogs_sbi_xact_t *xact) |
2734 | 0 | { |
2735 | 0 | ogs_sbi_object_t *sbi_object = NULL; |
2736 | |
|
2737 | 0 | ogs_assert(xact); |
2738 | | |
2739 | 0 | sbi_object = xact->sbi_object; |
2740 | 0 | ogs_assert(sbi_object); |
2741 | | |
2742 | 0 | if (xact->discovery_option) |
2743 | 0 | ogs_sbi_discovery_option_free(xact->discovery_option); |
2744 | |
|
2745 | 0 | ogs_assert(xact->t_response); |
2746 | 0 | ogs_timer_delete(xact->t_response); |
2747 | |
|
2748 | 0 | if (xact->request) |
2749 | 0 | ogs_sbi_request_free(xact->request); |
2750 | |
|
2751 | 0 | if (xact->target_apiroot) |
2752 | 0 | ogs_free(xact->target_apiroot); |
2753 | | |
2754 | | /* |
2755 | | * Release optional user context attached to the transaction. |
2756 | | * The transaction owns this memory and is responsible for |
2757 | | * freeing it when the transaction is destroyed. |
2758 | | */ |
2759 | 0 | if (xact->user_data) { |
2760 | 0 | if (xact->user_data_free) |
2761 | 0 | xact->user_data_free(xact->user_data); |
2762 | 0 | } |
2763 | |
|
2764 | 0 | ogs_list_remove(&sbi_object->xact_list, xact); |
2765 | 0 | ogs_pool_id_free(&xact_pool, xact); |
2766 | 0 | } |
2767 | | |
2768 | | void ogs_sbi_xact_remove_all(ogs_sbi_object_t *sbi_object) |
2769 | 0 | { |
2770 | 0 | ogs_sbi_xact_t *xact = NULL, *next_xact = NULL; |
2771 | |
|
2772 | 0 | ogs_assert(sbi_object); |
2773 | | |
2774 | 0 | ogs_list_for_each_safe(&sbi_object->xact_list, next_xact, xact) |
2775 | 0 | ogs_sbi_xact_remove(xact); |
2776 | 0 | } |
2777 | | |
2778 | | ogs_sbi_xact_t *ogs_sbi_xact_find_by_id(ogs_pool_id_t id) |
2779 | 0 | { |
2780 | 0 | return ogs_pool_find_by_id(&xact_pool, id); |
2781 | 0 | } |
2782 | | |
2783 | | ogs_sbi_subscription_spec_t *ogs_sbi_subscription_spec_add( |
2784 | | OpenAPI_nf_type_e nf_type, const OpenAPI_service_name_e service_name) |
2785 | 0 | { |
2786 | 0 | ogs_sbi_subscription_spec_t *subscription_spec = NULL; |
2787 | | |
2788 | | /* Issue #2630 : The format of subscrCond is invalid. Must be 'oneOf'. */ |
2789 | 0 | ogs_assert(!nf_type || !service_name); |
2790 | | |
2791 | 0 | ogs_pool_alloc(&subscription_spec_pool, &subscription_spec); |
2792 | 0 | ogs_assert(subscription_spec); |
2793 | 0 | memset(subscription_spec, 0, sizeof(ogs_sbi_subscription_spec_t)); |
2794 | |
|
2795 | 0 | if (nf_type) |
2796 | 0 | subscription_spec->subscr_cond.nf_type = nf_type; |
2797 | 0 | else if (service_name) |
2798 | 0 | subscription_spec->subscr_cond.service_name = service_name; |
2799 | 0 | else { |
2800 | 0 | ogs_fatal("SubscrCond must be 'oneOf'."); |
2801 | 0 | ogs_assert_if_reached(); |
2802 | 0 | } |
2803 | | |
2804 | 0 | ogs_list_add(&ogs_sbi_self()->subscription_spec_list, subscription_spec); |
2805 | |
|
2806 | 0 | return subscription_spec; |
2807 | 0 | } |
2808 | | |
2809 | | void ogs_sbi_subscription_spec_remove( |
2810 | | ogs_sbi_subscription_spec_t *subscription_spec) |
2811 | 0 | { |
2812 | 0 | ogs_assert(subscription_spec); |
2813 | | |
2814 | 0 | ogs_list_remove(&ogs_sbi_self()->subscription_spec_list, subscription_spec); |
2815 | |
|
2816 | 0 | ogs_pool_free(&subscription_spec_pool, subscription_spec); |
2817 | 0 | } |
2818 | | |
2819 | | void ogs_sbi_subscription_spec_remove_all(void) |
2820 | 0 | { |
2821 | 0 | ogs_sbi_subscription_spec_t *subscription_spec = NULL; |
2822 | 0 | ogs_sbi_subscription_spec_t *next_subscription_spec = NULL; |
2823 | |
|
2824 | 0 | ogs_list_for_each_safe(&ogs_sbi_self()->subscription_spec_list, |
2825 | 0 | next_subscription_spec, subscription_spec) |
2826 | 0 | ogs_sbi_subscription_spec_remove(subscription_spec); |
2827 | 0 | } |
2828 | | |
2829 | | ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_add(void) |
2830 | 0 | { |
2831 | 0 | ogs_sbi_subscription_data_t *subscription_data = NULL; |
2832 | |
|
2833 | 0 | ogs_pool_alloc(&subscription_data_pool, &subscription_data); |
2834 | 0 | if (!subscription_data) { |
2835 | 0 | ogs_error("OVERFLOW subscription_data_pool [pool:%llu]", |
2836 | 0 | (unsigned long long)ogs_app()->pool.subscription); |
2837 | 0 | return NULL; |
2838 | 0 | } |
2839 | | |
2840 | 0 | memset(subscription_data, 0, sizeof(ogs_sbi_subscription_data_t)); |
2841 | |
|
2842 | 0 | subscription_data->pool_id = OGS_NEXT_ID( |
2843 | 0 | subscription_data_pool.id, OGS_MIN_POOL_ID, OGS_MAX_POOL_ID); |
2844 | 0 | ogs_hash_set(subscription_data_pool.id_hash, |
2845 | 0 | &subscription_data->pool_id, sizeof(ogs_pool_id_t), |
2846 | 0 | subscription_data); |
2847 | |
|
2848 | 0 | ogs_list_add(&ogs_sbi_self()->subscription_data_list, subscription_data); |
2849 | |
|
2850 | 0 | return subscription_data; |
2851 | 0 | } |
2852 | | |
2853 | | void ogs_sbi_subscription_data_set_resource_uri( |
2854 | | ogs_sbi_subscription_data_t *subscription_data, char *resource_uri) |
2855 | 0 | { |
2856 | 0 | ogs_assert(subscription_data); |
2857 | 0 | ogs_assert(resource_uri); |
2858 | | |
2859 | 0 | if (subscription_data->resource_uri) |
2860 | 0 | ogs_free(subscription_data->resource_uri); |
2861 | 0 | subscription_data->resource_uri = ogs_strdup(resource_uri); |
2862 | 0 | ogs_assert(subscription_data->resource_uri); |
2863 | 0 | } |
2864 | | |
2865 | | void ogs_sbi_subscription_data_set_id( |
2866 | | ogs_sbi_subscription_data_t *subscription_data, char *id) |
2867 | 0 | { |
2868 | 0 | ogs_assert(subscription_data); |
2869 | 0 | ogs_assert(id); |
2870 | | |
2871 | 0 | if (subscription_data->id) |
2872 | 0 | ogs_free(subscription_data->id); |
2873 | 0 | subscription_data->id = ogs_strdup(id); |
2874 | 0 | ogs_assert(subscription_data->id); |
2875 | 0 | } |
2876 | | |
2877 | | void ogs_sbi_subscription_data_remove( |
2878 | | ogs_sbi_subscription_data_t *subscription_data) |
2879 | 0 | { |
2880 | 0 | ogs_assert(subscription_data); |
2881 | | |
2882 | 0 | ogs_list_remove(&ogs_sbi_self()->subscription_data_list, subscription_data); |
2883 | |
|
2884 | 0 | if (subscription_data->id) |
2885 | 0 | ogs_free(subscription_data->id); |
2886 | |
|
2887 | 0 | if (subscription_data->notification_uri) |
2888 | 0 | ogs_free(subscription_data->notification_uri); |
2889 | |
|
2890 | 0 | if (subscription_data->resource_uri) |
2891 | 0 | ogs_free(subscription_data->resource_uri); |
2892 | |
|
2893 | 0 | if (subscription_data->req_nf_instance_id) |
2894 | 0 | ogs_free(subscription_data->req_nf_instance_id); |
2895 | |
|
2896 | 0 | if (subscription_data->subscr_cond.nf_instance_id) |
2897 | 0 | ogs_free(subscription_data->subscr_cond.nf_instance_id); |
2898 | |
|
2899 | 0 | if (subscription_data->t_validity) |
2900 | 0 | ogs_timer_delete(subscription_data->t_validity); |
2901 | |
|
2902 | 0 | if (subscription_data->t_patch) |
2903 | 0 | ogs_timer_delete(subscription_data->t_patch); |
2904 | |
|
2905 | 0 | if (subscription_data->client) |
2906 | 0 | ogs_sbi_client_remove(subscription_data->client); |
2907 | |
|
2908 | 0 | ogs_hash_set(subscription_data_pool.id_hash, |
2909 | 0 | &subscription_data->pool_id, sizeof(ogs_pool_id_t), NULL); |
2910 | 0 | ogs_pool_free(&subscription_data_pool, subscription_data); |
2911 | 0 | } |
2912 | | |
2913 | | void ogs_sbi_subscription_data_remove_all_by_nf_instance_id( |
2914 | | char *nf_instance_id) |
2915 | 0 | { |
2916 | 0 | ogs_sbi_subscription_data_t *subscription_data = NULL; |
2917 | 0 | ogs_sbi_subscription_data_t *next_subscription_data = NULL; |
2918 | |
|
2919 | 0 | ogs_assert(nf_instance_id); |
2920 | | |
2921 | 0 | ogs_list_for_each_safe(&ogs_sbi_self()->subscription_data_list, |
2922 | 0 | next_subscription_data, subscription_data) { |
2923 | 0 | if (subscription_data->req_nf_instance_id && |
2924 | 0 | strcmp(subscription_data->req_nf_instance_id, |
2925 | 0 | nf_instance_id) == 0) { |
2926 | 0 | ogs_sbi_subscription_data_remove(subscription_data); |
2927 | 0 | } |
2928 | 0 | } |
2929 | 0 | } |
2930 | | |
2931 | | /* |
2932 | | * Send DELETE requests to NRF for all subscriptions belonging |
2933 | | * to the given NF instance before re-registration. |
2934 | | * |
2935 | | * This prevents subscription accumulation during repeated |
2936 | | * re-registration loops (e.g., heartbeat flapping). |
2937 | | * |
2938 | | * IMPORTANT: |
2939 | | * Local subscription_data MUST NOT be removed here. |
2940 | | * Cleanup is performed asynchronously in the unsubscribe |
2941 | | * response handler once NRF confirms deletion. |
2942 | | */ |
2943 | | void ogs_sbi_subscription_data_delete_and_remove_all_by_nf_instance_id( |
2944 | | const char *nf_instance_id) |
2945 | 0 | { |
2946 | 0 | ogs_sbi_subscription_data_t *subscription_data = NULL; |
2947 | |
|
2948 | 0 | ogs_assert(nf_instance_id); |
2949 | | |
2950 | 0 | ogs_list_for_each( |
2951 | 0 | &ogs_sbi_self()->subscription_data_list, subscription_data) { |
2952 | |
|
2953 | 0 | if (!subscription_data->id) { |
2954 | 0 | ogs_error("Skip subscription delete: id is NULL"); |
2955 | 0 | continue; |
2956 | 0 | } |
2957 | | |
2958 | 0 | if (!subscription_data->req_nf_instance_id) { |
2959 | 0 | ogs_error("Skip subscription delete: req_nf_instance_id is NULL"); |
2960 | 0 | continue; |
2961 | 0 | } |
2962 | | |
2963 | 0 | if (!subscription_data->resource_uri) { |
2964 | 0 | ogs_error("Skip subscription delete: resource_uri is NULL"); |
2965 | 0 | continue; |
2966 | 0 | } |
2967 | | |
2968 | 0 | if (strcmp(subscription_data->req_nf_instance_id, |
2969 | 0 | nf_instance_id) != 0) { |
2970 | 0 | ogs_error("Skip subscription delete: nf_instance_id mismatch " |
2971 | 0 | "[target:%s, current:%s]", |
2972 | 0 | subscription_data->req_nf_instance_id, nf_instance_id); |
2973 | 0 | continue; |
2974 | 0 | } |
2975 | | |
2976 | | /* |
2977 | | * Prevent duplicate DELETE transmissions. |
2978 | | * (Simple guard using existing state field or flag placeholder) |
2979 | | */ |
2980 | 0 | if (subscription_data->flags & OGS_SBI_SUBSCRIPTION_DELETE_SENT) { |
2981 | 0 | ogs_debug("[%s] Skip subscription delete: DELETE already sent", |
2982 | 0 | subscription_data->id); |
2983 | 0 | continue; |
2984 | 0 | } |
2985 | | |
2986 | 0 | subscription_data->flags |= OGS_SBI_SUBSCRIPTION_DELETE_SENT; |
2987 | | |
2988 | | /* |
2989 | | * If we have a subscription resource identifier, |
2990 | | * send DELETE to NRF to cleanup remote subscription state. |
2991 | | * |
2992 | | * Typical resource: |
2993 | | * /nnrf-nfm/v1/subscriptions/{subscriptionId} |
2994 | | */ |
2995 | 0 | ogs_info("[%s] Sending NRF subscription DELETE before " |
2996 | 0 | "NF re-registration", subscription_data->id); |
2997 | | |
2998 | | |
2999 | | /* Build DELETE request */ |
3000 | 0 | ogs_nnrf_nfm_send_nf_status_unsubscribe(subscription_data); |
3001 | | |
3002 | | /* |
3003 | | * NOTE: |
3004 | | * Do NOT remove subscription_data here. |
3005 | | * |
3006 | | * Local cleanup is performed in the unsubscribe |
3007 | | * response handler once NRF confirms deletion. |
3008 | | * |
3009 | | * Removing here could lead to: |
3010 | | * - Use-after-free |
3011 | | * - Double free |
3012 | | * - Dangling transaction context |
3013 | | */ |
3014 | 0 | } |
3015 | 0 | } |
3016 | | |
3017 | | void ogs_sbi_subscription_data_remove_all(void) |
3018 | 0 | { |
3019 | 0 | ogs_sbi_subscription_data_t *subscription_data = NULL; |
3020 | 0 | ogs_sbi_subscription_data_t *next_subscription_data = NULL; |
3021 | |
|
3022 | 0 | ogs_list_for_each_safe(&ogs_sbi_self()->subscription_data_list, |
3023 | 0 | next_subscription_data, subscription_data) |
3024 | 0 | ogs_sbi_subscription_data_remove(subscription_data); |
3025 | 0 | } |
3026 | | |
3027 | | ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_find(char *id) |
3028 | 0 | { |
3029 | 0 | ogs_sbi_subscription_data_t *subscription_data = NULL; |
3030 | |
|
3031 | 0 | ogs_assert(id); |
3032 | | |
3033 | 0 | ogs_list_for_each(&ogs_sbi_self()->subscription_data_list, |
3034 | 0 | subscription_data) { |
3035 | 0 | ogs_assert(subscription_data->id); |
3036 | 0 | if (strcmp(subscription_data->id, id) == 0) |
3037 | 0 | break; |
3038 | 0 | } |
3039 | | |
3040 | 0 | return subscription_data; |
3041 | 0 | } |
3042 | | |
3043 | | ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_find_by_pool_id( |
3044 | | ogs_pool_id_t id) |
3045 | 0 | { |
3046 | 0 | return ogs_pool_find_by_id(&subscription_data_pool, id); |
3047 | 0 | } |
3048 | | |
3049 | | bool ogs_sbi_nf_status_subscription_exists( |
3050 | | const char *req_nf_instance_id, |
3051 | | OpenAPI_nf_type_e nf_type, |
3052 | | OpenAPI_service_name_e service_name, |
3053 | | bool confirmed_only) |
3054 | 0 | { |
3055 | 0 | ogs_sbi_subscription_data_t *subscription_data = NULL; |
3056 | 0 | bool nf_type_present = (nf_type != OpenAPI_nf_type_NULL); |
3057 | 0 | bool service_name_present = (service_name != OpenAPI_service_name_NULL); |
3058 | |
|
3059 | 0 | ogs_assert(req_nf_instance_id); |
3060 | | |
3061 | 0 | ogs_list_for_each( |
3062 | 0 | &ogs_sbi_self()->subscription_data_list, subscription_data) { |
3063 | 0 | if (!subscription_data->req_nf_instance_id) |
3064 | 0 | continue; |
3065 | | |
3066 | 0 | if (strcmp(subscription_data->req_nf_instance_id, |
3067 | 0 | req_nf_instance_id) != 0) |
3068 | 0 | continue; |
3069 | | |
3070 | 0 | if (subscription_data->flags & OGS_SBI_SUBSCRIPTION_DELETE_SENT) |
3071 | 0 | continue; |
3072 | | |
3073 | | /* |
3074 | | * confirmed_only: count a subscription only after the NRF has accepted |
3075 | | * it, i.e. SubscriptionId and resource URI have been assigned from the |
3076 | | * 201 Created response. A locally pending request is not yet a valid |
3077 | | * notification context. |
3078 | | */ |
3079 | 0 | if (confirmed_only && |
3080 | 0 | (!subscription_data->id || !subscription_data->resource_uri)) |
3081 | 0 | continue; |
3082 | | |
3083 | 0 | if (nf_type_present && |
3084 | 0 | subscription_data->subscr_cond.nf_type != OpenAPI_nf_type_NULL && |
3085 | 0 | subscription_data->subscr_cond.nf_type == nf_type) |
3086 | 0 | return true; |
3087 | | |
3088 | 0 | if (service_name_present && |
3089 | 0 | subscription_data->subscr_cond.service_name != |
3090 | 0 | OpenAPI_service_name_NULL && |
3091 | 0 | subscription_data->subscr_cond.service_name == service_name) |
3092 | 0 | return true; |
3093 | 0 | } |
3094 | | |
3095 | 0 | return false; |
3096 | 0 | } |
3097 | | |
3098 | | bool ogs_sbi_supi_in_vplmn(char *supi) |
3099 | 0 | { |
3100 | 0 | char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; |
3101 | 0 | bool home_network = false; |
3102 | 0 | int i; |
3103 | |
|
3104 | 0 | ogs_assert(supi); |
3105 | | |
3106 | 0 | if (ogs_local_conf()->num_of_serving_plmn_id == 0) { |
3107 | 0 | return false; |
3108 | 0 | } |
3109 | | |
3110 | 0 | ogs_extract_digit_from_string(imsi_bcd, supi); |
3111 | |
|
3112 | 0 | for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { |
3113 | 0 | char buf[OGS_PLMNIDSTRLEN]; |
3114 | 0 | ogs_plmn_id_to_string(&ogs_local_conf()->serving_plmn_id[i], buf); |
3115 | |
|
3116 | 0 | if (strncmp(imsi_bcd, buf, strlen(buf)) == 0) { |
3117 | 0 | home_network = true; |
3118 | 0 | break; |
3119 | 0 | } |
3120 | 0 | } |
3121 | |
|
3122 | 0 | if (home_network == false) |
3123 | 0 | return true; |
3124 | | |
3125 | 0 | return false; |
3126 | 0 | } |
3127 | | |
3128 | | bool ogs_sbi_plmn_id_in_vplmn(ogs_plmn_id_t *plmn_id) |
3129 | 0 | { |
3130 | 0 | bool home_network = false; |
3131 | 0 | int i; |
3132 | |
|
3133 | 0 | ogs_assert(plmn_id); |
3134 | | |
3135 | 0 | if (ogs_local_conf()->num_of_serving_plmn_id == 0) { |
3136 | 0 | return false; |
3137 | 0 | } |
3138 | | |
3139 | 0 | if (ogs_plmn_id_mcc(plmn_id) == 0) { |
3140 | 0 | ogs_error("No MCC"); |
3141 | 0 | return false; |
3142 | 0 | } |
3143 | | |
3144 | 0 | if (ogs_plmn_id_mnc(plmn_id) == 0) { |
3145 | 0 | ogs_error("No MNC"); |
3146 | 0 | return false; |
3147 | 0 | } |
3148 | | |
3149 | 0 | for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { |
3150 | 0 | if (memcmp(&ogs_local_conf()->serving_plmn_id[i], |
3151 | 0 | plmn_id, OGS_PLMN_ID_LEN) == 0) { |
3152 | 0 | home_network = true; |
3153 | 0 | break; |
3154 | 0 | } |
3155 | 0 | } |
3156 | |
|
3157 | 0 | if (home_network == false) |
3158 | 0 | return true; |
3159 | | |
3160 | 0 | return false; |
3161 | 0 | } |
3162 | | |
3163 | | bool ogs_sbi_fqdn_in_vplmn(char *fqdn) |
3164 | 0 | { |
3165 | 0 | bool home_network = false; |
3166 | 0 | int i; |
3167 | |
|
3168 | 0 | ogs_assert(fqdn); |
3169 | | |
3170 | 0 | if (ogs_local_conf()->num_of_serving_plmn_id == 0) { |
3171 | 0 | return false; |
3172 | 0 | } |
3173 | | |
3174 | 0 | if (ogs_dnn_oi_from_fqdn(fqdn) == NULL) { |
3175 | 0 | return false; |
3176 | 0 | } |
3177 | | |
3178 | 0 | for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { |
3179 | 0 | if (ogs_plmn_id_mcc_from_fqdn(fqdn) == |
3180 | 0 | ogs_plmn_id_mcc(&ogs_local_conf()->serving_plmn_id[i]) && |
3181 | 0 | ogs_plmn_id_mnc_from_fqdn(fqdn) == |
3182 | 0 | ogs_plmn_id_mnc(&ogs_local_conf()->serving_plmn_id[i])) { |
3183 | 0 | home_network = true; |
3184 | 0 | break; |
3185 | 0 | } |
3186 | 0 | } |
3187 | |
|
3188 | 0 | if (home_network == false) |
3189 | 0 | return true; |
3190 | | |
3191 | 0 | return false; |
3192 | 0 | } |
3193 | | |
3194 | | /* OpenSSL Key Log Callback */ |
3195 | | void ogs_sbi_keylog_callback(const SSL *ssl, const char *line) |
3196 | 0 | { |
3197 | 0 | SSL_CTX *ctx = NULL; |
3198 | 0 | FILE *file = NULL; |
3199 | 0 | const char *sslkeylog_file = NULL; |
3200 | |
|
3201 | 0 | ogs_assert(ssl); |
3202 | 0 | ogs_assert(line); |
3203 | | |
3204 | | /* Retrieve SSL_CTX from SSL object */ |
3205 | 0 | ctx = SSL_get_SSL_CTX(ssl); |
3206 | 0 | ogs_assert(ctx); |
3207 | | |
3208 | 0 | sslkeylog_file = (const char *)SSL_CTX_get_app_data(ctx); |
3209 | 0 | ogs_assert(sslkeylog_file); |
3210 | | |
3211 | 0 | file = fopen(sslkeylog_file, "a"); |
3212 | 0 | if (file) { |
3213 | 0 | fprintf(file, "%s\n", line); |
3214 | 0 | fclose(file); |
3215 | 0 | } else { |
3216 | 0 | ogs_error("Failed to open SSL key log file: %s", sslkeylog_file); |
3217 | 0 | } |
3218 | 0 | } |