Coverage Report

Created: 2026-11-12 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/sbi/nnrf-handler.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019-2023 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
static void handle_nf_service(
23
        ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_service_t *NFService);
24
static bool handle_smf_info(
25
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_smf_info_t *SmfInfo);
26
static bool handle_scp_info(
27
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_scp_info_t *ScpInfo);
28
static bool handle_sepp_info(
29
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_sepp_info_t *SeppInfo);
30
static bool handle_amf_info(
31
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_amf_info_t *AmfInfo);
32
33
void ogs_nnrf_nfm_handle_nf_register(
34
        ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_message_t *recvmsg)
35
0
{
36
0
    OpenAPI_nf_profile_t *NFProfile = NULL;
37
0
    OpenAPI_lnode_t *node;
38
39
0
    ogs_assert(recvmsg);
40
0
    ogs_assert(nf_instance);
41
42
0
    NFProfile = recvmsg->NFProfile;
43
0
    if (!NFProfile) {
44
0
        ogs_error("No NFProfile");
45
0
        return;
46
0
    }
47
48
    /* TIME : Update heartbeat from NRF */
49
0
    if (NFProfile->is_heart_beat_timer == true)
50
0
        nf_instance->time.heartbeat_interval = NFProfile->heart_beat_timer;
51
52
0
    if (NFProfile->plmn_list) {
53
0
        ogs_local_conf()->num_of_serving_plmn_id = 0;
54
0
        OpenAPI_list_for_each(NFProfile->plmn_list, node) {
55
0
            OpenAPI_plmn_id_t *PlmnId = node->data;
56
0
            if (PlmnId) {
57
0
                if (ogs_local_conf()->num_of_serving_plmn_id >=
58
0
                        OGS_ARRAY_SIZE(ogs_local_conf()->serving_plmn_id)) {
59
0
                    ogs_error("OVERFLOW NFProfile->plmn_list [%d:%d:%d]",
60
0
                            ogs_local_conf()->num_of_serving_plmn_id,
61
0
                            OGS_MAX_NUM_OF_PLMN,
62
0
                            (int)OGS_ARRAY_SIZE(
63
0
                                ogs_local_conf()->serving_plmn_id));
64
0
                    break;
65
0
                }
66
0
                ogs_sbi_parse_plmn_id(
67
0
                    &ogs_local_conf()->serving_plmn_id[
68
0
                        ogs_local_conf()->num_of_serving_plmn_id], PlmnId);
69
0
                ogs_local_conf()->num_of_serving_plmn_id++;
70
0
            }
71
0
        }
72
0
    }
73
0
}
74
75
bool ogs_nnrf_nfm_handle_nf_profile(
76
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_profile_t *NFProfile)
77
0
{
78
0
    int rv;
79
0
    OpenAPI_lnode_t *node;
80
81
0
    ogs_assert(nf_instance);
82
0
    ogs_assert(NFProfile);
83
0
    ogs_assert(NFProfile->nf_instance_id);
84
0
    ogs_assert(NFProfile->nf_type);
85
0
    ogs_assert(NFProfile->nf_status);
86
87
0
    ogs_sbi_nf_instance_clear(nf_instance);
88
89
0
    nf_instance->nf_type = NFProfile->nf_type;
90
0
    nf_instance->nf_status = NFProfile->nf_status;
91
0
    if (NFProfile->is_heart_beat_timer == true)
92
0
        nf_instance->time.heartbeat_interval = NFProfile->heart_beat_timer;
93
94
0
    if (NFProfile->fqdn)
95
0
        nf_instance->fqdn = ogs_strdup(NFProfile->fqdn);
96
97
0
    if (NFProfile->is_priority == true)
98
0
        nf_instance->priority = NFProfile->priority;
99
0
    if (NFProfile->is_capacity == true)
100
0
        nf_instance->capacity = NFProfile->capacity;
101
0
    if (NFProfile->is_load == true)
102
0
        nf_instance->load = NFProfile->load;
103
104
0
    nf_instance->num_of_plmn_id = 0;
105
0
    OpenAPI_list_for_each(NFProfile->plmn_list, node) {
106
0
        OpenAPI_plmn_id_t *PlmnId = node->data;
107
0
        if (PlmnId) {
108
0
            if (nf_instance->num_of_plmn_id >=
109
0
                    OGS_ARRAY_SIZE(nf_instance->plmn_id)) {
110
0
                ogs_error("OVERFLOW NFProfile->plmn_list [%d:%d:%d]",
111
0
                        nf_instance->num_of_plmn_id, OGS_MAX_NUM_OF_PLMN,
112
0
                        (int)OGS_ARRAY_SIZE(nf_instance->plmn_id));
113
0
                break;
114
0
            }
115
0
            ogs_sbi_parse_plmn_id(
116
0
                &nf_instance->plmn_id[nf_instance->num_of_plmn_id], PlmnId);
117
0
            nf_instance->num_of_plmn_id++;
118
0
        }
119
0
    }
120
121
0
    OpenAPI_list_for_each(NFProfile->ipv4_addresses, node) {
122
0
        ogs_sockaddr_t *addr = NULL;
123
124
0
        if (!node->data) {
125
0
            ogs_error("No IPv4 Address");
126
0
            continue;
127
0
        }
128
129
0
        if (nf_instance->num_of_ipv4 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
130
131
0
            rv = ogs_getaddrinfo(
132
0
                    &addr, AF_UNSPEC,
133
0
                    node->data,
134
0
                    ogs_sbi_default_client_port(OpenAPI_uri_scheme_NULL), 0);
135
0
            if (rv != OGS_OK) {
136
0
                ogs_error("ogs_getaddrinfo[%s] failed", (char *)node->data);
137
0
                continue;
138
0
            }
139
140
0
            nf_instance->ipv4[nf_instance->num_of_ipv4] = addr;
141
0
            nf_instance->num_of_ipv4++;
142
0
        }
143
0
    }
144
0
    OpenAPI_list_for_each(NFProfile->ipv6_addresses, node) {
145
0
        ogs_sockaddr_t *addr = NULL;
146
147
0
        if (!node->data) {
148
0
            ogs_error("No IPv6 Address");
149
0
            continue;
150
0
        }
151
152
0
        if (nf_instance->num_of_ipv6 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
153
154
0
            rv = ogs_getaddrinfo(
155
0
                    &addr, AF_UNSPEC,
156
0
                    node->data,
157
0
                    ogs_sbi_default_client_port(OpenAPI_uri_scheme_NULL), 0);
158
0
            if (rv != OGS_OK) {
159
0
                ogs_error("ogs_getaddrinfo[%s] failed", (char *)node->data);
160
0
                continue;
161
0
            }
162
163
0
            nf_instance->ipv6[nf_instance->num_of_ipv6] = addr;
164
0
            nf_instance->num_of_ipv6++;
165
0
        }
166
0
    }
167
168
0
    OpenAPI_list_for_each(NFProfile->allowed_nf_types, node) {
169
0
        OpenAPI_nf_type_e AllowedNfType = (uintptr_t)node->data;
170
171
0
        if (!AllowedNfType) {
172
0
            ogs_error("AllowedNfType");
173
0
            continue;
174
0
        }
175
176
0
        if (nf_instance->num_of_allowed_nf_type <
177
0
                OGS_SBI_MAX_NUM_OF_NF_TYPE) {
178
0
            nf_instance->allowed_nf_type[
179
0
                nf_instance->num_of_allowed_nf_type] = AllowedNfType;
180
0
            nf_instance->num_of_allowed_nf_type++;
181
0
        }
182
0
    }
183
184
    /*
185
     * TS 33.518 4.2.2.2.1 - Store S-NSSAIs for slice-based discovery
186
     * authorization.  sNssais identifies the slices this NF serves;
187
     * allowedNssais restricts for which slices the NF may be discovered.
188
     */
189
0
    nf_instance->num_of_s_nssai = 0;
190
0
    OpenAPI_list_for_each(NFProfile->s_nssais, node) {
191
0
        OpenAPI_ext_snssai_t *sNssai = node->data;
192
0
        if (sNssai) {
193
0
            if (nf_instance->num_of_s_nssai >= OGS_MAX_NUM_OF_SLICE) {
194
0
                ogs_warn("Overflow: NFProfile.sNssais exceeds %d",
195
0
                        OGS_MAX_NUM_OF_SLICE);
196
0
                break;
197
0
            }
198
0
            nf_instance->s_nssai[nf_instance->num_of_s_nssai].sst =
199
0
                sNssai->sst;
200
0
            nf_instance->s_nssai[nf_instance->num_of_s_nssai].sd =
201
0
                ogs_s_nssai_sd_from_string(sNssai->sd);
202
0
            nf_instance->num_of_s_nssai++;
203
0
        }
204
0
    }
205
206
0
    nf_instance->num_of_allowed_nssai = 0;
207
0
    OpenAPI_list_for_each(NFProfile->allowed_nssais, node) {
208
0
        OpenAPI_ext_snssai_t *sNssai = node->data;
209
0
        if (sNssai) {
210
0
            if (nf_instance->num_of_allowed_nssai >= OGS_MAX_NUM_OF_SLICE) {
211
0
                ogs_warn("Overflow: NFProfile.allowedNssais exceeds %d",
212
0
                        OGS_MAX_NUM_OF_SLICE);
213
0
                break;
214
0
            }
215
0
            nf_instance->allowed_nssai[nf_instance->num_of_allowed_nssai].sst =
216
0
                sNssai->sst;
217
0
            nf_instance->allowed_nssai[nf_instance->num_of_allowed_nssai].sd =
218
0
                ogs_s_nssai_sd_from_string(sNssai->sd);
219
0
            nf_instance->num_of_allowed_nssai++;
220
0
        }
221
0
    }
222
223
0
    OpenAPI_list_for_each(NFProfile->nf_services, node) {
224
0
        ogs_sbi_nf_service_t *nf_service = NULL;
225
0
        OpenAPI_nf_service_t *NFService = node->data;
226
227
0
        if (!NFService) {
228
0
            ogs_error("No NFService");
229
0
            continue;
230
0
        }
231
232
0
        if (!NFService->service_instance_id) {
233
0
            ogs_error("No NFService.service_instance_id");
234
0
            continue;
235
0
        }
236
237
0
        if (!NFService->service_name) {
238
0
            ogs_error("No NFService.service_name");
239
0
            continue;
240
0
        }
241
242
0
        if (!NFService->scheme) {
243
0
            ogs_error("No NFService.scheme");
244
0
            continue;
245
0
        }
246
247
0
        nf_service = ogs_sbi_nf_service_find_by_id(
248
0
                        nf_instance, NFService->service_instance_id);
249
0
        if (!nf_service) {
250
0
            nf_service = ogs_sbi_nf_service_add(
251
0
                            nf_instance,
252
0
                            NFService->service_instance_id,
253
0
                            NFService->service_name, NFService->scheme);
254
0
            if (!nf_service) {
255
0
                ogs_error("Failed to add NFService [%s]",
256
0
                        NFService->service_instance_id);
257
0
                return false;
258
0
            }
259
0
        }
260
261
0
        ogs_sbi_nf_service_clear(nf_service);
262
263
0
        handle_nf_service(nf_service, NFService);
264
0
    }
265
266
0
    OpenAPI_list_for_each(NFProfile->nf_service_list, node) {
267
0
        ogs_sbi_nf_service_t *nf_service = NULL;
268
0
        OpenAPI_map_t *NFServiceMap = NULL;
269
0
        OpenAPI_nf_service_t *NFService = node->data;
270
271
0
        NFServiceMap = node->data;
272
0
        if (NFServiceMap) {
273
0
            NFService = NFServiceMap->value;
274
0
            if (!NFService) {
275
0
                ogs_error("No NFService");
276
0
                continue;
277
0
            }
278
279
0
            if (!NFService->service_instance_id) {
280
0
                ogs_error("No NFService.service_instance_id");
281
0
                continue;
282
0
            }
283
284
0
            if (!NFService->service_name) {
285
0
                ogs_error("No NFService.service_name");
286
0
                continue;
287
0
            }
288
289
0
            if (!NFService->scheme) {
290
0
                ogs_error("No NFService.scheme");
291
0
                continue;
292
0
            }
293
294
0
            nf_service = ogs_sbi_nf_service_find_by_id(
295
0
                            nf_instance, NFService->service_instance_id);
296
0
            if (!nf_service) {
297
0
                nf_service = ogs_sbi_nf_service_add(
298
0
                                nf_instance,
299
0
                                NFService->service_instance_id,
300
0
                                NFService->service_name, NFService->scheme);
301
0
                if (!nf_service) {
302
0
                    ogs_error("Failed to add NFService [%s]",
303
0
                            NFService->service_instance_id);
304
0
                    return false;
305
0
                }
306
0
            }
307
308
0
            ogs_sbi_nf_service_clear(nf_service);
309
310
0
            handle_nf_service(nf_service, NFService);
311
0
        }
312
0
    }
313
314
0
    ogs_sbi_nf_info_remove_all(&nf_instance->nf_info_list);
315
316
0
    if (NFProfile->smf_info &&
317
0
            handle_smf_info(nf_instance, NFProfile->smf_info) == false)
318
0
        return false;
319
320
0
    OpenAPI_list_for_each(NFProfile->smf_info_list, node) {
321
0
        OpenAPI_map_t *SmfInfoMap = node->data;
322
0
        if (SmfInfoMap && SmfInfoMap->value &&
323
0
                handle_smf_info(nf_instance, SmfInfoMap->value) == false)
324
0
            return false;
325
0
    }
326
0
    if (NFProfile->amf_info &&
327
0
            handle_amf_info(nf_instance, NFProfile->amf_info) == false)
328
0
        return false;
329
330
0
    OpenAPI_list_for_each(NFProfile->amf_info_list, node) {
331
0
        OpenAPI_map_t *AmfInfoMap = node->data;
332
0
        if (AmfInfoMap && AmfInfoMap->value &&
333
0
                handle_amf_info(nf_instance, AmfInfoMap->value) == false)
334
0
            return false;
335
0
    }
336
0
    if (NFProfile->scp_info &&
337
0
            handle_scp_info(nf_instance, NFProfile->scp_info) == false)
338
0
        return false;
339
0
    if (NFProfile->sepp_info &&
340
0
            handle_sepp_info(nf_instance, NFProfile->sepp_info) == false)
341
0
        return false;
342
343
0
    return true;
344
0
}
345
346
static void handle_nf_service(
347
        ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_service_t *NFService)
