/src/open5gs/lib/sbi/conv.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 | | #include "yuarel.h" |
22 | | |
23 | | static int parse_scheme_output( |
24 | | char *_protection_scheme_id, char *_scheme_output, |
25 | | ogs_datum_t *ecckey, ogs_datum_t *cipher_text, uint8_t *mactag) |
26 | 0 | { |
27 | 0 | uint8_t protection_scheme_id; |
28 | 0 | size_t scheme_output_size; |
29 | 0 | uint8_t *scheme_output = NULL; |
30 | 0 | uint8_t *p = NULL; |
31 | |
|
32 | 0 | ogs_assert(_protection_scheme_id); |
33 | 0 | ogs_assert(_scheme_output); |
34 | 0 | ogs_assert(ecckey); |
35 | 0 | ogs_assert(mactag); |
36 | 0 | ogs_assert(cipher_text); |
37 | | |
38 | 0 | protection_scheme_id = atoi(_protection_scheme_id); |
39 | 0 | if (protection_scheme_id == OGS_PROTECTION_SCHEME_PROFILE_A) { |
40 | 0 | ecckey->size = OGS_ECCKEY_LEN; |
41 | 0 | } else if (protection_scheme_id == OGS_PROTECTION_SCHEME_PROFILE_B) { |
42 | 0 | ecckey->size = OGS_ECCKEY_LEN+1; |
43 | 0 | } else { |
44 | 0 | ogs_fatal("Invalid protection scheme id [%s]", _protection_scheme_id); |
45 | 0 | ogs_assert_if_reached(); |
46 | | |
47 | 0 | return OGS_ERROR; |
48 | 0 | } |
49 | | |
50 | 0 | cipher_text->size = OGS_MSIN_LEN; |
51 | |
|
52 | 0 | scheme_output_size = strlen(_scheme_output)/2; |
53 | 0 | if (scheme_output_size < |
54 | 0 | ecckey->size + cipher_text->size + OGS_MACTAG_LEN) { |
55 | 0 | ogs_error("Not enough length [%zu]", strlen(_scheme_output)); |
56 | 0 | return OGS_ERROR; |
57 | 0 | } |
58 | | |
59 | 0 | scheme_output = ogs_calloc(1, scheme_output_size); |
60 | 0 | ogs_assert(scheme_output); |
61 | | |
62 | 0 | ogs_ascii_to_hex(_scheme_output, strlen(_scheme_output), |
63 | 0 | scheme_output, scheme_output_size); |
64 | |
|
65 | 0 | p = scheme_output; |
66 | 0 | ecckey->data = ogs_memdup(p, ecckey->size); |
67 | 0 | ogs_assert(ecckey->data); |
68 | | |
69 | 0 | p += ecckey->size; |
70 | 0 | cipher_text->data = ogs_memdup(p, cipher_text->size); |
71 | 0 | ogs_assert(cipher_text->data); |
72 | | |
73 | 0 | p += cipher_text->size; |
74 | 0 | memcpy(mactag, p, OGS_MACTAG_LEN); |
75 | |
|
76 | 0 | ogs_free(scheme_output); |
77 | |
|
78 | 0 | return OGS_OK; |
79 | 0 | } |
80 | | |
81 | | char *ogs_supi_from_suci(const char *suci) |
82 | 0 | { |
83 | 0 | #define MAX_SUCI_TOKEN 16 |
84 | 0 | char *array[MAX_SUCI_TOKEN]; |
85 | 0 | char *p, *tmp; |
86 | 0 | int i; |
87 | 0 | char *supi = NULL; |
88 | |
|
89 | 0 | ogs_assert(suci); |
90 | 0 | tmp = ogs_strdup(suci); |
91 | 0 | if (!tmp) { |
92 | 0 | ogs_error("ogs_strdup() failed"); |
93 | 0 | return NULL; |
94 | 0 | } |
95 | | |
96 | | /* Clang scan-build SA: Branch condition evaluates to a garbage value: If array "array" is not fully populated |
97 | | * in the while loop below then later access in the following switch-case may check uninitialized values. |
98 | | * Initialize "array" to NULL pointers to fix the issue. */ |
99 | 0 | for (i = 0; i < MAX_SUCI_TOKEN; i++) { |
100 | 0 | array[i] = NULL; |
101 | 0 | } |
102 | |
|
103 | 0 | p = tmp; |
104 | 0 | i = 0; |
105 | 0 | while((i < MAX_SUCI_TOKEN) && (array[i++] = strsep(&p, "-"))) { |
106 | | /* Empty Body */ |
107 | 0 | } |
108 | |
|
109 | 0 | SWITCH(array[0]) |
110 | 0 | CASE("suci") |
111 | 0 | SWITCH(array[1]) |
112 | 0 | CASE("0") /* SUPI format : IMSI */ |
113 | 0 | if (array[2] && array[3] && array[5] && array[6] && array[7]) { |
114 | 0 | uint8_t protection_scheme_id = atoi(array[5]); |
115 | 0 | uint8_t home_network_pki_value = atoi(array[6]); |
116 | |
|
117 | 0 | if (protection_scheme_id == OGS_PROTECTION_SCHEME_NULL) { |
118 | 0 | supi = ogs_msprintf("imsi-%s%s%s", |
119 | 0 | array[2], array[3], array[7]); |
120 | 0 | } else if (protection_scheme_id == |
121 | 0 | OGS_PROTECTION_SCHEME_PROFILE_A || |
122 | 0 | protection_scheme_id == |
123 | 0 | OGS_PROTECTION_SCHEME_PROFILE_B) { |
124 | |
|
125 | 0 | ogs_datum_t pubkey; |
126 | 0 | ogs_datum_t cipher_text; |
127 | 0 | ogs_datum_t plain_text; |
128 | 0 | char *plain_bcd; |
129 | 0 | uint8_t mactag1[OGS_MACTAG_LEN], mactag2[OGS_MACTAG_LEN]; |
130 | |
|
131 | 0 | uint8_t z[OGS_ECCKEY_LEN]; |
132 | |
|
133 | 0 | uint8_t ek[OGS_KEY_LEN]; |
134 | 0 | uint8_t icb[OGS_IVEC_LEN]; |
135 | 0 | uint8_t mk[OGS_SHA256_DIGEST_SIZE]; |
136 | |
|
137 | 0 | if (home_network_pki_value < |
138 | 0 | OGS_HOME_NETWORK_PKI_VALUE_MIN || |
139 | 0 | home_network_pki_value > |
140 | 0 | OGS_HOME_NETWORK_PKI_VALUE_MAX) { |
141 | 0 | ogs_error("Invalid HNET PKI Value [%s]", array[6]); |
142 | 0 | break; |
143 | 0 | } |
144 | | |
145 | 0 | if (!ogs_sbi_self()->hnet[home_network_pki_value].avail) { |
146 | 0 | ogs_error("HNET PKI Value Not Avaiable [%s]", array[6]); |
147 | 0 | break; |
148 | 0 | } |
149 | | |
150 | 0 | if (ogs_sbi_self()->hnet[home_network_pki_value].scheme |
151 | 0 | != protection_scheme_id) { |
152 | 0 | ogs_error("Scheme Not Matched [%d != %d]", |
153 | 0 | ogs_sbi_self()->hnet[home_network_pki_value].scheme, |
154 | 0 | protection_scheme_id); |
155 | 0 | break; |
156 | 0 | } |
157 | | |
158 | 0 | if (parse_scheme_output( |
159 | 0 | array[5], array[7], |
160 | 0 | &pubkey, &cipher_text, mactag1) != OGS_OK) { |
161 | 0 | ogs_error("parse_scheme_output[%s] failed", array[7]); |
162 | 0 | break; |
163 | 0 | } |
164 | | |
165 | 0 | if (protection_scheme_id == |
166 | 0 | OGS_PROTECTION_SCHEME_PROFILE_A) { |
167 | 0 | curve25519_donna(z, |
168 | 0 | ogs_sbi_self()->hnet[home_network_pki_value].key, |
169 | 0 | pubkey.data); |
170 | 0 | } else if (protection_scheme_id == |
171 | 0 | OGS_PROTECTION_SCHEME_PROFILE_B) { |
172 | 0 | if (ecdh_shared_secret( |
173 | 0 | pubkey.data, |
174 | 0 | ogs_sbi_self()-> |
175 | 0 | hnet[home_network_pki_value].key, |
176 | 0 | z) != 1) { |
177 | 0 | ogs_error("ecdh_shared_secret() failed"); |
178 | 0 | ogs_log_hexdump(OGS_LOG_ERROR, |
179 | 0 | pubkey.data, OGS_ECCKEY_LEN); |
180 | 0 | ogs_log_hexdump(OGS_LOG_ERROR, |
181 | 0 | ogs_sbi_self()-> |
182 | 0 | hnet[home_network_pki_value].key, |
183 | 0 | OGS_ECCKEY_LEN); |
184 | 0 | goto cleanup; |
185 | 0 | } |
186 | 0 | } else |
187 | 0 | ogs_assert_if_reached(); |
188 | | |
189 | 0 | ogs_kdf_ansi_x963( |
190 | 0 | z, OGS_ECCKEY_LEN, pubkey.data, pubkey.size, |
191 | 0 | ek, icb, mk); |
192 | |
|
193 | 0 | ogs_hmac_sha256( |
194 | 0 | mk, OGS_SHA256_DIGEST_SIZE, |
195 | 0 | cipher_text.data, cipher_text.size, |
196 | 0 | mactag2, OGS_MACTAG_LEN); |
197 | |
|
198 | 0 | if (memcmp(mactag1, mactag2, OGS_MACTAG_LEN) != 0) { |
199 | 0 | ogs_error("MAC-tag not matched"); |
200 | 0 | ogs_log_hexdump(OGS_LOG_ERROR, mactag1, OGS_MACTAG_LEN); |
201 | 0 | ogs_log_hexdump(OGS_LOG_ERROR, mactag2, OGS_MACTAG_LEN); |
202 | 0 | goto cleanup; |
203 | 0 | } |
204 | | |
205 | 0 | plain_text.size = cipher_text.size; |
206 | 0 | plain_text.data = ogs_calloc(1, plain_text.size); |
207 | 0 | ogs_assert(plain_text.data); |
208 | | |
209 | 0 | ogs_aes_ctr128_encrypt( |
210 | 0 | ek, icb, cipher_text.data, cipher_text.size, |
211 | 0 | plain_text.data); |
212 | |
|
213 | 0 | plain_bcd = ogs_calloc(1, plain_text.size*2+1); |
214 | 0 | ogs_assert(plain_bcd); |
215 | | |
216 | 0 | ogs_buffer_to_bcd(plain_text.data, plain_text.size, |
217 | 0 | plain_bcd, plain_text.size*2+1); |
218 | |
|
219 | 0 | supi = ogs_msprintf("imsi-%s%s%s", |
220 | 0 | array[2], array[3], plain_bcd); |
221 | 0 | ogs_assert(supi); |
222 | | |
223 | 0 | if (plain_text.data) |
224 | 0 | ogs_free(plain_text.data); |
225 | 0 | ogs_free(plain_bcd); |
226 | 0 | cleanup: |
227 | 0 | if (pubkey.data) |
228 | 0 | ogs_free(pubkey.data); |
229 | 0 | if (cipher_text.data) |
230 | 0 | ogs_free(cipher_text.data); |
231 | 0 | } else { |
232 | 0 | ogs_error("Invalid Protection Scheme [%s]", array[5]); |
233 | 0 | } |
234 | 0 | } |
235 | 0 | break; |
236 | 0 | DEFAULT |
237 | 0 | ogs_error("Not implemented [%s]", array[1]); |
238 | 0 | break; |
239 | 0 | END |
240 | 0 | break; |
241 | 0 | DEFAULT |
242 | 0 | ogs_error("Not implemented [%s]", array[0]); |
243 | 0 | break; |
244 | 0 | END |
245 | | |
246 | 0 | ogs_free(tmp); |
247 | 0 | return supi; |
248 | 0 | } |
249 | | |
250 | | char *ogs_supi_from_supi_or_suci(const char *supi_or_suci) |
251 | 0 | { |
252 | 0 | char *type = NULL; |
253 | 0 | char *supi = NULL; |
254 | |
|
255 | 0 | ogs_assert(supi_or_suci); |
256 | 0 | type = ogs_id_get_type(supi_or_suci); |
257 | 0 | if (!type) { |
258 | 0 | ogs_error("ogs_id_get_type[%s] failed", supi_or_suci); |
259 | 0 | goto cleanup; |
260 | 0 | } |
261 | 0 | SWITCH(type) |
262 | 0 | CASE("imsi") |
263 | 0 | supi = ogs_strdup(supi_or_suci); |
264 | 0 | ogs_expect(supi); |
265 | 0 | break; |
266 | 0 | CASE("suci") |
267 | 0 | supi = ogs_supi_from_suci(supi_or_suci); |
268 | 0 | ogs_expect(supi); |
269 | 0 | break; |
270 | 0 | DEFAULT |
271 | 0 | ogs_error("Not implemented [%s]", type); |
272 | 0 | break; |
273 | 0 | END |
274 | |
|
275 | 0 | cleanup: |
276 | 0 | if (type) |
277 | 0 | ogs_free(type); |
278 | 0 | return supi; |
279 | 0 | } |
280 | | |
281 | | char *ogs_uridup( |
282 | | OpenAPI_uri_scheme_e scheme, |
283 | | const char *fqdn, |
284 | | const ogs_sockaddr_t *addr, |
285 | | const ogs_sockaddr_t *addr6, |
286 | | uint16_t port, |
287 | | const ogs_sbi_header_t *h) |
288 | 0 | { |
289 | 0 | char buf[OGS_ADDRSTRLEN]; |
290 | 0 | char uri[OGS_HUGE_LEN]; |
291 | 0 | char *p, *last; |
292 | 0 | int i; |
293 | |
|
294 | 0 | ogs_assert(scheme); |
295 | 0 | ogs_assert(fqdn || addr || addr6); |
296 | | |
297 | 0 | p = uri; |
298 | 0 | last = uri + OGS_HUGE_LEN; |
299 | | |
300 | | /* HTTP scheme is selected based on TLS information */ |
301 | 0 | if (scheme == OpenAPI_uri_scheme_https) |
302 | 0 | p = ogs_slprintf(p, last, "https://"); |
303 | 0 | else if (scheme == OpenAPI_uri_scheme_http) |
304 | 0 | p = ogs_slprintf(p, last, "http://"); |
305 | 0 | else { |
306 | 0 | ogs_fatal("Invalid scheme [%d]", scheme); |
307 | 0 | ogs_assert_if_reached(); |
308 | 0 | } |
309 | | |
310 | | /* Hostname/IP address */ |
311 | 0 | if (fqdn) |
312 | 0 | p = ogs_slprintf(p, last, "%s", fqdn); |
313 | 0 | else if (addr6) { |
314 | 0 | p = ogs_slprintf(p, last, "[%s]", OGS_ADDR(addr6, buf)); |
315 | 0 | } else if (addr) { |
316 | 0 | p = ogs_slprintf(p, last, "%s", OGS_ADDR(addr, buf)); |
317 | 0 | } else |
318 | 0 | ogs_assert_if_reached(); |
319 | | |
320 | | /* Port number */ |
321 | 0 | if (port) |
322 | 0 | p = ogs_slprintf(p, last, ":%d", port); |
323 | | |
324 | | /* API */ |
325 | 0 | if (h) { |
326 | 0 | ogs_assert(h->service.name); |
327 | 0 | p = ogs_slprintf(p, last, "/%s", h->service.name); |
328 | 0 | ogs_assert(h->api.version); |
329 | 0 | p = ogs_slprintf(p, last, "/%s", h->api.version); |
330 | | |
331 | | /* Resource */ |
332 | 0 | ogs_assert(h->resource.component[0]); |
333 | 0 | for (i = 0; i < OGS_SBI_MAX_NUM_OF_RESOURCE_COMPONENT && |
334 | 0 | h->resource.component[i]; i++) |
335 | 0 | p = ogs_slprintf(p, last, "/%s", h->resource.component[i]); |
336 | 0 | } |
337 | | |
338 | 0 | return ogs_strdup(uri); |
339 | 0 | } |
340 | | |
341 | | char *ogs_sbi_server_uri( |
342 | | const ogs_sbi_server_t *server, |
343 | | const ogs_sbi_header_t *h) |
344 | 0 | { |
345 | 0 | ogs_sockaddr_t *advertise = NULL; |
346 | |
|
347 | 0 | ogs_assert(server); |
348 | | |
349 | 0 | advertise = server->advertise; |
350 | 0 | if (!advertise) |
351 | 0 | advertise = server->node.addr; |
352 | 0 | ogs_assert(advertise); |
353 | | |
354 | 0 | return ogs_sbi_sockaddr_uri(server->scheme, advertise, h); |
355 | 0 | } |
356 | | |
357 | | uint16_t ogs_sbi_uri_port_from_scheme_and_addr( |
358 | | OpenAPI_uri_scheme_e scheme, |
359 | | const ogs_sockaddr_t *addr) |
360 | 0 | { |
361 | 0 | uint16_t port = 0; |
362 | |
|
363 | 0 | ogs_assert(scheme); |
364 | 0 | ogs_assert(addr); |
365 | | |
366 | 0 | if (scheme == OpenAPI_uri_scheme_https && |
367 | 0 | OGS_PORT(addr) == OGS_SBI_HTTPS_PORT) { |
368 | | /* No Port in URI */ |
369 | 0 | } else if (scheme == OpenAPI_uri_scheme_http && |
370 | 0 | OGS_PORT(addr) == OGS_SBI_HTTP_PORT) { |
371 | | /* No Port in URI */ |
372 | 0 | } else { |
373 | 0 | port = OGS_PORT(addr); |
374 | 0 | } |
375 | |
|
376 | 0 | return port; |
377 | 0 | } |
378 | | |
379 | | char *ogs_sbi_sockaddr_uri( |
380 | | OpenAPI_uri_scheme_e scheme, |
381 | | const ogs_sockaddr_t *sa_list, |
382 | | const ogs_sbi_header_t *h) |
383 | 0 | { |
384 | 0 | int rv; |
385 | 0 | char *hostname = NULL; |
386 | 0 | ogs_sockaddr_t *addr = NULL, *addr6 = NULL; |
387 | 0 | uint16_t port = 0; |
388 | 0 | char *uri = NULL; |
389 | |
|
390 | 0 | ogs_assert(scheme); |
391 | 0 | ogs_assert(sa_list); |
392 | | |
393 | 0 | hostname = ogs_gethostname(sa_list); |
394 | |
|
395 | 0 | rv = ogs_copyaddrinfo(&addr, sa_list); |
396 | 0 | ogs_assert(rv == OGS_OK); |
397 | 0 | rv = ogs_copyaddrinfo(&addr6, addr); |
398 | 0 | ogs_assert(rv == OGS_OK); |
399 | | |
400 | 0 | rv = ogs_filteraddrinfo(&addr, AF_INET); |
401 | 0 | ogs_assert(rv == OGS_OK); |
402 | 0 | rv = ogs_filteraddrinfo(&addr6, AF_INET6); |
403 | 0 | ogs_assert(rv == OGS_OK); |
404 | | |
405 | 0 | if (addr6) |
406 | 0 | port = ogs_sbi_uri_port_from_scheme_and_addr(scheme, addr6); |
407 | 0 | else if (addr) |
408 | 0 | port = ogs_sbi_uri_port_from_scheme_and_addr(scheme, addr); |
409 | |
|
410 | 0 | uri = ogs_uridup(scheme, hostname, addr, addr6, port, h); |
411 | |
|
412 | 0 | ogs_freeaddrinfo(addr); |
413 | 0 | ogs_freeaddrinfo(addr6); |
414 | |
|
415 | 0 | return uri; |
416 | 0 | } |
417 | | |
418 | | char *ogs_sbi_client_uri( |
419 | | const ogs_sbi_client_t *client, |
420 | | const ogs_sbi_header_t *h) |
421 | 0 | { |
422 | 0 | uint16_t port = 0; |
423 | |
|
424 | 0 | ogs_assert(client); |
425 | | |
426 | 0 | if (client->fqdn) { |
427 | 0 | port = client->fqdn_port; |
428 | 0 | } else { |
429 | 0 | if (client->addr6) { |
430 | 0 | port = ogs_sbi_uri_port_from_scheme_and_addr( |
431 | 0 | client->scheme, client->addr6); |
432 | 0 | } else if (client->addr) { |
433 | 0 | port = ogs_sbi_uri_port_from_scheme_and_addr( |
434 | 0 | client->scheme, client->addr); |
435 | 0 | } |
436 | 0 | } |
437 | |
|
438 | 0 | return ogs_uridup( |
439 | 0 | client->scheme, client->fqdn, client->addr, client->addr6, port, h); |
440 | 0 | } |
441 | | |
442 | | char *ogs_sbi_client_apiroot(const ogs_sbi_client_t *client) |
443 | 0 | { |
444 | 0 | return ogs_sbi_client_uri(client, NULL); |
445 | 0 | } |
446 | | |
447 | | /** |
448 | | * Returns a url-decoded version of str |
449 | | * IMPORTANT: be sure to free() the returned string after use |
450 | | * Thanks Geek Hideout! |
451 | | * http://www.geekhideout.com/urlcode.shtml |
452 | | */ |
453 | | char *ogs_sbi_url_encode(const char *str) |
454 | 0 | { |
455 | 0 | if (str != NULL) { |
456 | 0 | char *pstr = (char *)str; |
457 | 0 | char *buf = ogs_malloc(strlen(str) * 3 + 1); |
458 | 0 | char *pbuf = buf; |
459 | 0 | ogs_assert(buf); |
460 | 0 | while (*pstr) { |
461 | |
|
462 | 0 | if (*pstr == '"' || |
463 | 0 | *pstr == '(' || |
464 | 0 | *pstr == ')' || |
465 | 0 | *pstr == ',' || |
466 | 0 | *pstr == '/' || |
467 | 0 | *pstr == ':' || |
468 | 0 | *pstr == ';' || |
469 | 0 | *pstr == '<' || |
470 | 0 | *pstr == '=' || |
471 | 0 | *pstr == '>' || |
472 | 0 | *pstr == '?' || |
473 | 0 | *pstr == '@' || |
474 | 0 | *pstr == '[' || |
475 | 0 | *pstr == '\\' || |
476 | 0 | *pstr == ']' || |
477 | 0 | *pstr == '{' || |
478 | 0 | *pstr == '}') { |
479 | 0 | *pbuf++ = '%'; |
480 | 0 | *pbuf++ = ogs_to_hex(*pstr >> 4); |
481 | 0 | *pbuf++ = ogs_to_hex(*pstr & 15); |
482 | 0 | } else |
483 | 0 | *pbuf++ = *pstr; |
484 | |
|
485 | 0 | pstr++; |
486 | 0 | } |
487 | 0 | *pbuf = '\0'; |
488 | 0 | return buf; |
489 | 0 | } else { |
490 | 0 | return NULL; |
491 | 0 | } |
492 | 0 | } |
493 | | |
494 | | char *ogs_sbi_url_decode(const char *str) |
495 | 302k | { |
496 | 302k | if (str != NULL) { |
497 | 230k | char *pstr = (char *)str; |
498 | 230k | char *buf = ogs_malloc(strlen(str) + 1); |
499 | 230k | char *pbuf = buf; |
500 | 230k | ogs_assert(buf); |
501 | 2.79M | while (*pstr) { |
502 | 2.56M | if (*pstr == '%') { |
503 | 5.91k | if (isxdigit((unsigned char)pstr[1]) && |
504 | 5.91k | isxdigit((unsigned char)pstr[2])) { |
505 | 4.14k | *pbuf++ = ogs_from_hex(pstr[1]) << 4 | |
506 | 4.14k | ogs_from_hex(pstr[2]); |
507 | 4.14k | pstr += 2; |
508 | 4.14k | } |
509 | 2.56M | } else if (*pstr == '+') { |
510 | 482 | *pbuf++ = ' '; |
511 | 2.56M | } else { |
512 | 2.56M | *pbuf++ = * pstr; |
513 | 2.56M | } |
514 | 2.56M | pstr++; |
515 | 2.56M | } |
516 | 230k | *pbuf = '\0'; |
517 | 230k | return buf; |
518 | 230k | } else { |
519 | 71.1k | return NULL; |
520 | 71.1k | } |
521 | 302k | } |
522 | | |
523 | | char *ogs_sbi_parse_uri(char *uri, const char *delim, char **saveptr) |
524 | 301k | { |
525 | 301k | char *item = NULL; |
526 | | |
527 | 301k | item = ogs_sbi_url_decode(ogs_strtok_r(uri, delim, saveptr)); |
528 | 301k | if (!item) { |
529 | 71.1k | return NULL; |
530 | 71.1k | } |
531 | | |
532 | 230k | return item; |
533 | 301k | } |
534 | | |
535 | | bool ogs_sbi_getaddr_from_uri( |
536 | | OpenAPI_uri_scheme_e *scheme, |
537 | | char **fqdn, uint16_t *fqdn_port, |
538 | | ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6, |
539 | | char *uri) |
540 | 0 | { |
541 | 0 | int rv; |
542 | 0 | ogs_sockaddr_t tmp; |
543 | 0 | struct yuarel yuarel; |
544 | 0 | char *p = NULL; |
545 | 0 | int port = 0; |
546 | |
|
547 | 0 | ogs_assert(fqdn); |
548 | 0 | ogs_assert(fqdn_port); |
549 | 0 | ogs_assert(addr); |
550 | 0 | ogs_assert(addr6); |
551 | 0 | ogs_assert(uri); |
552 | | |
553 | 0 | p = ogs_strdup(uri); |
554 | |
|
555 | 0 | rv = yuarel_parse(&yuarel, p); |
556 | 0 | if (rv != OGS_OK) { |
557 | 0 | ogs_free(p); |
558 | 0 | ogs_error("yuarel_parse() failed [%s]", uri); |
559 | 0 | return false; |
560 | 0 | } |
561 | | |
562 | 0 | if (!yuarel.scheme) { |
563 | 0 | ogs_error("No http.scheme found [%s]", uri); |
564 | 0 | ogs_free(p); |
565 | 0 | return false; |
566 | 0 | } |
567 | | |
568 | 0 | if (strcmp(yuarel.scheme, "https") == 0) { |
569 | 0 | *scheme = OpenAPI_uri_scheme_https; |
570 | 0 | } else if (strcmp(yuarel.scheme, "http") == 0) { |
571 | 0 | *scheme = OpenAPI_uri_scheme_http; |
572 | 0 | } else { |
573 | 0 | ogs_error("Invalid http.scheme [%s:%s]", yuarel.scheme, uri); |
574 | 0 | ogs_free(p); |
575 | 0 | return false; |
576 | 0 | } |
577 | | |
578 | 0 | if (!yuarel.host) { |
579 | 0 | ogs_error("No http.host found [%s]", uri); |
580 | 0 | ogs_free(p); |
581 | 0 | return false; |
582 | 0 | } |
583 | | |
584 | 0 | if (yuarel.port) port = yuarel.port; |
585 | |
|
586 | 0 | if (ogs_inet_pton(AF_INET, yuarel.host, &tmp) == OGS_OK || |
587 | 0 | ogs_inet_pton(AF_INET6, yuarel.host, &tmp) == OGS_OK) { |
588 | |
|
589 | 0 | *fqdn = NULL; |
590 | 0 | *fqdn_port = 0; |
591 | |
|
592 | 0 | rv = ogs_getaddrinfo(addr, AF_UNSPEC, yuarel.host, port, 0); |
593 | 0 | if (rv != OGS_OK) { |
594 | 0 | ogs_error("ogs_getaddrinfo() failed [%s]", uri); |
595 | 0 | ogs_free(p); |
596 | 0 | return false; |
597 | 0 | } |
598 | | |
599 | 0 | rv = ogs_copyaddrinfo(addr6, *addr); |
600 | 0 | ogs_assert(rv == OGS_OK); |
601 | | |
602 | 0 | rv = ogs_filteraddrinfo(addr, AF_INET); |
603 | 0 | ogs_assert(rv == OGS_OK); |
604 | 0 | rv = ogs_filteraddrinfo(addr6, AF_INET6); |
605 | 0 | ogs_assert(rv == OGS_OK); |
606 | |
|
607 | 0 | } else { |
608 | |
|
609 | 0 | *addr = NULL; |
610 | 0 | *addr6 = NULL; |
611 | |
|
612 | 0 | *fqdn = ogs_strdup(yuarel.host); |
613 | 0 | ogs_assert(*fqdn); |
614 | 0 | *fqdn_port = port; |
615 | |
|
616 | 0 | } |
617 | | |
618 | 0 | ogs_free(p); |
619 | 0 | return true; |
620 | 0 | } |
621 | | |
622 | | bool ogs_sbi_getpath_from_uri(char **path, const char *uri) |
623 | 0 | { |
624 | 0 | int rv; |
625 | 0 | struct yuarel yuarel; |
626 | 0 | char *p = NULL; |
627 | |
|
628 | 0 | ogs_assert(uri); |
629 | | |
630 | 0 | p = ogs_strdup(uri); |
631 | |
|
632 | 0 | rv = yuarel_parse(&yuarel, p); |
633 | 0 | if (rv != OGS_OK) { |
634 | 0 | ogs_error("yuarel_parse() failed [%s]", uri); |
635 | 0 | ogs_free(p); |
636 | 0 | return false; |
637 | 0 | } |
638 | | |
639 | 0 | if (!yuarel.scheme) { |
640 | 0 | ogs_error("No http.scheme found [%s]", uri); |
641 | 0 | ogs_free(p); |
642 | 0 | return false; |
643 | 0 | } |
644 | | |
645 | 0 | if (strcmp(yuarel.scheme, "https") == 0) { |
646 | |
|
647 | 0 | } else if (strcmp(yuarel.scheme, "http") == 0) { |
648 | |
|
649 | 0 | } else { |
650 | 0 | ogs_error("Invalid http.scheme [%s:%s]", yuarel.scheme, uri); |
651 | 0 | ogs_free(p); |
652 | 0 | return false; |
653 | 0 | } |
654 | | |
655 | 0 | if (!yuarel.host) { |
656 | 0 | ogs_error("No http.host found [%s]", uri); |
657 | 0 | ogs_free(p); |
658 | 0 | return false; |
659 | 0 | } |
660 | | |
661 | 0 | if (!yuarel.path) { |
662 | 0 | ogs_error("No http.path found [%s]", uri); |
663 | 0 | ogs_free(p); |
664 | 0 | return false; |
665 | 0 | } |
666 | | |
667 | 0 | *path = ogs_strdup(yuarel.path); |
668 | 0 | ogs_assert(*path); |
669 | | |
670 | 0 | ogs_free(p); |
671 | 0 | return true; |
672 | 0 | } |
673 | | |
674 | | char *ogs_sbi_client_resolve( |
675 | | OpenAPI_uri_scheme_e scheme, |
676 | | char *fqdn, uint16_t fqdn_port, |
677 | | const char **resolve, int num_of_resolve) |
678 | 0 | { |
679 | 0 | int i; |
680 | 0 | uint16_t port; |
681 | 0 | char *result = NULL; |
682 | |
|
683 | 0 | ogs_assert(scheme); |
684 | 0 | ogs_assert(fqdn); |
685 | 0 | ogs_assert(resolve); |
686 | 0 | ogs_assert(resolve[0]); |
687 | 0 | ogs_assert(num_of_resolve); |
688 | | |
689 | 0 | port = fqdn_port; |
690 | 0 | if (!port) { |
691 | 0 | if (scheme == OpenAPI_uri_scheme_https) |
692 | 0 | port = OGS_SBI_HTTPS_PORT; |
693 | 0 | else if (scheme == OpenAPI_uri_scheme_http) |
694 | 0 | port = OGS_SBI_HTTP_PORT; |
695 | 0 | else |
696 | 0 | ogs_assert_if_reached(); |
697 | 0 | } |
698 | | |
699 | 0 | result = ogs_msprintf("%s:%d:%s", fqdn, port, resolve[0]); |
700 | 0 | if (!result) { |
701 | 0 | ogs_error("ogs_msprintf() failed"); |
702 | 0 | return NULL; |
703 | 0 | } |
704 | | |
705 | 0 | for (i = 1; i < num_of_resolve; i++) { |
706 | 0 | ogs_assert(resolve[i]); |
707 | 0 | result = ogs_mstrcatf(result, ",%s", resolve[i]); |
708 | 0 | if (!result) { |
709 | 0 | ogs_error("ogs_mstrcatf() failed"); |
710 | 0 | ogs_free(result); |
711 | 0 | return NULL; |
712 | 0 | } |
713 | 0 | } |
714 | | |
715 | 0 | return result; |
716 | 0 | } |
717 | | |
718 | | char *ogs_sbi_bitrate_to_string(uint64_t bitrate, int unit) |
719 | 0 | { |
720 | 0 | if (unit == OGS_SBI_BITRATE_KBPS) { |
721 | 0 | return ogs_msprintf("%lld Kbps", |
722 | 0 | (long long)bitrate / 1000); |
723 | 0 | } else if (unit == OGS_SBI_BITRATE_MBPS) { |
724 | 0 | return ogs_msprintf("%lld Mbps", |
725 | 0 | (long long)bitrate / 1000 / 1000); |
726 | 0 | } else if (unit == OGS_SBI_BITRATE_GBPS) { |
727 | 0 | return ogs_msprintf("%lld Gbps", |
728 | 0 | (long long)bitrate / 1000 / 1000 / 1000); |
729 | 0 | } else if (unit == OGS_SBI_BITRATE_TBPS) { |
730 | 0 | return ogs_msprintf("%lld Tbps", |
731 | 0 | (long long)bitrate / 1000 / 1000 / 1000 / 1000); |
732 | 0 | } |
733 | | |
734 | 0 | return ogs_msprintf("%lld bps", (long long)bitrate); |
735 | 0 | } |
736 | | |
737 | | uint64_t ogs_sbi_bitrate_from_string(const char *str) |
738 | 0 | { |
739 | 0 | const char *unit = NULL; |
740 | 0 | double bitrate = 0; |
741 | 0 | ogs_assert(str); |
742 | 0 | uint64_t mul = 1; |
743 | |
|
744 | 0 | unit = strrchr(str, ' '); |
745 | 0 | bitrate = atof(str); |
746 | |
|
747 | 0 | if (!unit) { |
748 | 0 | ogs_error("No Unit [%s]", str); |
749 | 0 | return bitrate; |
750 | 0 | } |
751 | | |
752 | 0 | SWITCH(unit+1) |
753 | 0 | CASE("Kbps") |
754 | 0 | mul = 1000ul; |
755 | 0 | break; |
756 | 0 | CASE("Mbps") |
757 | 0 | mul = 1000ul * 1000ul; |
758 | 0 | break; |
759 | 0 | CASE("Gbps") |
760 | 0 | mul = 1000ul * 1000ul * 1000ul; |
761 | 0 | break; |
762 | 0 | CASE("Tbps") |
763 | 0 | mul = 1000ul * 1000ul * 1000ul * 1000ul; |
764 | 0 | break; |
765 | 0 | DEFAULT |
766 | 0 | END |
767 | |
|
768 | 0 | if (bitrate >= (INT64_MAX / mul)) |
769 | 0 | return INT64_MAX; |
770 | 0 | else |
771 | 0 | bitrate *= mul; |
772 | | |
773 | 0 | return (uint64_t) bitrate; |
774 | 0 | } |
775 | | |
776 | 0 | #define MAX_TIMESTR_LEN 128 |
777 | | |
778 | | int ogs_strftimezone(char *str, size_t size, int tm_gmtoff) |
779 | 0 | { |
780 | 0 | uint8_t off_sign; |
781 | 0 | int off; |
782 | 0 | int len; |
783 | |
|
784 | 0 | ogs_assert(str); |
785 | 0 | ogs_assert(size); |
786 | | |
787 | 0 | off_sign = '+'; |
788 | 0 | off = tm_gmtoff; |
789 | 0 | if (tm_gmtoff < 0) { |
790 | 0 | off_sign = '-'; |
791 | 0 | off = -off; |
792 | 0 | } |
793 | |
|
794 | 0 | len = ogs_snprintf(str, size, "%c%02d:%02d", |
795 | 0 | off_sign, off / 3600, (off % 3600) / 60); |
796 | 0 | if (len != 6) { |
797 | 0 | ogs_fatal("Unknown tm_gmtoff[%d:%d], len[%d], str[%s]", |
798 | 0 | tm_gmtoff, off, len, str); |
799 | 0 | ogs_assert_if_reached(); |
800 | 0 | } |
801 | | |
802 | 0 | return len; |
803 | 0 | } |
804 | | |
805 | | #define USE_MILLISECONDS_IN_RFC3339 0 |
806 | | |
807 | | char *ogs_sbi_localtime_string(ogs_time_t timestamp) |
808 | 0 | { |
809 | 0 | struct tm tm; |
810 | |
|
811 | 0 | char datetime[MAX_TIMESTR_LEN]; |
812 | 0 | char timezone[MAX_TIMESTR_LEN]; |
813 | 0 | int len; |
814 | |
|
815 | 0 | ogs_localtime(ogs_time_sec(timestamp), &tm); |
816 | 0 | ogs_strftime(datetime, sizeof datetime, "%Y-%m-%dT%H:%M:%S", &tm); |
817 | |
|
818 | 0 | len = ogs_strftimezone(timezone, MAX_TIMESTR_LEN, tm.tm_gmtoff); |
819 | 0 | ogs_assert(len == 6); |
820 | | |
821 | | #if USE_MILLISECONDS_IN_RFC3339 |
822 | | return ogs_msprintf("%s.%03lld%s", |
823 | | datetime, (long long)ogs_time_msec(timestamp), timezone); |
824 | | #else |
825 | 0 | return ogs_msprintf("%s.%06lld%s", |
826 | 0 | datetime, (long long)ogs_time_usec(timestamp), timezone); |
827 | 0 | #endif |
828 | 0 | } |
829 | | |
830 | | char *ogs_sbi_gmtime_string(ogs_time_t timestamp) |
831 | 0 | { |
832 | 0 | struct tm tm; |
833 | |
|
834 | 0 | char datetime[MAX_TIMESTR_LEN]; |
835 | |
|
836 | 0 | ogs_gmtime(ogs_time_sec(timestamp), &tm); |
837 | 0 | ogs_strftime(datetime, sizeof datetime, "%Y-%m-%dT%H:%M:%S", &tm); |
838 | |
|
839 | | #if USE_MILLISECONDS_IN_RFC3339 |
840 | | return ogs_msprintf("%s.%03lldZ", |
841 | | datetime, (long long)ogs_time_msec(timestamp)); |
842 | | #else |
843 | 0 | return ogs_msprintf("%s.%06lldZ", |
844 | 0 | datetime, (long long)ogs_time_usec(timestamp)); |
845 | 0 | #endif |
846 | 0 | } |
847 | | |
848 | | char *ogs_sbi_timezone_string(int tm_gmtoff) |
849 | 0 | { |
850 | 0 | char timezone[MAX_TIMESTR_LEN]; |
851 | 0 | int len; |
852 | |
|
853 | 0 | len = ogs_strftimezone(timezone, MAX_TIMESTR_LEN, tm_gmtoff); |
854 | 0 | ogs_assert(len == 6); |
855 | | |
856 | 0 | return ogs_msprintf("%s", timezone); |
857 | 0 | } |
858 | | |
859 | | bool ogs_sbi_time_from_string(ogs_time_t *timestamp, const char *str) |
860 | 0 | { |
861 | 0 | int rv, i, j, k; |
862 | 0 | struct tm tm; |
863 | 0 | bool is_subsecs, is_time, timezone_found; |
864 | 0 | char seconds[MAX_TIMESTR_LEN]; |
865 | 0 | char subsecs[MAX_TIMESTR_LEN]; |
866 | 0 | ogs_time_t usecs; |
867 | |
|
868 | 0 | ogs_assert(str); |
869 | 0 | ogs_assert(timestamp); |
870 | | |
871 | 0 | memset(seconds, 0, sizeof seconds); |
872 | 0 | memset(subsecs, 0, sizeof subsecs); |
873 | |
|
874 | 0 | is_subsecs = false; |
875 | 0 | is_time = false; |
876 | 0 | timezone_found = false; |
877 | 0 | i = 0; j = 0, k = 0; |
878 | 0 | while(str[i]) { |
879 | 0 | if (is_subsecs == false && str[i] == '.') |
880 | 0 | is_subsecs = true; |
881 | 0 | else if (is_subsecs == false && str[i] == 'T') |
882 | 0 | is_time = true; |
883 | 0 | else if (is_subsecs == true && (str[i] < '0' || str[i] > '9')) |
884 | 0 | is_subsecs = false; |
885 | |
|
886 | 0 | if (is_time == true && (str[i] == '+' || str[i] == '-')) |
887 | 0 | timezone_found = true; |
888 | |
|
889 | 0 | if (is_subsecs == false) { |
890 | 0 | if (str[i] == ':' && i >= 3 && |
891 | 0 | (str[i-3] == '+' || str[i-3] == '-')) { |
892 | | /* remove ':' character in timezone string range */ |
893 | 0 | } else { |
894 | 0 | if (j >= MAX_TIMESTR_LEN - 1) { |
895 | 0 | ogs_error("Too long time string [%d]", (int)strlen(str)); |
896 | 0 | return false; |
897 | 0 | } |
898 | 0 | seconds[j++] = str[i]; |
899 | 0 | } |
900 | 0 | } else { |
901 | 0 | if (k >= MAX_TIMESTR_LEN - 1) { |
902 | 0 | ogs_error("Too long time string [%d]", (int)strlen(str)); |
903 | 0 | return false; |
904 | 0 | } |
905 | 0 | subsecs[k++] = str[i]; |
906 | 0 | } |
907 | | |
908 | 0 | i++; |
909 | 0 | } |
910 | | |
911 | 0 | memset(&tm, 0, sizeof(tm)); |
912 | 0 | if (timezone_found == true) |
913 | 0 | ogs_strptime(seconds, "%Y-%m-%dT%H:%M:%S%z", &tm); |
914 | 0 | else |
915 | 0 | ogs_strptime(seconds, "%Y-%m-%dT%H:%M:%S", &tm); |
916 | | #if USE_MATH |
917 | | usecs = (ogs_time_t)floor(atof(subsecs) * 1000000.0 + 0.5); |
918 | | #else |
919 | 0 | usecs = (ogs_time_t)((atof(subsecs) * 10000000 + 5) / 10); |
920 | 0 | #endif |
921 | |
|
922 | 0 | rv = ogs_time_from_gmt(timestamp, &tm, usecs); |
923 | 0 | if (rv != OGS_OK) { |
924 | 0 | ogs_error("Cannot convert time [%s]", str); |
925 | 0 | return false; |
926 | 0 | } |
927 | | |
928 | 0 | return true; |
929 | 0 | } |
930 | | |
931 | | int ogs_sbi_rfc7231_string(char *date_str, ogs_time_t time) |
932 | 0 | { |
933 | 0 | const char ogs_month_snames[12][4] = { |
934 | 0 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", |
935 | 0 | "Aug", "Sep", "Oct", "Nov", "Dec" |
936 | 0 | }; |
937 | 0 | const char ogs_day_snames[7][4] = { |
938 | 0 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
939 | 0 | }; |
940 | |
|
941 | 0 | struct tm gmt; |
942 | 0 | const char *s; |
943 | 0 | int real_year; |
944 | |
|
945 | 0 | ogs_time_t sec = ogs_time_sec(time); |
946 | 0 | ogs_time_t msec = ogs_time_msec(time); |
947 | |
|
948 | 0 | ogs_assert(date_str); |
949 | | |
950 | 0 | ogs_gmtime(sec, &gmt); |
951 | | |
952 | | /* example: "Sun, 04 Aug 2019 08:49:37.845 GMT" */ |
953 | | /* 123456789012345678901234567890123 */ |
954 | |
|
955 | 0 | s = &ogs_day_snames[gmt.tm_wday][0]; |
956 | 0 | *date_str++ = *s++; |
957 | 0 | *date_str++ = *s++; |
958 | 0 | *date_str++ = *s++; |
959 | 0 | *date_str++ = ','; |
960 | 0 | *date_str++ = ' '; |
961 | 0 | *date_str++ = gmt.tm_mday / 10 + '0'; |
962 | 0 | *date_str++ = gmt.tm_mday % 10 + '0'; |
963 | 0 | *date_str++ = ' '; |
964 | 0 | s = &ogs_month_snames[gmt.tm_mon][0]; |
965 | 0 | *date_str++ = *s++; |
966 | 0 | *date_str++ = *s++; |
967 | 0 | *date_str++ = *s++; |
968 | 0 | *date_str++ = ' '; |
969 | 0 | real_year = 1900 + gmt.tm_year; |
970 | | /* This routine isn't y10k ready. */ |
971 | 0 | *date_str++ = real_year / 1000 + '0'; |
972 | 0 | *date_str++ = real_year % 1000 / 100 + '0'; |
973 | 0 | *date_str++ = real_year % 100 / 10 + '0'; |
974 | 0 | *date_str++ = real_year % 10 + '0'; |
975 | 0 | *date_str++ = ' '; |
976 | 0 | *date_str++ = gmt.tm_hour / 10 + '0'; |
977 | 0 | *date_str++ = gmt.tm_hour % 10 + '0'; |
978 | 0 | *date_str++ = ':'; |
979 | 0 | *date_str++ = gmt.tm_min / 10 + '0'; |
980 | 0 | *date_str++ = gmt.tm_min % 10 + '0'; |
981 | 0 | *date_str++ = ':'; |
982 | 0 | *date_str++ = gmt.tm_sec / 10 + '0'; |
983 | 0 | *date_str++ = gmt.tm_sec % 10 + '0'; |
984 | 0 | *date_str++ = '.'; |
985 | 0 | *date_str++ = msec / 100 + '0'; |
986 | 0 | *date_str++ = msec % 100 / 10 + '0'; |
987 | 0 | *date_str++ = msec % 10 + '0'; |
988 | 0 | *date_str++ = ' '; |
989 | 0 | *date_str++ = 'G'; |
990 | 0 | *date_str++ = 'M'; |
991 | 0 | *date_str++ = 'T'; |
992 | 0 | *date_str++ = 0; |
993 | |
|
994 | 0 | return OGS_OK; |
995 | 0 | } |
996 | | |
997 | | char *ogs_sbi_s_nssai_to_json(const ogs_s_nssai_t *s_nssai) |
998 | 0 | { |
999 | 0 | cJSON *item = NULL; |
1000 | 0 | OpenAPI_snssai_t sNSSAI; |
1001 | |
|
1002 | 0 | char *v = NULL; |
1003 | |
|
1004 | 0 | ogs_assert(s_nssai); |
1005 | | |
1006 | 0 | sNSSAI.sst = s_nssai->sst; |
1007 | 0 | sNSSAI.sd = ogs_s_nssai_sd_to_string(s_nssai->sd); |
1008 | |
|
1009 | 0 | item = OpenAPI_snssai_convertToJSON(&sNSSAI); |
1010 | 0 | if (!item) { |
1011 | 0 | ogs_error("OpenAPI_snssai_convertToJSON() failed"); |
1012 | 0 | return NULL; |
1013 | 0 | } |
1014 | 0 | if (sNSSAI.sd) ogs_free(sNSSAI.sd); |
1015 | |
|
1016 | 0 | v = cJSON_PrintUnformatted(item); |
1017 | 0 | ogs_expect(v); |
1018 | 0 | cJSON_Delete(item); |
1019 | |
|
1020 | 0 | return v; |
1021 | 0 | } |
1022 | | |
1023 | | bool ogs_sbi_s_nssai_from_json(ogs_s_nssai_t *s_nssai, const char *str) |
1024 | 30 | { |
1025 | 30 | bool rc = false; |
1026 | | |
1027 | 30 | cJSON *item = NULL; |
1028 | 30 | OpenAPI_snssai_t *sNSSAI = NULL; |
1029 | | |
1030 | 30 | ogs_assert(s_nssai); |
1031 | 30 | ogs_assert(str); |
1032 | | |
1033 | 30 | item = cJSON_Parse(str); |
1034 | 30 | if (item) { |
1035 | 6 | sNSSAI = OpenAPI_snssai_parseFromJSON(item); |
1036 | 6 | if (sNSSAI) { |
1037 | 2 | s_nssai->sst = sNSSAI->sst; |
1038 | 2 | s_nssai->sd = ogs_s_nssai_sd_from_string(sNSSAI->sd); |
1039 | 2 | OpenAPI_snssai_free(sNSSAI); |
1040 | 2 | rc = true; |
1041 | 2 | } |
1042 | 6 | cJSON_Delete(item); |
1043 | 6 | } |
1044 | | |
1045 | 30 | return rc; |
1046 | 30 | } |
1047 | | |
1048 | | char *ogs_sbi_s_nssai_to_string(const ogs_s_nssai_t *s_nssai) |
1049 | 0 | { |
1050 | 0 | ogs_assert(s_nssai); |
1051 | | |
1052 | 0 | if (s_nssai->sd.v != OGS_S_NSSAI_NO_SD_VALUE) { |
1053 | 0 | return ogs_msprintf("%d-%06x", s_nssai->sst, s_nssai->sd.v); |
1054 | 0 | } else { |
1055 | 0 | return ogs_msprintf("%d", s_nssai->sst); |
1056 | 0 | } |
1057 | 0 | } |
1058 | | |
1059 | | bool ogs_sbi_s_nssai_from_string(ogs_s_nssai_t *s_nssai, const char *str) |
1060 | 0 | { |
1061 | 0 | bool rc = false; |
1062 | 0 | char *token, *p, *tofree; |
1063 | 0 | char *sst = NULL; |
1064 | 0 | char *sd = NULL; |
1065 | |
|
1066 | 0 | ogs_assert(s_nssai); |
1067 | 0 | ogs_assert(str); |
1068 | | |
1069 | 0 | tofree = p = ogs_strdup(str); |
1070 | 0 | if (!p) { |
1071 | 0 | ogs_error("ogs_strdup[%s] failed", str); |
1072 | 0 | goto cleanup; |
1073 | 0 | } |
1074 | | |
1075 | 0 | token = strsep(&p, "-"); |
1076 | 0 | if (!token) { |
1077 | 0 | ogs_error("strsep[%s] failed", str); |
1078 | 0 | goto cleanup; |
1079 | 0 | } |
1080 | | |
1081 | 0 | sst = ogs_strdup(token); |
1082 | 0 | if (!sst) { |
1083 | 0 | ogs_error("ogs_strdup[%s:%s] failed", str, token); |
1084 | 0 | goto cleanup; |
1085 | 0 | } |
1086 | | |
1087 | 0 | s_nssai->sst = atoi(sst); |
1088 | 0 | s_nssai->sd.v = OGS_S_NSSAI_NO_SD_VALUE; |
1089 | |
|
1090 | 0 | if (p) { |
1091 | 0 | sd = ogs_strdup(p); |
1092 | 0 | if (!sd) { |
1093 | 0 | ogs_error("ogs_strdup[%s:%s] failed", str, token); |
1094 | 0 | goto cleanup; |
1095 | 0 | } |
1096 | 0 | s_nssai->sd = ogs_uint24_from_string_hexadecimal(sd); |
1097 | 0 | } |
1098 | | |
1099 | 0 | rc = true; |
1100 | |
|
1101 | 0 | cleanup: |
1102 | 0 | if (tofree) |
1103 | 0 | ogs_free(tofree); |
1104 | 0 | if (sst) |
1105 | 0 | ogs_free(sst); |
1106 | 0 | if (sd) |
1107 | 0 | ogs_free(sd); |
1108 | |
|
1109 | 0 | return rc; |
1110 | 0 | } |
1111 | | |
1112 | | OpenAPI_plmn_id_t *ogs_sbi_build_plmn_id(const ogs_plmn_id_t *plmn_id) |
1113 | 0 | { |
1114 | 0 | OpenAPI_plmn_id_t *PlmnId = NULL; |
1115 | |
|
1116 | 0 | ogs_assert(plmn_id); |
1117 | | |
1118 | 0 | PlmnId = ogs_calloc(1, sizeof(*PlmnId)); |
1119 | 0 | if (!PlmnId) { |
1120 | 0 | ogs_error("ogs_calloc() failed"); |
1121 | 0 | return NULL; |
1122 | 0 | } |
1123 | | |
1124 | 0 | PlmnId->mcc = ogs_plmn_id_mcc_string(plmn_id); |
1125 | 0 | if (!PlmnId->mcc) { |
1126 | 0 | ogs_error("ogs_plmn_id_mcc_string() failed"); |
1127 | 0 | ogs_sbi_free_plmn_id(PlmnId); |
1128 | 0 | return NULL; |
1129 | 0 | } |
1130 | 0 | PlmnId->mnc = ogs_plmn_id_mnc_string(plmn_id); |
1131 | 0 | if (!PlmnId->mnc) { |
1132 | 0 | ogs_error("ogs_plmn_id_mnc_string() failed"); |
1133 | 0 | ogs_sbi_free_plmn_id(PlmnId); |
1134 | 0 | return NULL; |
1135 | 0 | } |
1136 | | |
1137 | 0 | return PlmnId; |
1138 | 0 | } |
1139 | | |
1140 | | bool ogs_sbi_parse_plmn_id( |
1141 | | ogs_plmn_id_t *plmn_id, const OpenAPI_plmn_id_t *PlmnId) |
1142 | 35 | { |
1143 | 35 | ogs_assert(plmn_id); |
1144 | 35 | ogs_assert(PlmnId); |
1145 | 35 | ogs_assert(PlmnId->mcc); |
1146 | 35 | ogs_assert(PlmnId->mnc); |
1147 | | |
1148 | 35 | ogs_plmn_id_build(plmn_id, |
1149 | 35 | atoi(PlmnId->mcc), atoi(PlmnId->mnc), strlen(PlmnId->mnc)); |
1150 | | |
1151 | 35 | return true; |
1152 | 35 | } |
1153 | | |
1154 | | void ogs_sbi_free_plmn_id(OpenAPI_plmn_id_t *PlmnId) |
1155 | 25 | { |
1156 | 25 | ogs_assert(PlmnId); |
1157 | | |
1158 | 25 | if (PlmnId->mcc) |
1159 | 25 | ogs_free(PlmnId->mcc); |
1160 | 25 | if (PlmnId->mnc) |
1161 | 25 | ogs_free(PlmnId->mnc); |
1162 | | |
1163 | 25 | ogs_free(PlmnId); |
1164 | 25 | } |
1165 | | |
1166 | | OpenAPI_list_t *ogs_sbi_build_plmn_list( |
1167 | | const ogs_plmn_id_t *plmn_list, int num_of_plmn_list) |
1168 | 0 | { |
1169 | 0 | OpenAPI_list_t *PlmnList = NULL; |
1170 | 0 | OpenAPI_plmn_id_t *PlmnId = NULL; |
1171 | 0 | int i; |
1172 | |
|
1173 | 0 | ogs_assert(plmn_list); |
1174 | 0 | ogs_assert(num_of_plmn_list); |
1175 | | |
1176 | 0 | PlmnList = OpenAPI_list_create(); |
1177 | 0 | ogs_assert(PlmnList); |
1178 | | |
1179 | 0 | for (i = 0; i < num_of_plmn_list; i++) { |
1180 | 0 | PlmnId = ogs_sbi_build_plmn_id(plmn_list + i); |
1181 | 0 | ogs_assert(PlmnId); |
1182 | | |
1183 | 0 | OpenAPI_list_add(PlmnList, PlmnId); |
1184 | 0 | } |
1185 | | |
1186 | 0 | return PlmnList; |
1187 | 0 | } |
1188 | | |
1189 | | int ogs_sbi_parse_plmn_list( |
1190 | | ogs_plmn_id_t *plmn_list, const OpenAPI_list_t *PlmnList) |
1191 | 12 | { |
1192 | 12 | OpenAPI_plmn_id_t *PlmnId = NULL; |
1193 | 12 | OpenAPI_lnode_t *node = NULL; |
1194 | 12 | int num_of_plmn_list = 0; |
1195 | | |
1196 | 12 | ogs_assert(plmn_list); |
1197 | 12 | ogs_assert(PlmnList); |
1198 | | |
1199 | 12 | num_of_plmn_list = 0; |
1200 | 25 | OpenAPI_list_for_each(PlmnList, node) { |
1201 | 25 | PlmnId = node->data; |
1202 | 25 | if (PlmnId) { |
1203 | 25 | ogs_assert(PlmnId->mcc); |
1204 | 25 | ogs_assert(PlmnId->mnc); |
1205 | | |
1206 | 25 | if (num_of_plmn_list >= OGS_MAX_NUM_OF_PLMN) { |
1207 | 0 | ogs_warn("Exceeded maximum PLMN list size (%d)", |
1208 | 0 | OGS_MAX_NUM_OF_PLMN); |
1209 | 0 | break; |
1210 | 0 | } |
1211 | | |
1212 | 25 | ogs_plmn_id_build(plmn_list + num_of_plmn_list, |
1213 | 25 | atoi(PlmnId->mcc), atoi(PlmnId->mnc), strlen(PlmnId->mnc)); |
1214 | | |
1215 | 25 | num_of_plmn_list++; |
1216 | 25 | } |
1217 | 25 | } |
1218 | | |
1219 | 12 | return num_of_plmn_list; |
1220 | 12 | } |
1221 | | |
1222 | | void ogs_sbi_free_plmn_list(OpenAPI_list_t *PlmnList) |
1223 | 16 | { |
1224 | 16 | OpenAPI_plmn_id_t *PlmnId = NULL; |
1225 | 16 | OpenAPI_lnode_t *node = NULL; |
1226 | | |
1227 | 16 | ogs_assert(PlmnList); |
1228 | | |
1229 | 25 | OpenAPI_list_for_each(PlmnList, node) { |
1230 | 25 | PlmnId = node->data; |
1231 | 25 | if (PlmnId) |
1232 | 25 | ogs_sbi_free_plmn_id(PlmnId); |
1233 | 25 | } |
1234 | 16 | OpenAPI_list_free(PlmnList); |
1235 | 16 | } |
1236 | | |
1237 | | /** |
1238 | | * Compares an ogs_plmn_id_t structure with an OpenAPI_plmn_id_t structure. |
1239 | | * |
1240 | | * @param plmn_list The PLMN-ID in ogs_plmn_id_t format. |
1241 | | * @param PlmnList The PLMN-ID in OpenAPI_plmn_id_t format. |
1242 | | * @return true if the PLMN-IDs are equal; otherwise, false. |
1243 | | */ |
1244 | | bool ogs_sbi_compare_plmn_list( |
1245 | | const ogs_plmn_id_t *plmn_id, const OpenAPI_plmn_id_t *PlmnId) |
1246 | 0 | { |
1247 | 0 | ogs_plmn_id_t temp_plmn_id; |
1248 | |
|
1249 | 0 | ogs_assert(plmn_id); |
1250 | 0 | ogs_assert(PlmnId); |
1251 | 0 | ogs_assert(PlmnId->mcc); |
1252 | 0 | ogs_assert(PlmnId->mnc); |
1253 | | |
1254 | | /* Convert OpenAPI_plmn_id_t to ogs_plmn_id_t */ |
1255 | 0 | ogs_sbi_parse_plmn_id(&temp_plmn_id, PlmnId); |
1256 | | |
1257 | | /* Compare MCC and MNC values */ |
1258 | 0 | if (ogs_plmn_id_mcc(plmn_id) == ogs_plmn_id_mcc(&temp_plmn_id) && |
1259 | 0 | ogs_plmn_id_mnc(plmn_id) == ogs_plmn_id_mnc(&temp_plmn_id)) { |
1260 | 0 | return true; |
1261 | 0 | } |
1262 | | |
1263 | 0 | return false; |
1264 | 0 | } |
1265 | | |
1266 | | OpenAPI_plmn_id_nid_t *ogs_sbi_build_plmn_id_nid(const ogs_plmn_id_t *plmn_id) |
1267 | 0 | { |
1268 | 0 | OpenAPI_plmn_id_nid_t *PlmnIdNid = NULL; |
1269 | |
|
1270 | 0 | ogs_assert(plmn_id); |
1271 | | |
1272 | 0 | PlmnIdNid = ogs_calloc(1, sizeof(*PlmnIdNid)); |
1273 | 0 | if (!PlmnIdNid) { |
1274 | 0 | ogs_error("ogs_calloc() failed"); |
1275 | 0 | return NULL; |
1276 | 0 | } |
1277 | | |
1278 | 0 | PlmnIdNid->mcc = ogs_plmn_id_mcc_string(plmn_id); |
1279 | 0 | if (!PlmnIdNid->mcc) { |
1280 | 0 | ogs_error("ogs_plmn_id_mcc_string() failed"); |
1281 | 0 | ogs_sbi_free_plmn_id_nid(PlmnIdNid); |
1282 | 0 | return NULL; |
1283 | 0 | } |
1284 | 0 | PlmnIdNid->mnc = ogs_plmn_id_mnc_string(plmn_id); |
1285 | 0 | if (!PlmnIdNid->mnc) { |
1286 | 0 | ogs_error("ogs_plmn_id_mnc_string() failed"); |
1287 | 0 | ogs_sbi_free_plmn_id_nid(PlmnIdNid); |
1288 | 0 | return NULL; |
1289 | 0 | } |
1290 | | |
1291 | 0 | return PlmnIdNid; |
1292 | 0 | } |
1293 | | |
1294 | | bool ogs_sbi_parse_plmn_id_nid( |
1295 | | ogs_plmn_id_t *plmn_id, const OpenAPI_plmn_id_nid_t *PlmnIdNid) |
1296 | 12 | { |
1297 | 12 | ogs_assert(plmn_id); |
1298 | 12 | ogs_assert(PlmnIdNid); |
1299 | 12 | ogs_assert(PlmnIdNid->mcc); |
1300 | 12 | ogs_assert(PlmnIdNid->mnc); |
1301 | | |
1302 | 12 | ogs_plmn_id_build(plmn_id, |
1303 | 12 | atoi(PlmnIdNid->mcc), atoi(PlmnIdNid->mnc), strlen(PlmnIdNid->mnc)); |
1304 | | |
1305 | 12 | return true; |
1306 | 12 | } |
1307 | | |
1308 | | void ogs_sbi_free_plmn_id_nid(OpenAPI_plmn_id_nid_t *PlmnIdNid) |
1309 | 0 | { |
1310 | 0 | ogs_assert(PlmnIdNid); |
1311 | | |
1312 | 0 | if (PlmnIdNid->mcc) |
1313 | 0 | ogs_free(PlmnIdNid->mcc); |
1314 | 0 | if (PlmnIdNid->mnc) |
1315 | 0 | ogs_free(PlmnIdNid->mnc); |
1316 | 0 | if (PlmnIdNid->nid) |
1317 | 0 | ogs_free(PlmnIdNid->nid); |
1318 | |
|
1319 | 0 | ogs_free(PlmnIdNid); |
1320 | 0 | } |
1321 | | |
1322 | | OpenAPI_guami_t *ogs_sbi_build_guami(const ogs_guami_t *guami) |
1323 | 0 | { |
1324 | 0 | OpenAPI_guami_t *Guami = NULL; |
1325 | |
|
1326 | 0 | ogs_assert(guami); |
1327 | | |
1328 | 0 | Guami = ogs_calloc(1, sizeof(*Guami)); |
1329 | 0 | if (!Guami) { |
1330 | 0 | ogs_error("ogs_calloc() failed"); |
1331 | 0 | return NULL; |
1332 | 0 | } |
1333 | | |
1334 | 0 | Guami->plmn_id = ogs_sbi_build_plmn_id_nid(&guami->plmn_id); |
1335 | 0 | if (!Guami->plmn_id) { |
1336 | 0 | ogs_error("ogs_sbi_build_plmn_id_nid() failed"); |
1337 | 0 | ogs_sbi_free_guami(Guami); |
1338 | 0 | return NULL; |
1339 | 0 | } |
1340 | 0 | Guami->amf_id = ogs_amf_id_to_string(&guami->amf_id); |
1341 | 0 | if (!Guami->amf_id) { |
1342 | 0 | ogs_error("ogs_amf_id_to_string() failed"); |
1343 | 0 | ogs_sbi_free_guami(Guami); |
1344 | 0 | return NULL; |
1345 | 0 | } |
1346 | | |
1347 | 0 | return Guami; |
1348 | 0 | } |
1349 | | |
1350 | | bool ogs_sbi_parse_guami(ogs_guami_t *guami, const OpenAPI_guami_t *Guami) |
1351 | 42 | { |
1352 | 42 | ogs_assert(guami); |
1353 | 42 | ogs_assert(Guami); |
1354 | 42 | ogs_assert(Guami->amf_id); |
1355 | 42 | ogs_assert(Guami->plmn_id); |
1356 | | |
1357 | 42 | if (!ogs_amf_id_from_string(&guami->amf_id, Guami->amf_id)) { |
1358 | 30 | ogs_error("Invalid GUAMI AMF ID [%s]", Guami->amf_id); |
1359 | 30 | return false; |
1360 | 30 | } |
1361 | 12 | ogs_sbi_parse_plmn_id_nid(&guami->plmn_id, Guami->plmn_id); |
1362 | | |
1363 | 12 | return true; |
1364 | 42 | } |
1365 | | |
1366 | | void ogs_sbi_free_guami(OpenAPI_guami_t *Guami) |
1367 | 0 | { |
1368 | 0 | ogs_assert(Guami); |
1369 | | |
1370 | 0 | if (Guami->plmn_id) |
1371 | 0 | ogs_sbi_free_plmn_id_nid(Guami->plmn_id); |
1372 | 0 | if (Guami->amf_id) |
1373 | 0 | ogs_free(Guami->amf_id); |
1374 | 0 | ogs_free(Guami); |
1375 | 0 | } |
1376 | | |
1377 | | OpenAPI_nr_location_t *ogs_sbi_build_nr_location( |
1378 | | const ogs_5gs_tai_t *tai, const ogs_nr_cgi_t *nr_cgi) |
1379 | 0 | { |
1380 | 0 | OpenAPI_nr_location_t *NrLocation = NULL; |
1381 | 0 | OpenAPI_tai_t *Tai = NULL; |
1382 | 0 | OpenAPI_ncgi_t *Ncgi = NULL; |
1383 | |
|
1384 | 0 | ogs_assert(tai); |
1385 | 0 | ogs_assert(nr_cgi); |
1386 | | |
1387 | 0 | NrLocation = ogs_calloc(1, sizeof(*NrLocation)); |
1388 | 0 | if (!NrLocation) { |
1389 | 0 | ogs_error("ogs_calloc() failed"); |
1390 | 0 | return NULL; |
1391 | 0 | } |
1392 | | |
1393 | 0 | NrLocation->tai = Tai = ogs_calloc(1, sizeof(*Tai)); |
1394 | 0 | if (!Tai) { |
1395 | 0 | ogs_error("ogs_calloc() failed"); |
1396 | 0 | ogs_sbi_free_nr_location(NrLocation); |
1397 | 0 | return NULL; |
1398 | 0 | } |
1399 | 0 | Tai->plmn_id = ogs_sbi_build_plmn_id(&tai->plmn_id); |
1400 | 0 | if (!Tai->plmn_id) { |
1401 | 0 | ogs_error("ogs_sbi_build_plmn_id() failed"); |
1402 | 0 | ogs_sbi_free_nr_location(NrLocation); |
1403 | 0 | return NULL; |
1404 | 0 | } |
1405 | 0 | Tai->tac = ogs_uint24_to_0string(tai->tac); |
1406 | 0 | if (!Tai->tac) { |
1407 | 0 | ogs_error("ogs_uint24_to_0string() failed"); |
1408 | 0 | ogs_sbi_free_nr_location(NrLocation); |
1409 | 0 | return NULL; |
1410 | 0 | } |
1411 | | |
1412 | 0 | NrLocation->ncgi = Ncgi = ogs_calloc(1, sizeof(*Ncgi)); |
1413 | 0 | if (!Ncgi) { |
1414 | 0 | ogs_error("ogs_calloc() failed"); |
1415 | 0 | ogs_sbi_free_nr_location(NrLocation); |
1416 | 0 | return NULL; |
1417 | 0 | } |
1418 | 0 | Ncgi->plmn_id = ogs_sbi_build_plmn_id(&nr_cgi->plmn_id); |
1419 | 0 | if (!Ncgi->plmn_id) { |
1420 | 0 | ogs_error("ogs_sbi_build_plmn_id() failed"); |
1421 | 0 | ogs_sbi_free_nr_location(NrLocation); |
1422 | 0 | return NULL; |
1423 | 0 | } |
1424 | 0 | Ncgi->nr_cell_id = ogs_uint36_to_0string(nr_cgi->cell_id); |
1425 | 0 | if (!Ncgi->nr_cell_id) { |
1426 | 0 | ogs_error("ogs_uint36_to_0string() failed"); |
1427 | 0 | ogs_sbi_free_nr_location(NrLocation); |
1428 | 0 | return NULL; |
1429 | 0 | } |
1430 | | |
1431 | 0 | return NrLocation; |
1432 | 0 | } |
1433 | | |
1434 | | bool ogs_sbi_parse_nr_location(ogs_5gs_tai_t *tai, ogs_nr_cgi_t *nr_cgi, |
1435 | | const OpenAPI_nr_location_t *NrLocation) |
1436 | 0 | { |
1437 | 0 | OpenAPI_tai_t *Tai = NULL; |
1438 | 0 | OpenAPI_ncgi_t *Ncgi = NULL; |
1439 | |
|
1440 | 0 | ogs_assert(tai); |
1441 | 0 | ogs_assert(nr_cgi); |
1442 | 0 | ogs_assert(NrLocation); |
1443 | | |
1444 | 0 | Tai = NrLocation->tai; |
1445 | 0 | if (Tai) { |
1446 | 0 | if (Tai->plmn_id) |
1447 | 0 | ogs_sbi_parse_plmn_id(&tai->plmn_id, Tai->plmn_id); |
1448 | 0 | if (Tai->tac) |
1449 | 0 | tai->tac = ogs_uint24_from_string_hexadecimal(Tai->tac); |
1450 | 0 | } |
1451 | |
|
1452 | 0 | Ncgi = NrLocation->ncgi; |
1453 | 0 | if (Ncgi) { |
1454 | 0 | if (Ncgi->plmn_id) |
1455 | 0 | ogs_sbi_parse_plmn_id(&nr_cgi->plmn_id, Ncgi->plmn_id); |
1456 | 0 | if (Ncgi->nr_cell_id) |
1457 | 0 | nr_cgi->cell_id = ogs_uint64_from_string_hexadecimal( |
1458 | 0 | Ncgi->nr_cell_id); |
1459 | |
|
1460 | 0 | } |
1461 | |
|
1462 | 0 | return true; |
1463 | 0 | } |
1464 | | |
1465 | | void ogs_sbi_free_nr_location(OpenAPI_nr_location_t *NrLocation) |
1466 | 0 | { |
1467 | 0 | OpenAPI_tai_t *Tai = NULL; |
1468 | 0 | OpenAPI_ncgi_t *Ncgi = NULL; |
1469 | |
|
1470 | 0 | ogs_assert(NrLocation); |
1471 | | |
1472 | 0 | Tai = NrLocation->tai; |
1473 | 0 | if (Tai) { |
1474 | 0 | if (Tai->plmn_id) |
1475 | 0 | ogs_sbi_free_plmn_id(Tai->plmn_id); |
1476 | 0 | if (Tai->tac) |
1477 | 0 | ogs_free(Tai->tac); |
1478 | 0 | ogs_free(Tai); |
1479 | 0 | } |
1480 | |
|
1481 | 0 | Ncgi = NrLocation->ncgi; |
1482 | 0 | if (Ncgi) { |
1483 | 0 | if (Ncgi->plmn_id) |
1484 | 0 | ogs_sbi_free_plmn_id(Ncgi->plmn_id); |
1485 | 0 | if (Ncgi->nr_cell_id) |
1486 | 0 | ogs_free(Ncgi->nr_cell_id); |
1487 | 0 | ogs_free(Ncgi); |
1488 | 0 | } |
1489 | |
|
1490 | 0 | ogs_free(NrLocation); |
1491 | 0 | } |
1492 | | |
1493 | | OpenAPI_pcc_rule_t *ogs_sbi_build_pcc_rule( |
1494 | | const ogs_pcc_rule_t *pcc_rule, int flow_presence) |
1495 | 0 | { |
1496 | 0 | OpenAPI_pcc_rule_t *PccRule = NULL; |
1497 | 0 | OpenAPI_list_t *FlowInformationList = NULL; |
1498 | 0 | OpenAPI_flow_information_t *FlowInformation = NULL; |
1499 | |
|
1500 | 0 | int i; |
1501 | |
|
1502 | 0 | ogs_assert(pcc_rule); |
1503 | | |
1504 | 0 | PccRule = ogs_calloc(1, sizeof(*PccRule)); |
1505 | 0 | ogs_assert(PccRule); |
1506 | | |
1507 | | /* |
1508 | | * At this point, only 1 QosData is used for PccRule. |
1509 | | * Therefore, QoS ID uses the same value as PCC Rule ID. |
1510 | | */ |
1511 | 0 | PccRule->pcc_rule_id = pcc_rule->id; |
1512 | |
|
1513 | 0 | PccRule->ref_qos_data = OpenAPI_list_create(); |
1514 | 0 | ogs_assert(PccRule->ref_qos_data); |
1515 | | |
1516 | 0 | OpenAPI_list_add(PccRule->ref_qos_data, PccRule->pcc_rule_id); |
1517 | |
|
1518 | 0 | PccRule->is_precedence = true; |
1519 | 0 | PccRule->precedence = pcc_rule->precedence; |
1520 | |
|
1521 | 0 | if (flow_presence == 1) { |
1522 | 0 | FlowInformationList = OpenAPI_list_create(); |
1523 | 0 | ogs_assert(FlowInformationList); |
1524 | | |
1525 | 0 | for (i = 0; i < pcc_rule->num_of_flow; i++) { |
1526 | 0 | const ogs_flow_t *flow = &pcc_rule->flow[i]; |
1527 | 0 | ogs_assert(flow); |
1528 | | |
1529 | 0 | FlowInformation = ogs_calloc(1, sizeof(*FlowInformation)); |
1530 | 0 | ogs_assert(FlowInformation); |
1531 | | |
1532 | 0 | if (flow->direction == OGS_FLOW_UPLINK_ONLY) |
1533 | 0 | FlowInformation->flow_direction = |
1534 | 0 | OpenAPI_flow_direction_UPLINK; |
1535 | 0 | else if (flow->direction == OGS_FLOW_DOWNLINK_ONLY) |
1536 | 0 | FlowInformation->flow_direction = |
1537 | 0 | OpenAPI_flow_direction_DOWNLINK; |
1538 | 0 | else if (flow->direction == OGS_FLOW_BIDIRECTIONAL) |
1539 | 0 | FlowInformation->flow_direction = |
1540 | 0 | OpenAPI_flow_direction_BIDIRECTIONAL; |
1541 | 0 | else { |
1542 | 0 | ogs_fatal("Unsupported direction [%d]", flow->direction); |
1543 | 0 | ogs_assert_if_reached(); |
1544 | 0 | } |
1545 | | |
1546 | 0 | ogs_assert(flow->description); |
1547 | 0 | FlowInformation->flow_description = flow->description; |
1548 | |
|
1549 | 0 | OpenAPI_list_add(FlowInformationList, FlowInformation); |
1550 | 0 | } |
1551 | | |
1552 | 0 | if (FlowInformationList->count) |
1553 | 0 | PccRule->flow_infos = FlowInformationList; |
1554 | 0 | else |
1555 | 0 | OpenAPI_list_free(FlowInformationList); |
1556 | 0 | } |
1557 | | |
1558 | 0 | return PccRule; |
1559 | 0 | } |
1560 | | |
1561 | | void ogs_sbi_free_pcc_rule(OpenAPI_pcc_rule_t *PccRule) |
1562 | 0 | { |
1563 | 0 | OpenAPI_flow_information_t *FlowInformation = NULL; |
1564 | 0 | OpenAPI_lnode_t *node = NULL; |
1565 | |
|
1566 | 0 | ogs_assert(PccRule); |
1567 | | |
1568 | 0 | if (PccRule->ref_qos_data) |
1569 | 0 | OpenAPI_list_free(PccRule->ref_qos_data); |
1570 | 0 | if (PccRule->flow_infos) { |
1571 | 0 | OpenAPI_list_for_each(PccRule->flow_infos, node) { |
1572 | 0 | FlowInformation = node->data; |
1573 | 0 | if (FlowInformation) ogs_free(FlowInformation); |
1574 | 0 | } |
1575 | 0 | OpenAPI_list_free(PccRule->flow_infos); |
1576 | 0 | } |
1577 | 0 | ogs_free(PccRule); |
1578 | 0 | } |
1579 | | |
1580 | | OpenAPI_qos_data_t *ogs_sbi_build_qos_data(ogs_pcc_rule_t *pcc_rule) |
1581 | 0 | { |
1582 | 0 | OpenAPI_qos_data_t *QosData = NULL; |
1583 | |
|
1584 | 0 | ogs_assert(pcc_rule); |
1585 | | |
1586 | 0 | QosData = ogs_calloc(1, sizeof(*QosData)); |
1587 | 0 | ogs_assert(QosData); |
1588 | | |
1589 | | /* |
1590 | | * At this point, only 1 QosData is used for PccRule. |
1591 | | * Therefore, QoS ID uses the same value as PCC Rule ID. |
1592 | | */ |
1593 | 0 | QosData->qos_id = pcc_rule->id; |
1594 | |
|
1595 | 0 | QosData->is__5qi = true; |
1596 | 0 | QosData->_5qi = pcc_rule->qos.index; |
1597 | 0 | QosData->is_priority_level = true; |
1598 | 0 | QosData->priority_level = pcc_rule->qos.arp.priority_level; |
1599 | |
|
1600 | 0 | QosData->arp = ogs_calloc(1, sizeof(OpenAPI_arp_t)); |
1601 | 0 | ogs_assert(QosData->arp); |
1602 | | |
1603 | 0 | if (pcc_rule->qos.arp.pre_emption_capability == |
1604 | 0 | OGS_5GC_PRE_EMPTION_ENABLED) |
1605 | 0 | QosData->arp->preempt_cap = |
1606 | 0 | OpenAPI_preemption_capability_MAY_PREEMPT; |
1607 | 0 | else if (pcc_rule->qos.arp.pre_emption_capability == |
1608 | 0 | OGS_5GC_PRE_EMPTION_DISABLED) |
1609 | 0 | QosData->arp->preempt_cap = |
1610 | 0 | OpenAPI_preemption_capability_NOT_PREEMPT; |
1611 | 0 | ogs_assert(pcc_rule->qos.arp.pre_emption_capability); |
1612 | | |
1613 | 0 | if (pcc_rule->qos.arp.pre_emption_vulnerability == |
1614 | 0 | OGS_5GC_PRE_EMPTION_ENABLED) |
1615 | 0 | QosData->arp->preempt_vuln = |
1616 | 0 | OpenAPI_preemption_vulnerability_PREEMPTABLE; |
1617 | 0 | else if (pcc_rule->qos.arp.pre_emption_vulnerability == |
1618 | 0 | OGS_5GC_PRE_EMPTION_DISABLED) |
1619 | 0 | QosData->arp->preempt_vuln = |
1620 | 0 | OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE; |
1621 | 0 | ogs_assert(pcc_rule->qos.arp.pre_emption_vulnerability); |
1622 | 0 | QosData->arp->priority_level = pcc_rule->qos.arp.priority_level; |
1623 | |
|
1624 | 0 | if (pcc_rule->qos.mbr.uplink) |
1625 | 0 | QosData->maxbr_ul = ogs_sbi_bitrate_to_string( |
1626 | 0 | pcc_rule->qos.mbr.uplink, OGS_SBI_BITRATE_BPS); |
1627 | 0 | if (pcc_rule->qos.mbr.downlink) |
1628 | 0 | QosData->maxbr_dl = ogs_sbi_bitrate_to_string( |
1629 | 0 | pcc_rule->qos.mbr.downlink, OGS_SBI_BITRATE_BPS); |
1630 | |
|
1631 | 0 | if (pcc_rule->qos.gbr.uplink) |
1632 | 0 | QosData->gbr_ul = ogs_sbi_bitrate_to_string( |
1633 | 0 | pcc_rule->qos.gbr.uplink, OGS_SBI_BITRATE_BPS); |
1634 | 0 | if (pcc_rule->qos.gbr.downlink) |
1635 | 0 | QosData->gbr_dl = ogs_sbi_bitrate_to_string( |
1636 | 0 | pcc_rule->qos.gbr.downlink, OGS_SBI_BITRATE_BPS); |
1637 | |
|
1638 | 0 | return QosData; |
1639 | 0 | } |
1640 | | |
1641 | | void ogs_sbi_free_qos_data(OpenAPI_qos_data_t *QosData) |
1642 | 0 | { |
1643 | 0 | ogs_assert(QosData); |
1644 | | |
1645 | 0 | if (QosData->arp) ogs_free(QosData->arp); |
1646 | 0 | if (QosData->maxbr_ul) ogs_free(QosData->maxbr_ul); |
1647 | 0 | if (QosData->maxbr_dl) ogs_free(QosData->maxbr_dl); |
1648 | 0 | if (QosData->gbr_ul) ogs_free(QosData->gbr_ul); |
1649 | 0 | if (QosData->gbr_dl) ogs_free(QosData->gbr_dl); |
1650 | |
|
1651 | | ogs_free(QosData); |
1652 | 0 | } |