348
0
{
349
0
    int rv;
350
0
    OpenAPI_lnode_t *node = NULL;
351
352
0
    ogs_assert(nf_service);
353
0
    ogs_assert(NFService);
354
355
0
    OpenAPI_list_for_each(NFService->versions, node) {
356
0
        OpenAPI_nf_service_version_t *NFServiceVersion = node->data;
357
358
0
        if (!NFServiceVersion) {
359
0
            ogs_error("No NFServiceVersion");
360
0
            continue;
361
0
        }
362
363
0
        ogs_sbi_nf_service_add_version(nf_service,
364
0
                    NFServiceVersion->api_version_in_uri,
365
0
                    NFServiceVersion->api_full_version,
366
0
                    NFServiceVersion->expiry);
367
0
    }
368
369
0
    if (NFService->fqdn)
370
0
        nf_service->fqdn = ogs_strdup(NFService->fqdn);
371
372
0
    OpenAPI_list_for_each(NFService->ip_end_points, node) {
373
0
        OpenAPI_ip_end_point_t *IpEndPoint = node->data;
374
0
        ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
375
0
        int port = 0;
376
377
0
        if (!IpEndPoint) {
378
0
            ogs_error("No IpEndPoint");
379
0
            continue;
380
0
        }
381
382
0
        if (nf_service->num_of_addr < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
383
0
            if (!IpEndPoint->is_port)
384
0
                port = ogs_sbi_default_client_port(nf_service->scheme);
385
0
            else
386
0
                port = IpEndPoint->port;
387
388
0
            if (IpEndPoint->ipv4_address) {
389
0
                rv = ogs_getaddrinfo(&addr, AF_UNSPEC,
390
0
                        IpEndPoint->ipv4_address, port, 0);
391
0
                if (rv != OGS_OK) {
392
0
                    ogs_error("ogs_getaddrinfo[%s] failed",
393
0
                                IpEndPoint->ipv4_address);
394
0
                    continue;
395
0
                }
396
0
            }
397
0
            if (IpEndPoint->ipv6_address) {
398
0
                rv = ogs_getaddrinfo(&addr6, AF_UNSPEC,
399
0
                        IpEndPoint->ipv6_address, port, 0);
400
0
                if (rv != OGS_OK) {
401
0
                    ogs_error("ogs_getaddrinfo[%s] failed",
402
0
                                IpEndPoint->ipv6_address);
403
0
                    continue;
404
0
                }
405
0
            }
406
407
0
            if (addr || addr6) {
408
0
                nf_service->addr[nf_service->num_of_addr].
409
0
                    is_port = IpEndPoint->is_port;
410
0
                nf_service->addr[nf_service->num_of_addr].
411
0
                    port = port;
412
0
                nf_service->addr[nf_service->num_of_addr].
413
0
                    ipv4 = addr;
414
0
                nf_service->addr[nf_service->num_of_addr].
415
0
                    ipv6 = addr6;
416
0
                nf_service->num_of_addr++;
417
0
            }
418
0
        }
419
0
    }
420
421
0
    OpenAPI_list_for_each(NFService->allowed_nf_types, node) {
422
0
        OpenAPI_nf_type_e AllowedNfType = (uintptr_t)node->data;
423
424
0
        if (!AllowedNfType) {
425
0
            ogs_error("AllowedNfType");
426
0
            continue;
427
0
        }
428
429
0
        if (nf_service->num_of_allowed_nf_type <
430
0
                OGS_SBI_MAX_NUM_OF_NF_TYPE) {
431
0
            nf_service->allowed_nf_type[
432
0
                nf_service->num_of_allowed_nf_type] = AllowedNfType;
433
0
            nf_service->num_of_allowed_nf_type++;
434
0
        }
435
0
    }
436
437
0
    if (NFService->is_priority == true)
438
0
        nf_service->priority = NFService->priority;
439
0
    if (NFService->is_capacity == true)
440
0
        nf_service->capacity = NFService->capacity;
441
0
    if (NFService->is_load == true)
442
0
        nf_service->load = NFService->load;
443
0
}
444
445
static bool handle_smf_info(
446
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_smf_info_t *SmfInfo)
447
0
{
448
0
    bool rv = true;
449
0
    ogs_sbi_nf_info_t *nf_info = NULL;
450
451
0
    OpenAPI_list_t *sNssaiSmfInfoList = NULL;
452
0
    OpenAPI_snssai_smf_info_item_t *sNssaiSmfInfoItem = NULL;
453
0
    OpenAPI_ext_snssai_t *sNssai = NULL;
454
0
    OpenAPI_list_t *DnnSmfInfoList = NULL;
455
0
    OpenAPI_dnn_smf_info_item_t *DnnSmfInfoItem = NULL;
456
457
0
    OpenAPI_list_t *TaiList = NULL;
458
0
    OpenAPI_tai_t *TaiItem = NULL;
459
0
    OpenAPI_list_t *TaiRangeList = NULL;
460
0
    OpenAPI_tai_range_t *TaiRangeItem = NULL;
461
0
    OpenAPI_list_t *TacRangeList = NULL;
462
0
    OpenAPI_tac_range_t *TacRangeItem = NULL;
463
464
0
    OpenAPI_lnode_t *node = NULL, *node2 = NULL;
465
466
0
    ogs_assert(nf_instance);
467
0
    ogs_assert(SmfInfo);
468
469
0
    nf_info = ogs_sbi_nf_info_add(
470
0
            &nf_instance->nf_info_list, OpenAPI_nf_type_SMF);
471
0
    if (!nf_info) {
472
0
        ogs_error("Failed to add SMF nfInfo");
473
0
        return false;
474
0
    }
475
476
0
    sNssaiSmfInfoList = SmfInfo->s_nssai_smf_info_list;
477
0
    OpenAPI_list_for_each(sNssaiSmfInfoList, node) {
478
0
        sNssaiSmfInfoItem = node->data;
479
0
        if (sNssaiSmfInfoItem) {
480
0
            if (nf_info->smf.num_of_slice >= OGS_MAX_NUM_OF_SLICE) {
481
0
                ogs_error("OVERFLOW Slice [%d:%d]",
482
0
                        nf_info->smf.num_of_slice, OGS_MAX_NUM_OF_SLICE);
483
0
                rv = false;
484
0
                break;
485
0
            }
486
487
0
            DnnSmfInfoList = sNssaiSmfInfoItem->dnn_smf_info_list;
488
0
            OpenAPI_list_for_each(DnnSmfInfoList, node2) {
489
0
                DnnSmfInfoItem = node2->data;
490
0
                if (DnnSmfInfoItem && DnnSmfInfoItem->dnn) {
491
0
                    int dnn_index = nf_info->smf.slice
492
0
                        [nf_info->smf.num_of_slice].num_of_dnn;
493
494
0
                    if (dnn_index >= OGS_MAX_NUM_OF_DNN) {
495
0
                        ogs_error("OVERFLOW DNN [%d:%d]",
496
0
                                dnn_index, OGS_MAX_NUM_OF_DNN);
497
0
                        rv = false;
498
0
                        break;
499
0
                    }
500
0
                    nf_info->smf.slice[nf_info->smf.num_of_slice].
501
0
                        dnn[dnn_index] = ogs_strdup(DnnSmfInfoItem->dnn);
502
0
                    if (!nf_info->smf.slice[nf_info->smf.num_of_slice].
503
0
                            dnn[dnn_index]) {
504
0
                        ogs_error("No memory for DNN");
505
0
                        rv = false;
506
0
                        break;
507
0
                    }
508
0
                    nf_info->smf.slice[nf_info->smf.num_of_slice].
509
0
                        num_of_dnn++;
510
0
                }
511
0
            }
512
513
0
            if (rv == false)
514
0
                break;
515
516
0
            if (!nf_info->smf.slice[nf_info->smf.num_of_slice].num_of_dnn) {
517
0
                ogs_error("No DNN");
518
0
                continue;
519
0
            }
520
521
0
            sNssai = sNssaiSmfInfoItem->s_nssai;
522
0
            if (sNssai) {
523
0
                ogs_s_nssai_t *s_nssai = NULL;
524
525
0
                s_nssai = &nf_info->smf.
526
0
                    slice[nf_info->smf.num_of_slice].s_nssai;
527
0
                s_nssai->sst = sNssai->sst;
528
0
                s_nssai->sd = ogs_s_nssai_sd_from_string(sNssai->sd);
529
0
                nf_info->smf.num_of_slice++;
530
0
            }
531
0
        }
532
0
    }
533
534
0
    if (rv == false) goto out;
535
536
0
    if (nf_info->smf.num_of_slice == 0) {
537
0
        ogs_error("No S-NSSAI(DNN) in smfInfo");
538
0
        ogs_sbi_nf_info_remove(&nf_instance->nf_info_list, nf_info);
539
0
        return true;
540
0
    }
541
542
0
    TaiList = SmfInfo->tai_list;
543
0
    OpenAPI_list_for_each(TaiList, node) {
544
0
        TaiItem = node->data;
545
0
        if (TaiItem && TaiItem->plmn_id && TaiItem->tac) {
546
0
            ogs_5gs_tai_t *nr_tai = NULL;
547
0
            if (nf_info->smf.num_of_nr_tai >= OGS_MAX_NUM_OF_TAI) {
548
0
                ogs_error("OVERFLOW TAI [%d:%d]",
549
0
                        nf_info->smf.num_of_nr_tai, OGS_MAX_NUM_OF_TAI);
550
0
                rv = false;
551
0
                break;
552
0
            }
553
554
0
            nr_tai = &nf_info->smf.nr_tai[nf_info->smf.num_of_nr_tai];
555
0
            ogs_assert(nr_tai);
556
0
            ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id);
557
0
            nr_tai->tac = ogs_uint24_from_string_hexadecimal(TaiItem->tac);
558
559
0
            nf_info->smf.num_of_nr_tai++;
560
0
        }
561
0
    }
562
563
0
    if (rv == false) goto out;
564
565
0
    TaiRangeList = SmfInfo->tai_range_list;
566
0
    OpenAPI_list_for_each(TaiRangeList, node) {
567
0
        TaiRangeItem = node->data;
568
0
        if (TaiRangeItem && TaiRangeItem->plmn_id &&
569
0
                TaiRangeItem->tac_range_list) {
570
571
0
            if (nf_info->smf.num_of_nr_tai_range >= OGS_MAX_NUM_OF_TAI) {
572
0
                ogs_error("OVERFLOW TaiRangeItem [%d:%d]",
573
0
                        nf_info->smf.num_of_nr_tai_range, OGS_MAX_NUM_OF_TAI);
574
0
                rv = false;
575
0
                break;
576
0
            }
577
578
0
            ogs_sbi_parse_plmn_id(
579
0
                &nf_info->smf.nr_tai_range
580
0
                    [nf_info->smf.num_of_nr_tai_range].plmn_id,
581
0
                TaiRangeItem->plmn_id);
582
583
0
            TacRangeList = TaiRangeItem->tac_range_list;
584
0
            OpenAPI_list_for_each(TacRangeList, node2) {
585
0
                TacRangeItem = node2->data;
586
0
                if (TacRangeItem &&
587
0
                        TacRangeItem->start && TacRangeItem->end) {
588
0
                    int tac_index = nf_info->smf.nr_tai_range
589
0
                        [nf_info->smf.num_of_nr_tai_range].num_of_tac_range;
590
0
                    if (tac_index >= OGS_MAX_NUM_OF_TAI) {
591
0
                        ogs_error("OVERFLOW TAI [%d:%d]",
592
0
                                tac_index, OGS_MAX_NUM_OF_TAI);
593
0
                        rv = false;
594
0
                        break;
595
0
                    }
596
597
0
                    nf_info->smf.nr_tai_range
598
0
                        [nf_info->smf.num_of_nr_tai_range].
599
0
                            start[tac_index] =
600
0
                                ogs_uint24_from_string_hexadecimal(
601
0
                                        TacRangeItem->start);
602
0
                    nf_info->smf.nr_tai_range
603
0
                        [nf_info->smf.num_of_nr_tai_range].
604
0
                            end[tac_index] =
605
0
                                ogs_uint24_from_string_hexadecimal(
606
0
                                        TacRangeItem->end);
607
608
0
                    nf_info->smf.nr_tai_range
609
0
                        [nf_info->smf.num_of_nr_tai_range].
610
0
                            num_of_tac_range++;
611
0
                }
612
0
            }
613
614
0
            if (rv == false)
615
0
                break;
616
617
0
            nf_info->smf.num_of_nr_tai_range++;
618
0
        }
619
0
    }
620
621
0
out:
622
0
    if (rv == false) {
623
0
        ogs_sbi_nf_info_remove(&nf_instance->nf_info_list, nf_info);
624
0
        return false;
625
0
    }
626
627
0
    return true;
628
0
}
629
630
static void scp_info_free(ogs_sbi_scp_info_t *scp_info)
631
0
{
632
0
    int i;
633
634
0
    ogs_assert(scp_info);
635
636
0
    for (i = 0; i < scp_info->num_of_domain; i++) {
637
0
        ogs_free(scp_info->domain[i].name);
638
0
        ogs_free(scp_info->domain[i].fqdn);
639
0
    }
640
0
    memset(scp_info, 0, sizeof(*scp_info));
641
0
}
642
643
static bool handle_scp_info(
644
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_scp_info_t *ScpInfo)
645
0
{
646
0
    ogs_sbi_nf_info_t *nf_info = NULL;
647
648
0
    OpenAPI_list_t *PortList = NULL;
649
0
    OpenAPI_map_t *PortMap = NULL;
650
651
0
    OpenAPI_map_t *DomainInfoMap = NULL;
652
0
    OpenAPI_scp_domain_info_t *DomainInfo = NULL;
653
654
0
    OpenAPI_lnode_t *node = NULL, *node2 = NULL;
655
656
0
    ogs_sbi_scp_info_t scp_info;
657
658
0
    ogs_assert(nf_instance);
659
0
    ogs_assert(ScpInfo);
660
661
0
    memset(&scp_info, 0, sizeof(scp_info));
662
663
0
    PortList = ScpInfo->scp_ports;
664
0
    OpenAPI_list_for_each(PortList, node) {
665
0
        PortMap = node->data;
666
0
        if (PortMap) {
667
0
            if (PortMap->key) {
668
0
                double *port = PortMap->value;
669
0
                if (strcmp(PortMap->key, "http") == 0) {
670
0
                    if (port) {
671
0
                        scp_info.http.presence = true;
672
0
                        scp_info.http.port = *port;
673
0
                    } else {
674
0
                        ogs_error("No Port Value");
675
0
                    }
676
0
                } else if (strcmp(PortMap->key, "https") == 0) {
677
0
                    if (port) {
678
0
                        scp_info.https.presence = true;
679
0
                        scp_info.https.port = *port;
680
0
                    } else {
681
0
                        ogs_error("No Port Value");
682
0
                    }
683
0
                } else {
684
0
                    ogs_error("Unknown Port Key = %s", PortMap->key);
685
0
                }
686
0
            }
687
0
        }
688
0
    }
689
690
0
    OpenAPI_list_for_each(ScpInfo->scp_domain_info_list, node) {
691
0
        DomainInfoMap = node->data;
692
0
        if (DomainInfoMap && DomainInfoMap->key && DomainInfoMap->value) {
693
0
            if (scp_info.num_of_domain >= OGS_MAX_NUM_OF_SCP_DOMAIN) {
694
0
                ogs_warn("Exceeded maximum SCP domains (%d)",
695
0
                        OGS_MAX_NUM_OF_SCP_DOMAIN);
696
0
                break;
697
0
            }
698
0
            scp_info.domain[scp_info.num_of_domain].name =
699
0
                ogs_strdup(DomainInfoMap->key);
700
0
            DomainInfo = DomainInfoMap->value;
701
0
            if (DomainInfo->scp_fqdn)
702
0
                scp_info.domain[scp_info.num_of_domain].fqdn =
703
0
                    ogs_strdup(DomainInfo->scp_fqdn);
704
0
            OpenAPI_list_for_each(DomainInfo->scp_ports, node2) {
705
0
                PortMap = node2->data;
706
0
                if (PortMap) {
707
0
                    if (PortMap->key) {
708
0
                        double *port = PortMap->value;
709
0
                        if (strcmp(PortMap->key, "http") == 0) {
710
0
                            if (port) {
711
0
                                scp_info.domain[scp_info.num_of_domain].
712
0
                                    http.presence = true;
713
0
                                scp_info.domain[scp_info.num_of_domain].
714
0
                                    http.port = *port;
715
0
                            } else {
716
0
                                ogs_error("No Port Value");
717
0
                            }
718
0
                        } else if (strcmp(PortMap->key, "https") == 0) {
719
0
                            if (port) {
720
0
                                scp_info.domain[scp_info.num_of_domain].
721
0
                                    https.presence = true;
722
0
                                scp_info.domain[scp_info.num_of_domain].
723
0
                                    https.port = *port;
724
0
                            } else {
725
0
                                ogs_error("No Port Value");
726
0
                            }
727
0
                        } else {
728
0
                            ogs_error("Unknown Port Key = %s", PortMap->key);
729
0
                        }
730
0
                    }
731
0
                }
732
0
            }
733
0
            scp_info.num_of_domain++;
734
0
        }
735
0
    }
736
737
0
    if (scp_info.http.presence || scp_info.https.presence ||
738
0
        scp_info.num_of_domain) {
739
0
        nf_info = ogs_sbi_nf_info_add(
740
0
                &nf_instance->nf_info_list, OpenAPI_nf_type_SCP);
741
0
        if (!nf_info) {
742
0
            ogs_error("Failed to add SCP nfInfo");
743
0
            scp_info_free(&scp_info);
744
0
            return false;
745
0
        }
746
747
0
        memcpy(&nf_info->scp, &scp_info, sizeof(scp_info));
748
0
    }
749
750
0
    return true;
751
0
}
752
753
static bool handle_sepp_info(
754
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_sepp_info_t *SeppInfo)
755
0
{
756
0
    ogs_sbi_nf_info_t *nf_info = NULL;
757
758
0
    OpenAPI_list_t *PortList = NULL;
759
0
    OpenAPI_map_t *PortMap = NULL;
760
761
0
    OpenAPI_lnode_t *node = NULL;
762
763
0
    ogs_port_t http, https;
764
765
0
    ogs_assert(nf_instance);
766
0
    ogs_assert(SeppInfo);
767
768
0
    http.port = 0;
769
0
    https.port = 0;
770
0
    http.presence = false;
771
0
    https.presence = false;
772
773
0
    PortList = SeppInfo->sepp_ports;
774
0
    OpenAPI_list_for_each(PortList, node) {
775
0
        PortMap = node->data;
776
0
        if (PortMap) {
777
0
            if (PortMap->key) {
778
0
                double *port = PortMap->value;
779
0
                if (strcmp(PortMap->key, "http") == 0) {
780
0
                    if (port) {
781
0
                        http.presence = true;
782
0
                        http.port = *port;
783
0
                    } else {
784
0
                        ogs_error("No Port Value");
785
0
                    }
786
0
                } else if (strcmp(PortMap->key, "https") == 0) {
787
0
                    if (port) {
788
0
                        https.presence = true;
789
0
                        https.port = *port;
790
0
                    } else {
791
0
                        ogs_error("No Port Value");
792
0
                    }
793
0
                } else {
794
0
                    ogs_error("Unknown Port Key = %s", PortMap->key);
795
0
                }
796
0
            }
797
0
        }
798
0
    }
799
800
0
    if (http.presence || https.presence) {
801
0
        nf_info = ogs_sbi_nf_info_add(
802
0
                &nf_instance->nf_info_list, OpenAPI_nf_type_SEPP);
803
0
        if (!nf_info) {
804
0
            ogs_error("Failed to add SEPP nfInfo");
805
0
            return false;
806
0
        }
807
808
0
        nf_info->sepp.http.presence = http.presence;
809
0
        nf_info->sepp.http.port = http.port;
810
811
0
        nf_info->sepp.https.presence = https.presence;
812
0
        nf_info->sepp.https.port = https.port;
813
0
    }
814
815
0
    return true;
816
0
}
817
818
static bool handle_amf_info(
819
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_amf_info_t *AmfInfo)
820
0
{
821
0
    bool rv = true;
822
0
    ogs_sbi_nf_info_t *nf_info = NULL;
823
0
    OpenAPI_list_t *GuamiList = NULL;
824
0
    OpenAPI_guami_t *GuamiAmfInfoItem = NULL;
825
0
    OpenAPI_list_t *TaiList = NULL;
826
0
    OpenAPI_tai_t *TaiItem = NULL;
827
0
    OpenAPI_list_t *TaiRangeList = NULL;
828
0
    OpenAPI_tai_range_t *TaiRangeItem = NULL;
829
0
    OpenAPI_list_t *TacRangeList = NULL;
830
0
    OpenAPI_tac_range_t *TacRangeItem = NULL;
831
0
    OpenAPI_lnode_t *node = NULL, *node2 = NULL;
832
833
0
    ogs_assert(nf_instance);
834
0
    ogs_assert(AmfInfo);
835
836
0
    nf_info = ogs_sbi_nf_info_add(
837
0
            &nf_instance->nf_info_list, OpenAPI_nf_type_AMF);
838
0
    if (!nf_info) {
839
0
        ogs_error("Failed to add AMF nfInfo");
840
0
        return false;
841
0
    }
842
843
0
    nf_info->amf.amf_set_id = ogs_uint64_from_string_hexadecimal(
844
0
            AmfInfo->amf_set_id);
845
0
    nf_info->amf.amf_region_id = ogs_uint64_from_string_hexadecimal(
846
0
            AmfInfo->amf_region_id);
847
848
0
    GuamiList = AmfInfo->guami_list;
849
0
    OpenAPI_list_for_each(GuamiList, node) {
850
0
        GuamiAmfInfoItem = node->data;
851
0
        if (GuamiAmfInfoItem) {
852
0
            if (nf_info->amf.num_of_guami >= OGS_MAX_NUM_OF_SERVED_GUAMI) {
853
0
                ogs_error("OVERFLOW Guami [%d:%d]",
854
0
                        nf_info->amf.num_of_guami, OGS_MAX_NUM_OF_SERVED_GUAMI);
855
0
                rv = false;
856
0
                break;
857
0
            }
858
859
0
            if (GuamiAmfInfoItem->amf_id && GuamiAmfInfoItem->plmn_id &&
860
0
                    GuamiAmfInfoItem->plmn_id->mnc &&
861
0
                    GuamiAmfInfoItem->plmn_id->mcc) {
862
863
0
                if (!ogs_sbi_parse_guami(
864
0
                        &nf_info->amf.guami[nf_info->amf.num_of_guami],
865
0
                        GuamiAmfInfoItem)) {
866
0
                    ogs_error("[%s] Invalid GUAMI in AMF NF profile",
867
0
                            nf_instance->id);
868
0
                    rv = false;
869
0
                    break;
870
0
                }
871
0
                nf_info->amf.num_of_guami++;
872
0
            }
873
0
        }
874
0
    }
875
0
    if (rv == false) goto out;
876
877
0
    TaiList = AmfInfo->tai_list;
878
0
    OpenAPI_list_for_each(TaiList, node) {
879
0
        TaiItem = node->data;
880
0
        if (TaiItem && TaiItem->plmn_id && TaiItem->tac) {
881
0
            ogs_5gs_tai_t *nr_tai = NULL;
882
883
0
            if (nf_info->amf.num_of_nr_tai >= OGS_MAX_NUM_OF_TAI) {
884
0
                ogs_error("OVERFLOW TaiItem [%d:%d]",
885
0
                        nf_info->amf.num_of_nr_tai, OGS_MAX_NUM_OF_TAI);
886
0
                rv = false;
887
0
                break;
888
0
            }
889
890
0
            nr_tai = &nf_info->amf.nr_tai[nf_info->amf.num_of_nr_tai];
891
892
0
            ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id);
893
0
            nr_tai->tac = ogs_uint24_from_string_hexadecimal(TaiItem->tac);
894
0
            nf_info->amf.num_of_nr_tai++;
895
0
        }
896
0
    }
897
0
    if (rv == false) goto out;
898
899
0
    TaiRangeList = AmfInfo->tai_range_list;
900
0
    OpenAPI_list_for_each(TaiRangeList, node) {
901
0
        TaiRangeItem = node->data;
902
0
        if (TaiRangeItem && TaiRangeItem->plmn_id &&
903
0
                TaiRangeItem->tac_range_list) {
904
0
            if (nf_info->amf.num_of_nr_tai_range >= OGS_MAX_NUM_OF_TAI) {
905
0
                ogs_error("OVERFLOW TaiRangeItem [%d:%d]",
906
0
                        nf_info->amf.num_of_nr_tai_range, OGS_MAX_NUM_OF_TAI);
907
0
                rv = false;
908
0
                break;
909
0
            }
910
911
0
            ogs_sbi_parse_plmn_id(
912
0
                &nf_info->amf.nr_tai_range
913
0
                    [nf_info->amf.num_of_nr_tai_range].plmn_id,
914
0
                TaiRangeItem->plmn_id);
915
916
0
            TacRangeList = TaiRangeItem->tac_range_list;
917
0
            OpenAPI_list_for_each(TacRangeList, node2) {
918
0
                TacRangeItem = node2->data;
919
0
                if (TacRangeItem &&
920
0
                        TacRangeItem->start && TacRangeItem->end) {
921
0
                    int tac_index = nf_info->amf.nr_tai_range
922
0
                        [nf_info->amf.num_of_nr_tai_range].num_of_tac_range;
923
0
                    if (tac_index >= OGS_MAX_NUM_OF_TAI) {
924
0
                        ogs_error("OVERFLOW TAI [%d:%d]",
925
0
                                tac_index, OGS_MAX_NUM_OF_TAI);
926
0
                        rv = false;
927
0
                        break;
928
0
                    }
929
930
0
                    nf_info->amf.nr_tai_range
931
0
                        [nf_info->amf.num_of_nr_tai_range].start[tac_index] =
932
0
                                ogs_uint24_from_string_hexadecimal(
933
0
                                        TacRangeItem->start);
934
0
                    nf_info->amf.nr_tai_range
935
0
                        [nf_info->amf.num_of_nr_tai_range].end[tac_index] =
936
0
                                ogs_uint24_from_string_hexadecimal(
937
0
                                        TacRangeItem->end);
938
939
0
                    nf_info->amf.nr_tai_range
940
0
                        [nf_info->amf.num_of_nr_tai_range].num_of_tac_range++;
941
0
                }
942
0
            }
943
944
0
            if (rv == false)
945
0
                break;
946
947
0
            nf_info->amf.num_of_nr_tai_range++;
948
0
        }
949
0
    }
950
951
0
out:
952
0
    if (rv == false) {
953
0
        ogs_sbi_nf_info_remove(&nf_instance->nf_info_list, nf_info);
954
0
        return false;
955
0
    }
956
957
0
    return true;
958
0
}
959
960
static void handle_validity_time(
961
        ogs_sbi_subscription_data_t *subscription_data,
962
        char *validity_time, const char *action)
963
0
{
964
0
    ogs_time_t time, validity, patch;
965
0
    char *validity_time_string = NULL;
966
967
0
    ogs_assert(subscription_data);
968
0
    ogs_assert(action);
969
970
    /*
971
     * If there is a validity_time, then the NRF is updating
972
     * the validity_time by sending HTTP_STATUS to 200.
973
     * Therefore, change subscription_data->valdity_duration
974
     * according to this value.
975
     *
976
     * If validity_time is NULL, NRF sent an HTTP_STATUS of 204 (No content).
977
     * In this case, use the existing subscription_data->validity_duration.
978
     */
979
0
    if (validity_time) {
980
0
        if (ogs_sbi_time_from_string(&time, validity_time) == false) {
981
0
            ogs_error("[%s] Subscription %s until %s [parser error]",
982
0
                    subscription_data->id, action, validity_time);
983
0
            return;
984
0
        }
985
986
0
        validity = time - ogs_time_now();
987
0
        if (validity < 0) {
988
0
            ogs_error("[%s] Subscription %s until %s [validity:%d.%06d]",
989
0
                    subscription_data->id, action, validity_time,
990
0
                    (int)ogs_time_sec(validity), (int)ogs_time_usec(validity));
991
0
            return;
992
0
        }
993
994
        /*
995
         * Store subscription_data->validity_duration to derive NRF validity.
996
         * It will be used in ogs_nnrf_nfm_build_status_update().
997
         *
998
         * So, you should not remove the following lines.
999
         */
1000
0
        subscription_data->validity_duration =
1001
            /* Normalize seconds */
1002
0
            ogs_time_from_sec(ogs_time_to_sec(validity));
1003
0
    }
1004
1005
0
    if (!subscription_data->t_validity) {
1006
0
        subscription_data->t_validity =
1007
0
            ogs_timer_add(ogs_app()->timer_mgr,
1008
0
                ogs_timer_subscription_validity,
1009
0
                OGS_UINT_TO_POINTER(subscription_data->pool_id));
1010
0
        ogs_assert(subscription_data->t_validity);
1011
0
    }
1012
0
    ogs_timer_start(subscription_data->t_validity,
1013
0
            subscription_data->validity_duration);
1014
1015
    /*
1016
     * PATCH request will be sent before VALIDITY is expired.
1017
     */
1018
0
#define PATCH_TIME_FROM_VALIDITY(x) ((x) / 2)
1019
0
    patch = PATCH_TIME_FROM_VALIDITY(subscription_data->validity_duration);
1020
1021
0
    if (!subscription_data->t_patch) {
1022
0
        subscription_data->t_patch =
1023
0
            ogs_timer_add(ogs_app()->timer_mgr,
1024
0
                ogs_timer_subscription_patch,
1025
0
                OGS_UINT_TO_POINTER(subscription_data->pool_id));
1026
0
        ogs_assert(subscription_data->t_patch);
1027
0
    }
1028
0
    ogs_timer_start(subscription_data->t_patch, patch);
1029
1030
0
    if (validity_time) {
1031
0
        validity_time_string = ogs_strdup(validity_time);
1032
0
        ogs_assert(validity_time_string);
1033
0
    } else {
1034
0
        validity_time_string = ogs_sbi_localtime_string(
1035
0
                ogs_time_now() + subscription_data->validity_duration);
1036
0
        ogs_assert(validity_time_string);
1037
0
    }
1038
1039
0
    ogs_info("[%s] Subscription %s until %s "
1040
0
            "[duration:%lld,validity:%d.%06d,patch:%d.%06d]",
1041
0
            subscription_data->id, action, validity_time_string,
1042
0
            (long long)subscription_data->validity_duration,
1043
0
            (int)ogs_time_sec(subscription_data->validity_duration),
1044
0
            (int)ogs_time_usec(subscription_data->validity_duration),
1045
0
            (int)ogs_time_sec(patch), (int)ogs_time_usec(patch));
1046
1047
0
    ogs_free(validity_time_string);
1048
0
}
1049
1050
void ogs_nnrf_nfm_handle_nf_status_subscribe(
1051
        ogs_sbi_subscription_data_t *subscription_data,
1052
        ogs_sbi_message_t *recvmsg)
1053
0
{
1054
0
    OpenAPI_subscription_data_t *SubscriptionData = NULL;
1055
1056
0
    int rv;
1057
0
    ogs_sbi_message_t message;
1058
0
    ogs_sbi_header_t header;
1059
1060
0
    bool rc;
1061
0
    ogs_sbi_client_t *client = NULL;
1062
0
    OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL;
1063
0
    char *fqdn = NULL;
1064
0
    uint16_t fqdn_port = 0;
1065
0
    ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
1066
1067
0
    ogs_assert(recvmsg);
1068
0
    ogs_assert(subscription_data);
1069
1070
0
    SubscriptionData = recvmsg->SubscriptionData;
1071
0
    if (!SubscriptionData) {
1072
0
        ogs_error("No SubscriptionData");
1073
0
        return;
1074
0
    }
1075
1076
0
    if (!recvmsg->http.location) {
1077
0
        ogs_error("No http.location");
1078
0
        return;
1079
0
    }
1080
1081
0
    memset(&header, 0, sizeof(header));
1082
0
    header.uri = recvmsg->http.location;
1083
1084
0
    rv = ogs_sbi_parse_header(&message, &header);
1085
0
    if (rv != OGS_OK) {
1086
0
        ogs_error("Cannot parse http.location [%s]",
1087
0
            recvmsg->http.location);
1088
0
        return;
1089
0
    }
1090
1091
0
    if (!message.h.resource.component[1]) {
1092
0
        ogs_error("No Subscription ID [%s]", recvmsg->http.location);
1093
0
        ogs_sbi_header_free(&header);
1094
0
        return;
1095
0
    }
1096
1097
0
    rc = ogs_sbi_getaddr_from_uri(
1098
0
            &scheme, &fqdn, &fqdn_port, &addr, &addr6, header.uri);
1099
0
    if (rc == false || scheme == OpenAPI_uri_scheme_NULL) {
1100
0
        ogs_error("Invalid URI [%s]", header.uri);
1101
0
        ogs_sbi_header_free(&header);
1102
0
        return;
1103
0
    }
1104
1105
0
    client = ogs_sbi_client_find(scheme, fqdn, fqdn_port, addr, addr6);
1106
0
    if (!client) {
1107
0
        ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC);
1108
0
        client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6);
1109
0
        if (!client) {
1110
0
            ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC);
1111
1112
0
            ogs_sbi_header_free(&header);
1113
0
            ogs_free(fqdn);
1114
0
            ogs_freeaddrinfo(addr);
1115
0
            ogs_freeaddrinfo(addr6);
1116
1117
0
            return;
1118
0
        }
1119
0
    }
1120
0
    OGS_SBI_SETUP_CLIENT(subscription_data, client);
1121
1122
0
    ogs_free(fqdn);
1123
0
    ogs_freeaddrinfo(addr);
1124
0
    ogs_freeaddrinfo(addr6);
1125
1126
0
    ogs_sbi_subscription_data_set_resource_uri(
1127
0
            subscription_data, header.uri);
1128
0
    ogs_sbi_subscription_data_set_id(
1129
0
            subscription_data, message.h.resource.component[1]);
1130
1131
0
    ogs_sbi_header_free(&header);
1132
1133
    /* SBI Features */
1134
0
    if (SubscriptionData->nrf_supported_features) {
1135
0
        subscription_data->nrf_supported_features =
1136
0
            ogs_uint64_from_string_hexadecimal(
1137
0
                    SubscriptionData->nrf_supported_features);
1138
0
    } else {
1139
0
        subscription_data->nrf_supported_features = 0;
1140
0
    }
1141
1142
    /* Subscription Validity Time */
1143
0
    if (SubscriptionData->validity_time)
1144
0
        handle_validity_time(
1145
0
                subscription_data, SubscriptionData->validity_time, "created");
1146
0
}
1147
1148
void ogs_nnrf_nfm_handle_nf_status_update(
1149
        ogs_sbi_subscription_data_t *subscription_data,
1150
        ogs_sbi_message_t *recvmsg)
1151
0
{
1152
0
    OpenAPI_subscription_data_t *SubscriptionData = NULL;
1153
0
    char *validity_time = NULL;
1154
0
    const char *action = NULL;
1155
1156
0
    ogs_assert(recvmsg);
1157
0
    ogs_assert(subscription_data);
1158
1159
0
    if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) {
1160
0
        SubscriptionData = recvmsg->SubscriptionData;
1161
0
        if (!SubscriptionData) {
1162
0
            ogs_error("No SubscriptionData");
1163
0
            return;
1164
0
        }
1165
0
        if (!SubscriptionData->validity_time) {
1166
0
            ogs_error("No validityTime");
1167
0
            return;
1168
0
        }
1169
1170
0
        validity_time = SubscriptionData->validity_time;
1171
0
        action = "updated(200 OK)";
1172
0
    } else if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) {
1173
        /* No valdityTime. Re-use current subscription_data->valdity_duration */
1174
0
        action = "updated(204 No Content)";
1175
0
    } else {
1176
0
        ogs_fatal("[%s] HTTP response error [%d]",
1177
0
                subscription_data->id ?  subscription_data->id : "Unknown",
1178
0
                recvmsg->res_status);
1179
0
        ogs_assert_if_reached();
1180
0
    }
1181
1182
    /* Update Subscription Validity Time */
1183
0
    handle_validity_time(subscription_data, validity_time, action);
1184
0
}
1185
1186
void ogs_nnrf_nfm_handle_nf_status_subscription_response(
1187
        ogs_sbi_message_t *recvmsg, void *data)
1188
0
{
1189
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
1190
1191
0
    ogs_assert(recvmsg);
1192
1193
0
    subscription_data = ogs_sbi_subscription_data_find_by_pool_id(
1194
0
            OGS_POINTER_TO_UINT(data));
1195
0
    if (!subscription_data) {
1196
0
        ogs_error("Subscription has already been removed [%d]",
1197
0
                (int)OGS_POINTER_TO_UINT(data));
1198
0
        return;
1199
0
    }
1200
1201
0
    SWITCH(recvmsg->h.method)
1202
0
    CASE(OGS_SBI_HTTP_METHOD_POST)
1203
0
        if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_CREATED ||
1204
0
            recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) {
1205
0
            ogs_nnrf_nfm_handle_nf_status_subscribe(
1206
0
                    subscription_data, recvmsg);
1207
0
        } else {
1208
0
            ogs_error("HTTP response error : %d", recvmsg->res_status);
1209
0
        }
1210
0
        break;
1211
1212
0
    CASE(OGS_SBI_HTTP_METHOD_PATCH)
1213
0
        if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK ||
1214
0
            recvmsg->res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) {
1215
0
            ogs_nnrf_nfm_handle_nf_status_update(subscription_data, recvmsg);
1216
0
        } else {
1217
0
            ogs_error("[%s] HTTP response error [%d]",
1218
0
                    subscription_data->id ? subscription_data->id : "Unknown",
1219
0
                    recvmsg->res_status);
1220
0
        }
1221
0
        break;
1222
1223
0
    CASE(OGS_SBI_HTTP_METHOD_DELETE)
1224
0
        if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT)
1225
0
            ogs_info("[%s] Subscription deleted",
1226
0
                    subscription_data->id ? subscription_data->id : "Unknown");
1227
0
        else
1228
0
            ogs_error("[%s] HTTP response error [%d]",
1229
0
                    subscription_data->id ? subscription_data->id : "Unknown",
1230
0
                    recvmsg->res_status);
1231
1232
0
        ogs_sbi_subscription_data_remove(subscription_data);
1233
0
        break;
1234
1235
0
    DEFAULT
1236
0
        ogs_error("[%s] Invalid HTTP method [%s]",
1237
0
                subscription_data->id ? subscription_data->id : "Unknown",
1238
0
                recvmsg->h.method);
1239
0
        ogs_assert_if_reached();
1240
0
    END
1241
0
}
1242
1243
/*
1244
 * Defense-in-depth (TS 33.501 clause 5.9.2.1): accept an NRF status
1245
 * notification only when it corresponds to a confirmed subscription this NF
1246
 * created with the NRF. We test live subscription state (subscription_data_list
1247
 * via ogs_sbi_nf_status_subscription_exists(..., confirmed_only=true)), so a
1248
 * notification outside our active subscription scope is discarded before any
1249
 * local NF cache mutation.
1250
 *
1251
 * NOTE: This is surface reduction, NOT source authentication. Transport-layer
1252
 * trust (TLS/mTLS via server.verify_client) remains the primary control: a
1253
 * forged profile that falls within our active subscription scope is still
1254
 * accepted.
1255
 */
1256
static bool nf_profile_has_status_subscription(OpenAPI_nf_profile_t *NFProfile)
1257
0
{
1258
0
    OpenAPI_lnode_t *node = NULL;
1259
1260
0
    ogs_assert(NFProfile);
1261
0
    ogs_assert(ogs_sbi_self()->nf_instance);
1262
0
    ogs_assert(ogs_sbi_self()->nf_instance->id);
1263
1264
0
    if (ogs_sbi_nf_status_subscription_exists(
1265
0
                ogs_sbi_self()->nf_instance->id,
1266
0
                NFProfile->nf_type, OpenAPI_service_name_NULL, true))
1267
0
        return true;
1268
1269
0
    OpenAPI_list_for_each(NFProfile->nf_services, node) {
1270
0
        OpenAPI_nf_service_t *NFService = node->data;
1271
0
        if (NFService && ogs_sbi_nf_status_subscription_exists(
1272
0
                    ogs_sbi_self()->nf_instance->id,
1273
0
                    OpenAPI_nf_type_NULL, NFService->service_name, true))
1274
0
            return true;
1275
0
    }
1276
1277
0
    OpenAPI_list_for_each(NFProfile->nf_service_list, node) {
1278
0
        OpenAPI_map_t *NFServiceMap = node->data;
1279
0
        OpenAPI_nf_service_t *NFService =
1280
0
            NFServiceMap ? NFServiceMap->value : NULL;
1281
0
        if (NFService && ogs_sbi_nf_status_subscription_exists(
1282
0
                    ogs_sbi_self()->nf_instance->id,
1283
0
                    OpenAPI_nf_type_NULL, NFService->service_name, true))
1284
0
            return true;
1285
0
    }
1286
1287
0
    return false;
1288
0
}
1289
1290
/* NF_DEREGISTERED carries no profile, so match the cached NF's type/services
1291
 * against a confirmed subscription before evicting it (forged-deregister DoS). */
1292
static bool nf_instance_has_status_subscription(
1293
        ogs_sbi_nf_instance_t *nf_instance)
1294
0
{
1295
0
    ogs_sbi_nf_service_t *nf_service = NULL;
1296
1297
0
    ogs_assert(nf_instance);
1298
0
    ogs_assert(ogs_sbi_self()->nf_instance);
1299
0
    ogs_assert(ogs_sbi_self()->nf_instance->id);
1300
1301
0
    if (ogs_sbi_nf_status_subscription_exists(
1302
0
                ogs_sbi_self()->nf_instance->id,
1303
0
                nf_instance->nf_type, OpenAPI_service_name_NULL, true))
1304
0
        return true;
1305
1306
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
1307
0
        if (ogs_sbi_nf_status_subscription_exists(
1308
0
                    ogs_sbi_self()->nf_instance->id,
1309
0
                    OpenAPI_nf_type_NULL, nf_service->name, true))
1310
0
            return true;
1311
0
    }
1312
1313
0
    return false;
1314
0
}
1315
1316
bool ogs_nnrf_nfm_handle_nf_status_notify(
1317
        ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
1318
0
{
1319
0
    int rv;
1320
1321
0
    ogs_sbi_response_t *response = NULL;
1322
0
    OpenAPI_notification_data_t *NotificationData = NULL;
1323
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1324
1325
0
    ogs_sbi_message_t message;
1326
0
    ogs_sbi_header_t header;
1327
1328
0
    ogs_assert(stream);
1329
0
    ogs_assert(recvmsg);
1330
1331
0
    NotificationData = recvmsg->NotificationData;
1332
0
    if (!NotificationData) {
1333
0
        ogs_error("No NotificationData");
1334
0
        ogs_assert(true ==
1335
0
            ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1336
0
                recvmsg, "No NotificationData", NULL, NULL));
1337
0
        return false;
1338
0
    }
1339
1340
0
    if (!NotificationData->nf_instance_uri) {
1341
0
        ogs_error("No nfInstanceUri");
1342
0
        ogs_assert(true ==
1343
0
            ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1344
0
                recvmsg, "No nfInstanceUri", NULL, NULL));
1345
0
        return false;
1346
0
    }
1347
1348
0
    memset(&header, 0, sizeof(header));
1349
0
    header.uri = NotificationData->nf_instance_uri;
1350
1351
0
    rv = ogs_sbi_parse_header(&message, &header);
1352
0
    if (rv != OGS_OK) {
1353
0
        ogs_error("Cannot parse nfInstanceUri [%s]", header.uri);
1354
0
        ogs_assert(true ==
1355
0
            ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1356
0
                recvmsg, "Cannot parse nfInstanceUri", header.uri, NULL));
1357
0
        return false;
1358
0
    }
1359
1360
0
    if (!message.h.resource.component[1]) {
1361
0
        ogs_error("No nfInstanceId [%s]", header.uri);
1362
0
        ogs_assert(true ==
1363
0
            ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1364
0
                recvmsg, "Cannot parse nfInstanceUri", header.uri, NULL));
1365
0
        ogs_sbi_header_free(&header);
1366
0
        return false;
1367
0
    }
1368
1369
0
    if (NF_INSTANCE_ID_IS_SELF(message.h.resource.component[1])) {
1370
0
        ogs_warn("[%s] The notification is not allowed",
1371
0
                message.h.resource.component[1]);
1372
0
        ogs_assert(true ==
1373
0
            ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN,
1374
0
                recvmsg, "The notification is not allowed",
1375
0
                message.h.resource.component[1], NULL));
1376
0
        ogs_sbi_header_free(&header);
1377
0
        return false;
1378
0
    }
1379
1380
0
    if (NotificationData->event ==
1381
0
            OpenAPI_notification_event_type_NF_REGISTERED) {
1382
1383
0
        OpenAPI_nf_profile_t *NFProfile = NULL;
1384
0
        bool nf_instance_created = false;
1385
1386
0
        NFProfile = NotificationData->nf_profile;
1387
0
        if (!NFProfile) {
1388
0
            ogs_error("No NFProfile");
1389
0
            ogs_assert(true ==
1390
0
                ogs_sbi_server_send_error(
1391
0
                    stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1392
0
                    recvmsg, "No NFProfile", NULL, NULL));
1393
0
            ogs_sbi_header_free(&header);
1394
0
            return false;
1395
0
        }
1396
1397
0
        if (!NFProfile->nf_instance_id) {
1398
0
            ogs_error("No NFProfile.NFInstanceId");
1399
0
            ogs_assert(true ==
1400
0
                ogs_sbi_server_send_error(
1401
0
                    stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1402
0
                    recvmsg, "No NFProfile.NFInstanceId", NULL, NULL));
1403
0
            ogs_sbi_header_free(&header);
1404
0
            return false;
1405
0
        }
1406
1407
0
        if (!NFProfile->nf_type) {
1408
0
            ogs_error("No NFProfile.NFType");
1409
0
            ogs_assert(true ==
1410
0
                ogs_sbi_server_send_error(
1411
0
                    stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1412
0
                    recvmsg, "No NFProfile.NFType", NULL, NULL));
1413
0
            ogs_sbi_header_free(&header);
1414
0
            return false;
1415
0
        }
1416
1417
0
        if (!NFProfile->nf_status) {
1418
0
            ogs_error("No NFProfile.NFStatus");
1419
0
            ogs_assert(true ==
1420
0
                ogs_sbi_server_send_error(
1421
0
                    stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1422
0
                    recvmsg, "No NFProfile.NFStatus", NULL, NULL));
1423
0
            ogs_sbi_header_free(&header);
1424
0
            return false;
1425
0
        }
1426
1427
0
        if (nf_profile_has_status_subscription(NFProfile) == false) {
1428
0
            ogs_warn("[%s] (NRF-notify) No active subscription for notified "
1429
0
                    "profile [type:%s] - discarded",
1430
0
                    NFProfile->nf_instance_id,
1431
0
                    OpenAPI_nf_type_ToString(NFProfile->nf_type));
1432
0
            ogs_assert(true ==
1433
0
                ogs_sbi_server_send_error(
1434
0
                    stream, OGS_SBI_HTTP_STATUS_NOT_FOUND,
1435
0
                    recvmsg, "No active subscription for notification",
1436
0
                    NFProfile->nf_instance_id, NULL));
1437
0
            ogs_sbi_header_free(&header);
1438
0
            return false;
1439
0
        }
1440
1441
0
        nf_instance = ogs_sbi_nf_instance_find(message.h.resource.component[1]);
1442
0
        if (!nf_instance) {
1443
0
            nf_instance = ogs_sbi_nf_instance_add();
1444
0
            if (!nf_instance) {
1445
0
                ogs_error("Can't add notified NF instance [%s] "
1446
0
                        "due to insufficient space",
1447
0
                        message.h.resource.component[1]);
1448
0
                ogs_assert(true == ogs_sbi_server_send_error(
1449
0
                        stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR,
1450
0
                        recvmsg, "Insufficient resources",
1451
0
                        message.h.resource.component[1],
1452
0
                        "INSUFFICIENT_RESOURCES"));
1453
0
                ogs_sbi_header_free(&header);
1454
0
                return false;
1455
0
            }
1456
1457
0
            ogs_sbi_nf_instance_set_id(
1458
0
                    nf_instance, message.h.resource.component[1]);
1459
0
            ogs_sbi_nf_fsm_init(nf_instance);
1460
0
            nf_instance_created = true;
1461
1462
0
            ogs_info("[%s] (NRF-notify) NF registered", nf_instance->id);
1463
0
        } else {
1464
0
            ogs_warn("[%s] (NRF-notify) NF has already been added [type:%s]",
1465
0
                    nf_instance->id,
1466
0
                    OpenAPI_nf_type_ToString(nf_instance->nf_type));
1467
0
            if (!OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_registered)) {
1468
0
                ogs_error("[%s] (NRF-notify) NF invalid state [type:%s]",
1469
0
                        nf_instance->id,
1470
0
                        OpenAPI_nf_type_ToString(nf_instance->nf_type));
1471
0
            }
1472
0
        }
1473
1474
0
        if (ogs_nnrf_nfm_handle_nf_profile(nf_instance, NFProfile) == false) {
1475
0
            ogs_error("[%s] (NRF-notify) Invalid NFProfile [type:%s]",
1476
0
                    NFProfile->nf_instance_id,
1477
0
                    OpenAPI_nf_type_ToString(NFProfile->nf_type));
1478
1479
            /*
1480
             * ogs_nnrf_nfm_handle_nf_profile() rebuilds the NF profile in
1481
             * place. If parsing fails for a newly created cache entry, remove
1482
             * it because it may contain a partial profile. If the entry
1483
             * already existed, keep it in the registry to avoid deleting a
1484
             * previously usable local cache entry because of one bad notify.
1485
             */
1486
0
            if (nf_instance_created == true) {
1487
0
                ogs_sbi_nf_fsm_fini(nf_instance);
1488
0
                ogs_sbi_nf_instance_remove(nf_instance);
1489
0
            }
1490
1491
0
            ogs_assert(true ==
1492
0
                ogs_sbi_server_send_error(
1493
0
                    stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1494
0
                    recvmsg, "Invalid NFProfile",
1495
0
                    NFProfile->nf_instance_id, NULL));
1496
0
            ogs_sbi_header_free(&header);
1497
0
            return false;
1498
0
        }
1499
1500
0
        ogs_info("[%s] (NRF-notify) NF Profile updated [type:%s]",
1501
0
                    nf_instance->id,
1502
0
                    OpenAPI_nf_type_ToString(nf_instance->nf_type));
1503
1504
0
        ogs_sbi_client_associate(nf_instance);
1505
1506
0
        switch (nf_instance->nf_type) {
1507
0
        case OpenAPI_nf_type_SEPP:
1508
0
            ogs_sbi_self()->sepp_instance = nf_instance;
1509
0
            break;
1510
0
        default:
1511
0
            break;
1512
0
        }
1513
1514
0
    } else if (NotificationData->event ==
1515
0
            OpenAPI_notification_event_type_NF_DEREGISTERED) {
1516
0
        nf_instance = ogs_sbi_nf_instance_find(message.h.resource.component[1]);
1517
0
        if (nf_instance) {
1518
0
            if (nf_instance_has_status_subscription(nf_instance) == false) {
1519
0
                ogs_warn("[%s] (NRF-notify) NF_DEREGISTERED outside "
1520
0
                        "subscription scope [type:%s] - ignored",
1521
0
                        nf_instance->id,
1522
0
                        OpenAPI_nf_type_ToString(nf_instance->nf_type));
1523
0
                ogs_assert(true ==
1524
0
                    ogs_sbi_server_send_error(
1525
0
                        stream, OGS_SBI_HTTP_STATUS_NOT_FOUND,
1526
0
                        recvmsg, "No active subscription for notification",
1527
0
                        message.h.resource.component[1], NULL));
1528
0
                ogs_sbi_header_free(&header);
1529
0
                return false;
1530
0
            }
1531
1532
0
            ogs_info("[%s] (NRF-notify) NF_DEREGISTERED event [type:%s]",
1533
0
                    nf_instance->id,
1534
0
                    OpenAPI_nf_type_ToString(nf_instance->nf_type));
1535
0
            ogs_sbi_nf_fsm_fini(nf_instance);
1536
0
            ogs_sbi_nf_instance_remove(nf_instance);
1537
0
        } else {
1538
0
            ogs_warn("[%s] (NRF-notify) Not found",
1539
0
                    message.h.resource.component[1]);
1540
0
            ogs_assert(true ==
1541
0
                ogs_sbi_server_send_error(stream,
1542
0
                    OGS_SBI_HTTP_STATUS_NOT_FOUND,
1543
0
                    recvmsg, "Not found", message.h.resource.component[1],
1544
0
                    NULL));
1545
0
            ogs_sbi_header_free(&header);
1546
0
            return false;
1547
0
        }
1548
0
    } else {
1549
0
        char *eventstr = OpenAPI_notification_event_type_ToString(
1550
0
                            NotificationData->event);
1551
0
        ogs_error("Not supported event [%d:%s]",
1552
0
                NotificationData->event, eventstr ? eventstr : "Unknown");
1553
0
        ogs_assert(true ==
1554
0
            ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
1555
0
                recvmsg, "Not supported event",
1556
0
                eventstr ? eventstr : "Unknown", NULL));
1557
0
        ogs_sbi_header_free(&header);
1558
0
        return false;
1559
0
    }
1560
1561
0
    response = ogs_sbi_build_response(recvmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT);
1562
0
    ogs_assert(response);
1563
0
    ogs_assert(true == ogs_sbi_server_send_response(stream, response));
1564
1565
0
    ogs_sbi_header_free(&header);
1566
0
    return true;
1567
0
}
1568
1569
void ogs_nnrf_disc_handle_nf_discover_search_result(
1570
        OpenAPI_search_result_t *SearchResult)
1571
0
{
1572
0
    OpenAPI_lnode_t *node = NULL;
1573
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1574
1575
0
    ogs_assert(SearchResult);
1576
0
    ogs_assert(SearchResult->validity_period);
1577
0
    ogs_assert(SearchResult->nf_instances);
1578
1579
0
    OpenAPI_list_for_each(SearchResult->nf_instances, node) {
1580
0
        OpenAPI_nf_profile_t *NFProfile = NULL;
1581
0
        bool nf_instance_created = false;
1582
1583
0
        if (!node->data) continue;
1584
1585
0
        NFProfile = node->data;
1586
1587
0
        if (!NFProfile) {
1588
0
            ogs_error("No NFProfile");
1589
0
            continue;
1590
0
        }
1591
1592
0
        if (!NFProfile->nf_instance_id) {
1593
0
            ogs_error("No NFProfile.NFInstanceId");
1594
0
            continue;
1595
0
        }
1596
1597
0
        if (!NFProfile->nf_type) {
1598
0
            ogs_error("No NFProfile.NFType");
1599
0
            continue;
1600
0
        }
1601
1602
0
        if (!NFProfile->nf_status) {
1603
0
            ogs_error("No NFProfile.NFStatus");
1604
0
            continue;
1605
0
        }
1606
1607
0
        nf_instance = ogs_sbi_nf_instance_find(NFProfile->nf_instance_id);
1608
0
        if (!nf_instance) {
1609
0
            nf_instance = ogs_sbi_nf_instance_add();
1610
0
            if (!nf_instance) {
1611
0
                ogs_error("Can't add discovered NF instance [%s:%s] "
1612
0
                        "due to insufficient space",
1613
0
                        NFProfile->nf_instance_id,
1614
0
                        OpenAPI_nf_type_ToString(NFProfile->nf_type));
1615
0
                continue;
1616
0
            }
1617
1618
0
            ogs_sbi_nf_instance_set_id(nf_instance, NFProfile->nf_instance_id);
1619
0
            ogs_sbi_nf_fsm_init(nf_instance);
1620
0
            nf_instance_created = true;
1621
1622
0
            ogs_info("[%s] (NRF-discover) NF registered [type:%s]",
1623
0
                    NFProfile->nf_instance_id,
1624
0
                    OpenAPI_nf_type_ToString(NFProfile->nf_type));
1625
0
        } else {
1626
0
            ogs_warn("[%s] (NRF-discover) NF has already been added [type:%s]",
1627
0
                    NFProfile->nf_instance_id,
1628
0
                    OpenAPI_nf_type_ToString(NFProfile->nf_type));
1629
0
            if (!OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_registered)) {
1630
0
                ogs_error("[%s] (NRF-notify) NF invalid state [type:%s]",
1631
0
                        NFProfile->nf_instance_id,
1632
0
                        OpenAPI_nf_type_ToString(NFProfile->nf_type));
1633
0
            }
1634
0
        }
1635
1636
0
        if (NF_INSTANCE_ID_IS_OTHERS(nf_instance->id)) {
1637
0
            if (ogs_nnrf_nfm_handle_nf_profile(
1638
0
                        nf_instance, NFProfile) == false) {
1639
0
                ogs_error("[%s] (NRF-discover) Invalid NFProfile [type:%s]",
1640
0
                        NFProfile->nf_instance_id,
1641
0
                        OpenAPI_nf_type_ToString(NFProfile->nf_type));
1642
1643
                /*
1644
                 * Do not leave a newly created partial NFProfile in the
1645
                 * registry. If the entry already existed, keep it to avoid
1646
                 * deleting a previously usable local cache entry because of
1647
                 * one bad discovery result.
1648
                 */
1649
0
                if (nf_instance_created == true) {
1650
0
                    ogs_sbi_nf_fsm_fini(nf_instance);
1651
0
                    ogs_sbi_nf_instance_remove(nf_instance);
1652
0
                }
1653
1654
0
                continue;
1655
0
            }
1656
1657
0
            ogs_sbi_client_associate(nf_instance);
1658
1659
0
            switch (nf_instance->nf_type) {
1660
0
            case OpenAPI_nf_type_SEPP:
1661
0
                ogs_sbi_self()->sepp_instance = nf_instance;
1662
0
                break;
1663
0
            default:
1664
0
                break;
1665
0
            }
1666
1667
            /* TIME : Update validity from NRF */
1668
0
            nf_instance->time.validity_duration = SearchResult->validity_period;
1669
1670
0
            ogs_assert(nf_instance->t_validity);
1671
0
            ogs_timer_start(nf_instance->t_validity,
1672
0
                ogs_time_from_sec(nf_instance->time.validity_duration));
1673
1674
0
            ogs_info("[%s] (NF-discover) NF Profile updated "
1675
0
                    "[type:%s validity:%ds]",
1676
0
                    NFProfile->nf_instance_id,
1677
0
                    OpenAPI_nf_type_ToString(NFProfile->nf_type),
1678
0
                    nf_instance->time.validity_duration);
1679
0
        }
1680
0
    }
1681
0
}