Bug Summary

File:.build-ci/../libnvme/src/nvme/nbft.c
Warning:line 770, column 13
Value of 'errno' was not checked and may be overwritten by function 'malloc'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nbft.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I libnvme/src/libnvme3.so.3.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu99 -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-1 -x c ../libnvme/src/nvme/nbft.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2021-2022, Dell Inc. or its subsidiaries. All Rights Reserved.
5 *
6 * Authors: Stuart Hayes <Stuart_Hayes@Dell.com>
7 *
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12
13#include <arpa/inet.h>
14
15#include <ccan/endian/endian.h>
16
17#include <libnvme.h>
18
19#include "private.h"
20#include "compiler-attributes.h"
21
22static __u8 csum(const __u8 *buffer, ssize_t length)
23{
24 int n;
25 __u8 sum = 0;
26
27 for (n = 0; n < length; n++)
28 sum = (__u8)(sum + ((__u8 *)buffer)[n]);
29 return sum;
30}
31
32static void format_ip_addr(char *buf, size_t buflen, __u8 *addr)
33{
34 struct in6_addr addr_ipv6;
35
36 memcpy(&addr_ipv6, addr, sizeof(addr_ipv6));
37 if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (&addr_ipv6); __a->__in6_u.__u6_addr32[0] == 0 &&
__a->__in6_u.__u6_addr32[1] == 0 && __a->__in6_u
.__u6_addr32[2] == __bswap_32 (0xffff); }))
)
38 /* ipv4 */
39 inet_ntop(AF_INET2, &addr_ipv6.s6_addr32__in6_u.__u6_addr32[3], buf, buflen);
40 else
41 /* ipv6 */
42 inet_ntop(AF_INET610, &addr_ipv6, buf, buflen);
43}
44
45static bool_Bool in_heap(struct nbft_header *header, struct nbft_heap_obj obj)
46{
47 if (le16_to_cpu(obj.length) == 0)
48 return true1;
49 if (le32_to_cpu(obj.offset) < le32_to_cpu(header->heap_offset))
50 return false0;
51 if (le32_to_cpu(obj.offset) >
52 le32_to_cpu(header->heap_offset) + le32_to_cpu(header->heap_length))
53 return false0;
54 if (le32_to_cpu(obj.offset) + le16_to_cpu(obj.length) >
55 le32_to_cpu(header->heap_offset) + le32_to_cpu(header->heap_length))
56 return false0;
57 return true1;
58}
59
60/*
61 * Return transport_type string (NBFT Table 2)
62 */
63static char *trtype_to_string(__u8 transport_type)
64{
65 switch (transport_type) {
66 case 3:
67 return "tcp";
68 default:
69 return "invalid";
70 }
71}
72
73#define verify(ctx, condition, message)do { if (!(condition)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG
, ((void*)0), "file %s: " message "\n", nbft->filename); return
-22; } } while (0)
\
74 do { \
75 if (!(condition)) { \
76 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "file %s: " message "\n", \__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
message "\n", nbft->filename)
77 nbft->filename)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
message "\n", nbft->filename)
; \
78 return -EINVAL22; \
79 } \
80 } while (0)
81
82static int __get_heap_obj(struct libnvme_global_ctx *ctx,
83 struct nbft_header *header, const char *filename,
84 const char *descriptorname, const char *fieldname,
85 struct nbft_heap_obj obj, bool_Bool is_string,
86 char **output)
87{
88 if (le16_to_cpu(obj.length) == 0)
89 return -ENOENT2;
90
91 if (!in_heap(header, obj)) {
92 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: field '%s' in descriptor '%s' has invalid offset or length\n"
, filename, fieldname, descriptorname)
93 "file %s: field '%s' in descriptor '%s' has invalid offset or length\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: field '%s' in descriptor '%s' has invalid offset or length\n"
, filename, fieldname, descriptorname)
94 filename, fieldname, descriptorname)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: field '%s' in descriptor '%s' has invalid offset or length\n"
, filename, fieldname, descriptorname)
;
95 return -EINVAL22;
96 }
97
98 /* check that string is zero terminated correctly */
99 *output = (char *)header + le32_to_cpu(obj.offset);
100
101 if (is_string) {
102 if (strnlen(*output, le16_to_cpu(obj.length) + 1) <
103 le16_to_cpu(obj.length)) {
104 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n"
, filename, fieldname, descriptorname, strnlen(*output, le16_to_cpu
(obj.length) + 1), le16_to_cpu(obj.length))
105 "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n"
, filename, fieldname, descriptorname, strnlen(*output, le16_to_cpu
(obj.length) + 1), le16_to_cpu(obj.length))
106 filename, fieldname, descriptorname,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n"
, filename, fieldname, descriptorname, strnlen(*output, le16_to_cpu
(obj.length) + 1), le16_to_cpu(obj.length))
107 strnlen(*output, le16_to_cpu(obj.length) + 1),__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n"
, filename, fieldname, descriptorname, strnlen(*output, le16_to_cpu
(obj.length) + 1), le16_to_cpu(obj.length))
108 le16_to_cpu(obj.length))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is shorter (%zd) than specified length (%d)\n"
, filename, fieldname, descriptorname, strnlen(*output, le16_to_cpu
(obj.length) + 1), le16_to_cpu(obj.length))
;
109 } else if (strnlen(*output, le16_to_cpu(obj.length) + 1) >
110 le16_to_cpu(obj.length)) {
111 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is not zero terminated\n"
, filename, fieldname, descriptorname)
112 "file %s: string '%s' in descriptor '%s' is not zero terminated\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is not zero terminated\n"
, filename, fieldname, descriptorname)
113 filename, fieldname, descriptorname)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: string '%s' in descriptor '%s' is not zero terminated\n"
, filename, fieldname, descriptorname)
;
114 return -EINVAL22;
115 }
116 }
117
118 return 0;
119}
120
121#define get_heap_obj(ctx, descriptor, obj, is_string, output)__get_heap_obj(ctx, header, nbft->filename, "descriptor", "obj"
, descriptor->obj, is_string, output)
\
122 __get_heap_obj(ctx, header, nbft->filename, \
123 stringify(descriptor)"descriptor", stringify(obj)"obj", \
124 descriptor->obj, is_string, \
125 output)
126
127static struct libnbft_discovery *discovery_from_index(struct libnbft_info *nbft,
128 int i)
129{
130 struct libnbft_discovery **d;
131
132 for (d = nbft->discovery_list; d && *d; d++) {
133 if ((*d)->index == i)
134 return *d;
135 }
136 return NULL((void*)0);
137}
138
139static struct libnbft_hfi *hfi_from_index(struct libnbft_info *nbft, int i)
140{
141 struct libnbft_hfi **h;
142
143 for (h = nbft->hfi_list; h && *h; h++) {
144 if ((*h)->index == i)
145 return *h;
146 }
147 return NULL((void*)0);
148}
149
150static struct libnbft_security *security_from_index(struct libnbft_info *nbft,
151 int i)
152{
153 struct libnbft_security **s;
154
155 for (s = nbft->security_list; s && *s; s++) {
156 if ((*s)->index == i)
157 return *s;
158 }
159 return NULL((void*)0);
160}
161
162static int read_ssns_exended_info(struct libnvme_global_ctx *ctx,
163 struct libnbft_info *nbft, struct libnbft_subsystem_ns *ssns,
164 struct nbft_ssns_ext_info *raw_ssns_ei)
165{
166 struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
167
168 verify(ctx, raw_ssns_ei->structure_id == NBFT_DESC_SSNS_EXT_INFO,do { if (!(raw_ssns_ei->structure_id == NBFT_DESC_SSNS_EXT_INFO
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid ID in SSNS extended info descriptor" "\n", nbft->
filename); return -22; } } while (0)
169 "invalid ID in SSNS extended info descriptor")do { if (!(raw_ssns_ei->structure_id == NBFT_DESC_SSNS_EXT_INFO
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid ID in SSNS extended info descriptor" "\n", nbft->
filename); return -22; } } while (0)
;
170 verify(ctx, raw_ssns_ei->version == 1,do { if (!(raw_ssns_ei->version == 1)) { __libnvme_msg(ctx
, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid version in SSNS extended info descriptor"
"\n", nbft->filename); return -22; } } while (0)
171 "invalid version in SSNS extended info descriptor")do { if (!(raw_ssns_ei->version == 1)) { __libnvme_msg(ctx
, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid version in SSNS extended info descriptor"
"\n", nbft->filename); return -22; } } while (0)
;
172 verify(ctx, le16_to_cpu(raw_ssns_ei->ssns_index) == ssns->index,do { if (!(le16_to_cpu(raw_ssns_ei->ssns_index) == ssns->
index)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"SSNS index doesn't match extended info descriptor index" "\n"
, nbft->filename); return -22; } } while (0)
173 "SSNS index doesn't match extended info descriptor index")do { if (!(le16_to_cpu(raw_ssns_ei->ssns_index) == ssns->
index)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"SSNS index doesn't match extended info descriptor index" "\n"
, nbft->filename); return -22; } } while (0)
;
174
175 if (!(le32_to_cpu(raw_ssns_ei->flags) & NBFT_SSNS_EXT_INFO_VALID))
176 return -EINVAL22;
177
178 if (le32_to_cpu(raw_ssns_ei->flags) & NBFT_SSNS_EXT_INFO_ADMIN_ASQSZ)
179 ssns->asqsz = le16_to_cpu(raw_ssns_ei->asqsz);
180 ssns->controller_id = le16_to_cpu(raw_ssns_ei->cntlid);
181 get_heap_obj(ctx, raw_ssns_ei, dhcp_root_path_str_obj, 1,__get_heap_obj(ctx, header, nbft->filename, "raw_ssns_ei",
"dhcp_root_path_str_obj", raw_ssns_ei->dhcp_root_path_str_obj
, 1, &ssns->dhcp_root_path_string)
182 &ssns->dhcp_root_path_string)__get_heap_obj(ctx, header, nbft->filename, "raw_ssns_ei",
"dhcp_root_path_str_obj", raw_ssns_ei->dhcp_root_path_str_obj
, 1, &ssns->dhcp_root_path_string)
;
183
184 return 0;
185}
186
187static int read_ssns(struct libnvme_global_ctx *ctx,
188 struct libnbft_info *nbft, struct nbft_ssns *raw_ssns,
189 struct libnbft_subsystem_ns **s)
190{
191 struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
192 struct libnbft_subsystem_ns *ssns;
193 __u8 *ss_hfi_indexes = NULL((void*)0);
194 __u8 *tmp = NULL((void*)0);
195 int i, ret;
196
197 if (!(le16_to_cpu(raw_ssns->flags) & NBFT_SSNS_VALID))
198 return -EINVAL22;
199
200 verify(ctx, raw_ssns->structure_id == NBFT_DESC_SSNS,do { if (!(raw_ssns->structure_id == NBFT_DESC_SSNS)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in SSNS descriptor"
"\n", nbft->filename); return -22; } } while (0)
201 "invalid ID in SSNS descriptor")do { if (!(raw_ssns->structure_id == NBFT_DESC_SSNS)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in SSNS descriptor"
"\n", nbft->filename); return -22; } } while (0)
;
202
203 /* verify transport type */
204 verify(ctx, raw_ssns->trtype == NBFT_TRTYPE_TCP,do { if (!(raw_ssns->trtype == NBFT_TRTYPE_TCP)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid transport type in SSNS descriptor"
"\n", nbft->filename); return -22; } } while (0)
205 "invalid transport type in SSNS descriptor")do { if (!(raw_ssns->trtype == NBFT_TRTYPE_TCP)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid transport type in SSNS descriptor"
"\n", nbft->filename); return -22; } } while (0)
;
206
207 ssns = calloc(1, sizeof(*ssns));
208 if (!ssns)
209 return -ENOMEM12;
210
211 ssns->index = le16_to_cpu(raw_ssns->index);
212 strncpy(ssns->transport, trtype_to_string(raw_ssns->trtype),
213 sizeof(ssns->transport));
214
215 /* transport specific flags */
216 if (raw_ssns->trtype == NBFT_TRTYPE_TCP) {
217 if (le16_to_cpu(raw_ssns->trflags) &
218 NBFT_SSNS_PDU_HEADER_DIGEST)
219 ssns->pdu_header_digest_required = true1;
220 if (le16_to_cpu(raw_ssns->trflags) &
221 NBFT_SSNS_DATA_DIGEST)
222 ssns->data_digest_required = true1;
223 }
224
225 /* primary discovery controller */
226 if (raw_ssns->primary_discovery_ctrl_index) {
227 ssns->discovery = discovery_from_index(nbft,
228 raw_ssns->primary_discovery_ctrl_index);
229 if (!ssns->discovery)
230 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: namespace %d discovery controller not found\n"
, nbft->filename, ssns->index)
231 "file %s: namespace %d discovery controller not found\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: namespace %d discovery controller not found\n"
, nbft->filename, ssns->index)
232 nbft->filename, ssns->index)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: namespace %d discovery controller not found\n"
, nbft->filename, ssns->index)
;
233 }
234
235 /* subsystem transport address */
236 ret = get_heap_obj(ctx, raw_ssns, subsys_traddr_obj, 0, (char **)&tmp)__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "subsys_traddr_obj"
, raw_ssns->subsys_traddr_obj, 0, (char **)&tmp)
;
237 if (ret)
238 goto fail;
239
240 format_ip_addr(ssns->traddr, sizeof(ssns->traddr), tmp);
241
242 /* subsystem transport service identifier */
243 ret = get_heap_obj(ctx, raw_ssns, subsys_trsvcid_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "subsys_trsvcid_obj"
, raw_ssns->subsys_trsvcid_obj, 1, &ssns->trsvcid)
244 1, &ssns->trsvcid)__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "subsys_trsvcid_obj"
, raw_ssns->subsys_trsvcid_obj, 1, &ssns->trsvcid)
;
245 if (ret)
246 goto fail;
247
248 /* subsystem port ID */
249 ssns->subsys_port_id = le16_to_cpu(raw_ssns->subsys_port_id);
250
251 /* NSID, NID type, & NID */
252 ssns->nsid = le32_to_cpu(raw_ssns->nsid);
253 ssns->nid_type = raw_ssns->nidt;
254 ssns->nid = raw_ssns->nid;
255
256 /* flags */
257 ssns->unavailable = !!(le16_to_cpu(raw_ssns->flags) &
258 NBFT_SSNS_UNAVAIL_NAMESPACE_UNAVAIL);
259 ssns->discovered = !!(le16_to_cpu(raw_ssns->flags) &
260 NBFT_SSNS_DISCOVERED_NAMESPACE);
261
262 /* security profile */
263 if (raw_ssns->security_desc_index) {
264 ssns->security = security_from_index(nbft,
265 raw_ssns->security_desc_index);
266 if (!ssns->security)
267 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: namespace %d security controller not found\n"
, nbft->filename, ssns->index)
268 "file %s: namespace %d security controller not found\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: namespace %d security controller not found\n"
, nbft->filename, ssns->index)
269 nbft->filename, ssns->index)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: namespace %d security controller not found\n"
, nbft->filename, ssns->index)
;
270 }
271
272 /* HFI descriptors */
273 ret = get_heap_obj(ctx, raw_ssns, secondary_hfi_assoc_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "secondary_hfi_assoc_obj"
, raw_ssns->secondary_hfi_assoc_obj, 0, (char **)&ss_hfi_indexes
)
274 0, (char **)&ss_hfi_indexes)__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "secondary_hfi_assoc_obj"
, raw_ssns->secondary_hfi_assoc_obj, 0, (char **)&ss_hfi_indexes
)
;
275 if (ret)
276 goto fail;
277
278 ssns->hfis =
279 calloc(le16_to_cpu(raw_ssns->secondary_hfi_assoc_obj.length) +
280 2, sizeof(*ssns->hfis));
281 if (!ssns->hfis) {
282 ret = -ENOMEM12;
283 goto fail;
284 }
285 ssns->hfis[0] = hfi_from_index(nbft, raw_ssns->primary_hfi_desc_index);
286 if (!ssns->hfis[0]) {
287 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d: HFI %d not found\n"
, nbft->filename, ssns->index, raw_ssns->primary_hfi_desc_index
)
288 "file %s: SSNS %d: HFI %d not found\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d: HFI %d not found\n"
, nbft->filename, ssns->index, raw_ssns->primary_hfi_desc_index
)
289 nbft->filename, ssns->index,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d: HFI %d not found\n"
, nbft->filename, ssns->index, raw_ssns->primary_hfi_desc_index
)
290 raw_ssns->primary_hfi_desc_index)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d: HFI %d not found\n"
, nbft->filename, ssns->index, raw_ssns->primary_hfi_desc_index
)
;
291 ret = -EINVAL22;
292 goto fail;
293 }
294 ssns->num_hfis = 1;
295 for (i = 0; i < le16_to_cpu(raw_ssns->secondary_hfi_assoc_obj.length);
296 i++) {
297 bool_Bool duplicate = false0;
298 int j;
299
300 for (j = 0; j < i; j++) {
301 if (ss_hfi_indexes[i] == ss_hfi_indexes[j]) {
302 duplicate = true1;
303 break;
304 }
305 }
306
307 if (!duplicate &&
308 ss_hfi_indexes[i] == raw_ssns->primary_hfi_desc_index)
309 duplicate = true1;
310
311 if (duplicate) {
312 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d skipping duplicate HFI index %d\n"
, nbft->filename, ssns->index, ss_hfi_indexes[i])
313 "file %s: SSNS %d skipping duplicate HFI index %d\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d skipping duplicate HFI index %d\n"
, nbft->filename, ssns->index, ss_hfi_indexes[i])
314 nbft->filename, ssns->index, ss_hfi_indexes[i])__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d skipping duplicate HFI index %d\n"
, nbft->filename, ssns->index, ss_hfi_indexes[i])
;
315 continue;
316 }
317
318 ssns->hfis[i + 1] = hfi_from_index(nbft, ss_hfi_indexes[i]);
319 if (ss_hfi_indexes[i] && !ssns->hfis[i + 1])
320 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d HFI %d not found\n"
, nbft->filename, ssns->index, ss_hfi_indexes[i])
321 "file %s: SSNS %d HFI %d not found\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d HFI %d not found\n"
, nbft->filename, ssns->index, ss_hfi_indexes[i])
322 nbft->filename, ssns->index, ss_hfi_indexes[i])__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: SSNS %d HFI %d not found\n"
, nbft->filename, ssns->index, ss_hfi_indexes[i])
;
323 else
324 ssns->num_hfis++;
325 }
326
327 /* SSNS NQN */
328 ret = get_heap_obj(ctx, raw_ssns, subsys_ns_nqn_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "subsys_ns_nqn_obj"
, raw_ssns->subsys_ns_nqn_obj, 1, &ssns->subsys_nqn
)
329 1, &ssns->subsys_nqn)__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "subsys_ns_nqn_obj"
, raw_ssns->subsys_ns_nqn_obj, 1, &ssns->subsys_nqn
)
;
330 if (ret)
331 goto fail;
332
333 /* SSNS extended info */
334 if (le16_to_cpu(raw_ssns->flags) & NBFT_SSNS_EXTENDED_INFO_IN_USE) {
335 struct nbft_ssns_ext_info *ssns_extended_info;
336
337 if (!get_heap_obj(ctx, raw_ssns, ssns_extended_info_desc_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "ssns_extended_info_desc_obj"
, raw_ssns->ssns_extended_info_desc_obj, 0, (char **)&
ssns_extended_info)
338 0, (char **)&ssns_extended_info)__get_heap_obj(ctx, header, nbft->filename, "raw_ssns", "ssns_extended_info_desc_obj"
, raw_ssns->ssns_extended_info_desc_obj, 0, (char **)&
ssns_extended_info)
) {
339 read_ssns_exended_info(ctx, nbft, ssns,
340 ssns_extended_info);
341 }
342 }
343
344 *s = ssns;
345 return 0;
346
347fail:
348 free(ssns);
349 return ret;
350}
351
352static int read_hfi_info_tcp(struct libnvme_global_ctx *ctx,
353 struct libnbft_info *nbft,
354 struct nbft_hfi_info_tcp *raw_hfi_info_tcp,
355 struct libnbft_hfi *hfi)
356{
357 struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
358
359 if ((raw_hfi_info_tcp->flags & NBFT_HFI_INFO_TCP_VALID) == 0)
360 return -EINVAL22;
361
362 verify(ctx, raw_hfi_info_tcp->structure_id == NBFT_DESC_HFI_TRINFO,do { if (!(raw_hfi_info_tcp->structure_id == NBFT_DESC_HFI_TRINFO
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid ID in HFI transport descriptor" "\n", nbft->filename
); return -22; } } while (0)
363 "invalid ID in HFI transport descriptor")do { if (!(raw_hfi_info_tcp->structure_id == NBFT_DESC_HFI_TRINFO
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid ID in HFI transport descriptor" "\n", nbft->filename
); return -22; } } while (0)
;
364 verify(ctx, raw_hfi_info_tcp->version == 1,do { if (!(raw_hfi_info_tcp->version == 1)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid version in HFI transport descriptor"
"\n", nbft->filename); return -22; } } while (0)
365 "invalid version in HFI transport descriptor")do { if (!(raw_hfi_info_tcp->version == 1)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid version in HFI transport descriptor"
"\n", nbft->filename); return -22; } } while (0)
;
366 if (le16_to_cpu(raw_hfi_info_tcp->hfi_index) != hfi->index)
367 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: HFI descriptor index %d does not match index in HFI transport descriptor\n"
, nbft->filename, hfi->index)
368 "file %s: HFI descriptor index %d does not match index in HFI transport descriptor\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: HFI descriptor index %d does not match index in HFI transport descriptor\n"
, nbft->filename, hfi->index)
369 nbft->filename, hfi->index)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: HFI descriptor index %d does not match index in HFI transport descriptor\n"
, nbft->filename, hfi->index)
;
370
371 hfi->tcp_info.pci_sbdf = le32_to_cpu(raw_hfi_info_tcp->pci_sbdf);
372 memcpy(hfi->tcp_info.mac_addr, raw_hfi_info_tcp->mac_addr,
373 sizeof(raw_hfi_info_tcp->mac_addr));
374 hfi->tcp_info.vlan = le16_to_cpu(raw_hfi_info_tcp->vlan);
375 hfi->tcp_info.ip_origin = raw_hfi_info_tcp->ip_origin;
376 format_ip_addr(hfi->tcp_info.ipaddr, sizeof(hfi->tcp_info.ipaddr),
377 raw_hfi_info_tcp->ip_address);
378 hfi->tcp_info.subnet_mask_prefix = raw_hfi_info_tcp->subnet_mask_prefix;
379 format_ip_addr(hfi->tcp_info.gateway_ipaddr,
380 sizeof(hfi->tcp_info.ipaddr), raw_hfi_info_tcp->ip_gateway);
381 hfi->tcp_info.route_metric =
382 le16_to_cpu(raw_hfi_info_tcp->route_metric);
383 format_ip_addr(hfi->tcp_info.primary_dns_ipaddr,
384 sizeof(hfi->tcp_info.primary_dns_ipaddr),
385 raw_hfi_info_tcp->primary_dns);
386 format_ip_addr(hfi->tcp_info.secondary_dns_ipaddr,
387 sizeof(hfi->tcp_info.secondary_dns_ipaddr),
388 raw_hfi_info_tcp->secondary_dns);
389 if (raw_hfi_info_tcp->flags & NBFT_HFI_INFO_TCP_DHCP_OVERRIDE) {
390 hfi->tcp_info.dhcp_override = true1;
391 format_ip_addr(hfi->tcp_info.dhcp_server_ipaddr,
392 sizeof(hfi->tcp_info.dhcp_server_ipaddr),
393 raw_hfi_info_tcp->dhcp_server);
394 }
395 get_heap_obj(ctx, raw_hfi_info_tcp, host_name_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_hfi_info_tcp"
, "host_name_obj", raw_hfi_info_tcp->host_name_obj, 1, &
hfi->tcp_info.host_name)
396 1, &hfi->tcp_info.host_name)__get_heap_obj(ctx, header, nbft->filename, "raw_hfi_info_tcp"
, "host_name_obj", raw_hfi_info_tcp->host_name_obj, 1, &
hfi->tcp_info.host_name)
;
397 if (raw_hfi_info_tcp->flags & NBFT_HFI_INFO_TCP_GLOBAL_ROUTE)
398 hfi->tcp_info.this_hfi_is_default_route = true1;
399
400 return 0;
401}
402
403static int read_hfi(struct libnvme_global_ctx *ctx, struct libnbft_info *nbft,
404 struct nbft_hfi *raw_hfi, struct libnbft_hfi **h)
405{
406 int ret;
407 struct libnbft_hfi *hfi;
408 struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
409
410 if (!(raw_hfi->flags & NBFT_HFI_VALID))
411 return -EINVAL22;
412
413 verify(ctx, raw_hfi->structure_id == NBFT_DESC_HFI,do { if (!(raw_hfi->structure_id == NBFT_DESC_HFI)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in HFI descriptor"
"\n", nbft->filename); return -22; } } while (0)
414 "invalid ID in HFI descriptor")do { if (!(raw_hfi->structure_id == NBFT_DESC_HFI)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in HFI descriptor"
"\n", nbft->filename); return -22; } } while (0)
;
415
416 hfi = calloc(1, sizeof(struct libnbft_hfi));
417 if (!hfi)
418 return -ENOMEM12;
419
420 hfi->index = raw_hfi->index;
421
422 /*
423 * read HFI transport descriptor for this HFI
424 */
425 if (raw_hfi->trtype == NBFT_TRTYPE_TCP) {
426 /* TCP */
427 struct nbft_hfi_info_tcp *raw_hfi_info_tcp;
428
429 strncpy(hfi->transport, trtype_to_string(raw_hfi->trtype),
430 sizeof(hfi->transport));
431
432 ret = get_heap_obj(ctx, raw_hfi, trinfo_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_hfi", "trinfo_obj"
, raw_hfi->trinfo_obj, 0, (char **)&raw_hfi_info_tcp)
433 0, (char **)&raw_hfi_info_tcp)__get_heap_obj(ctx, header, nbft->filename, "raw_hfi", "trinfo_obj"
, raw_hfi->trinfo_obj, 0, (char **)&raw_hfi_info_tcp)
;
434 if (ret)
435 goto fail;
436
437 ret = read_hfi_info_tcp(ctx, nbft, raw_hfi_info_tcp, hfi);
438 if (ret)
439 goto fail;
440 } else {
441 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: invalid transport type %d\n"
, nbft->filename, raw_hfi->trtype)
442 "file %s: invalid transport type %d\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: invalid transport type %d\n"
, nbft->filename, raw_hfi->trtype)
443 nbft->filename, raw_hfi->trtype)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: invalid transport type %d\n"
, nbft->filename, raw_hfi->trtype)
;
444 ret = -EINVAL22;
445 goto fail;
446 }
447
448 *h = hfi;
449 return 0;
450
451fail:
452 free(hfi);
453 return ret;
454}
455
456static int read_discovery(struct libnvme_global_ctx *ctx,
457 struct libnbft_info *nbft,
458 struct nbft_discovery *raw_discovery,
459 struct libnbft_discovery **d)
460{
461 struct libnbft_discovery *discovery = NULL((void*)0);
462 struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
463 int r = -EINVAL22;
464
465 if (!(raw_discovery->flags & NBFT_DISCOVERY_VALID))
466 goto error;
467
468 verify(ctx, raw_discovery->structure_id == NBFT_DESC_DISCOVERY,do { if (!(raw_discovery->structure_id == NBFT_DESC_DISCOVERY
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid ID in discovery descriptor" "\n", nbft->filename
); return -22; } } while (0)
469 "invalid ID in discovery descriptor")do { if (!(raw_discovery->structure_id == NBFT_DESC_DISCOVERY
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid ID in discovery descriptor" "\n", nbft->filename
); return -22; } } while (0)
;
470
471 discovery = calloc(1, sizeof(struct libnbft_discovery));
472 if (!discovery) {
473 r = -ENOMEM12;
474 goto error;
475 }
476
477 discovery->index = raw_discovery->index;
478
479 if (get_heap_obj(ctx, raw_discovery, discovery_ctrl_addr_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_discovery"
, "discovery_ctrl_addr_obj", raw_discovery->discovery_ctrl_addr_obj
, 1, &discovery->uri)
480 1, &discovery->uri)__get_heap_obj(ctx, header, nbft->filename, "raw_discovery"
, "discovery_ctrl_addr_obj", raw_discovery->discovery_ctrl_addr_obj
, 1, &discovery->uri)
)
481 goto error;
482
483 if (get_heap_obj(ctx, raw_discovery, discovery_ctrl_nqn_obj,__get_heap_obj(ctx, header, nbft->filename, "raw_discovery"
, "discovery_ctrl_nqn_obj", raw_discovery->discovery_ctrl_nqn_obj
, 1, &discovery->nqn)
484 1, &discovery->nqn)__get_heap_obj(ctx, header, nbft->filename, "raw_discovery"
, "discovery_ctrl_nqn_obj", raw_discovery->discovery_ctrl_nqn_obj
, 1, &discovery->nqn)
)
485 goto error;
486
487 discovery->hfi = hfi_from_index(nbft, raw_discovery->hfi_index);
488 if (raw_discovery->hfi_index && !discovery->hfi)
489 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: discovery %d HFI not found\n"
, nbft->filename, discovery->index)
490 "file %s: discovery %d HFI not found\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: discovery %d HFI not found\n"
, nbft->filename, discovery->index)
491 nbft->filename, discovery->index)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: discovery %d HFI not found\n"
, nbft->filename, discovery->index)
;
492
493 discovery->security =
494 security_from_index(nbft, raw_discovery->sec_index);
495 if (raw_discovery->sec_index && !discovery->security)
496 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: discovery %d security descriptor not found\n"
, nbft->filename, discovery->index)
497 "file %s: discovery %d security descriptor not found\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: discovery %d security descriptor not found\n"
, nbft->filename, discovery->index)
498 nbft->filename, discovery->index)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: discovery %d security descriptor not found\n"
, nbft->filename, discovery->index)
;
499
500 *d = discovery;
501 r = 0;
502
503error:
504 if (r)
505 free(discovery);
506 return r;
507}
508
509static int read_security(struct libnvme_global_ctx *ctx, struct libnbft_info *nbft,
510 struct nbft_security *raw_security,
511 struct libnbft_security **s)
512{
513 return -EINVAL22;
514}
515
516static void read_hfi_descriptors(struct libnvme_global_ctx *ctx,
517 struct libnbft_info *nbft, int num_hfi,
518 struct nbft_hfi *raw_hfi_array, int hfi_len)
519{
520 int i, cnt;
521
522 nbft->hfi_list = calloc(num_hfi + 1, sizeof(struct libnbft_hfi *));
523 for (i = 0, cnt = 0; i < num_hfi; i++) {
524 if (read_hfi(ctx, nbft, &raw_hfi_array[i],
525 &nbft->hfi_list[cnt]) == 0)
526 cnt++;
527 }
528}
529
530static void read_security_descriptors(struct libnvme_global_ctx *ctx,
531 struct libnbft_info *nbft, int num_sec,
532 struct nbft_security *raw_sec_array, int sec_len)
533{
534 int i, cnt;
535
536 nbft->security_list = calloc(num_sec + 1,
537 sizeof(struct libnbft_security *));
538 for (i = 0, cnt = 0; i < num_sec; i++) {
539 if (read_security(ctx, nbft, &raw_sec_array[i],
540 &nbft->security_list[cnt]) == 0)
541 cnt++;
542 }
543}
544
545static void read_discovery_descriptors(struct libnvme_global_ctx *ctx,
546 struct libnbft_info *nbft, int num_disc,
547 struct nbft_discovery *raw_disc_array, int disc_len)
548{
549 int i, cnt;
550
551 nbft->discovery_list =
552 calloc(num_disc + 1, sizeof(struct libnbft_discovery *));
553 for (i = 0, cnt = 0; i < num_disc; i++) {
554 if (read_discovery(ctx, nbft, &raw_disc_array[i],
555 &nbft->discovery_list[cnt]) == 0)
556 cnt++;
557 }
558}
559
560static void read_ssns_descriptors(struct libnvme_global_ctx *ctx,
561 struct libnbft_info *nbft, int num_ssns,
562 struct nbft_ssns *raw_ssns_array, int ssns_len)
563{
564 int i, cnt;
565
566 nbft->subsystem_ns_list =
567 calloc(num_ssns + 1, sizeof(struct libnbft_subsystem_ns *));
568 for (i = 0, cnt = 0; i < num_ssns; i++) {
569 if (read_ssns(ctx, nbft, &raw_ssns_array[i],
570 &nbft->subsystem_ns_list[cnt]) == 0)
571 cnt++;
572 }
573}
574
575/**
576 * parse_raw_nbft - parses raw ACPI NBFT table and fill in abstracted libnbft_info structure
577 * @nbft: libnbft_info struct containing only raw_nbft and raw_nbft_size
578 *
579 * Returns 0 on success, errno otherwise.
580 */
581static int parse_raw_nbft(struct libnvme_global_ctx *ctx, struct libnbft_info *nbft)
582{
583 __u8 *raw_nbft = nbft->raw_nbft;
584 int raw_nbft_size = nbft->raw_nbft_size;
585
586 struct nbft_header *header;
587 struct nbft_control *control;
588 struct nbft_host *host;
589
590 verify(ctx, raw_nbft_size >=do { if (!(raw_nbft_size >= sizeof(struct nbft_header) + sizeof
(struct nbft_control))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG
, ((void*)0), "file %s: " "table is too short" "\n", nbft->
filename); return -22; } } while (0)
591 sizeof(struct nbft_header) + sizeof(struct nbft_control),do { if (!(raw_nbft_size >= sizeof(struct nbft_header) + sizeof
(struct nbft_control))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG
, ((void*)0), "file %s: " "table is too short" "\n", nbft->
filename); return -22; } } while (0)
592 "table is too short")do { if (!(raw_nbft_size >= sizeof(struct nbft_header) + sizeof
(struct nbft_control))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG
, ((void*)0), "file %s: " "table is too short" "\n", nbft->
filename); return -22; } } while (0)
;
593 verify(ctx, csum(raw_nbft, raw_nbft_size) == 0, "invalid checksum")do { if (!(csum(raw_nbft, raw_nbft_size) == 0)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid checksum"
"\n", nbft->filename); return -22; } } while (0)
;
594
595 /*
596 * header
597 */
598 header = (struct nbft_header *)raw_nbft;
599
600 verify(ctx, strncmp(header->signature, NBFT_HEADER_SIG, 4) == 0,do { if (!(strncmp(header->signature, "NBFT", 4) == 0)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid signature"
"\n", nbft->filename); return -22; } } while (0)
601 "invalid signature")do { if (!(strncmp(header->signature, "NBFT", 4) == 0)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid signature"
"\n", nbft->filename); return -22; } } while (0)
;
602 verify(ctx, le32_to_cpu(header->length) <= raw_nbft_size,do { if (!(le32_to_cpu(header->length) <= raw_nbft_size
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"length in header exceeds table length" "\n", nbft->filename
); return -22; } } while (0)
603 "length in header exceeds table length")do { if (!(le32_to_cpu(header->length) <= raw_nbft_size
)) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"length in header exceeds table length" "\n", nbft->filename
); return -22; } } while (0)
;
604 verify(ctx, header->major_revision == 1,do { if (!(header->major_revision == 1)) { __libnvme_msg(ctx
, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "unsupported major revision"
"\n", nbft->filename); return -22; } } while (0)
605 "unsupported major revision")do { if (!(header->major_revision == 1)) { __libnvme_msg(ctx
, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "unsupported major revision"
"\n", nbft->filename); return -22; } } while (0)
;
606 verify(ctx, header->minor_revision == 0,do { if (!(header->minor_revision == 0)) { __libnvme_msg(ctx
, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "unsupported minor revision"
"\n", nbft->filename); return -22; } } while (0)
607 "unsupported minor revision")do { if (!(header->minor_revision == 0)) { __libnvme_msg(ctx
, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "unsupported minor revision"
"\n", nbft->filename); return -22; } } while (0)
;
608 verify(ctx, le32_to_cpu(header->heap_length) +do { if (!(le32_to_cpu(header->heap_length) + le32_to_cpu(
header->heap_offset) <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"heap exceeds table length" "\n", nbft->filename); return
-22; } } while (0)
609 le32_to_cpu(header->heap_offset) <= le32_to_cpu(header->length),do { if (!(le32_to_cpu(header->heap_length) + le32_to_cpu(
header->heap_offset) <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"heap exceeds table length" "\n", nbft->filename); return
-22; } } while (0)
610 "heap exceeds table length")do { if (!(le32_to_cpu(header->heap_length) + le32_to_cpu(
header->heap_offset) <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"heap exceeds table length" "\n", nbft->filename); return
-22; } } while (0)
;
611
612 /*
613 * control
614 */
615 control =
616 (struct nbft_control *)(raw_nbft + sizeof(struct nbft_header));
617
618 if ((control->flags & NBFT_CONTROL_VALID) == 0)
619 return 0;
620 verify(ctx, control->structure_id == NBFT_DESC_CONTROL,do { if (!(control->structure_id == NBFT_DESC_CONTROL)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in control structure"
"\n", nbft->filename); return -22; } } while (0)
621 "invalid ID in control structure")do { if (!(control->structure_id == NBFT_DESC_CONTROL)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in control structure"
"\n", nbft->filename); return -22; } } while (0)
;
622
623 /*
624 * host
625 */
626 verify(ctx, le32_to_cpu(control->hdesc.offset) +do { if (!(le32_to_cpu(control->hdesc.offset) + sizeof(struct
nbft_host) <= le32_to_cpu(header->length) && le32_to_cpu
(control->hdesc.offset) >= sizeof(struct nbft_host))) {
__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"host descriptor offset/length is invalid" "\n", nbft->filename
); return -22; } } while (0)
627 sizeof(struct nbft_host) <= le32_to_cpu(header->length) &&do { if (!(le32_to_cpu(control->hdesc.offset) + sizeof(struct
nbft_host) <= le32_to_cpu(header->length) && le32_to_cpu
(control->hdesc.offset) >= sizeof(struct nbft_host))) {
__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"host descriptor offset/length is invalid" "\n", nbft->filename
); return -22; } } while (0)
628 le32_to_cpu(control->hdesc.offset) >= sizeof(struct nbft_host),do { if (!(le32_to_cpu(control->hdesc.offset) + sizeof(struct
nbft_host) <= le32_to_cpu(header->length) && le32_to_cpu
(control->hdesc.offset) >= sizeof(struct nbft_host))) {
__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"host descriptor offset/length is invalid" "\n", nbft->filename
); return -22; } } while (0)
629 "host descriptor offset/length is invalid")do { if (!(le32_to_cpu(control->hdesc.offset) + sizeof(struct
nbft_host) <= le32_to_cpu(header->length) && le32_to_cpu
(control->hdesc.offset) >= sizeof(struct nbft_host))) {
__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"host descriptor offset/length is invalid" "\n", nbft->filename
); return -22; } } while (0)
;
630 host = (struct nbft_host *)(raw_nbft +
631 le32_to_cpu(control->hdesc.offset));
632
633 verify(ctx, host->flags & NBFT_HOST_VALID,do { if (!(host->flags & NBFT_HOST_VALID)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "host descriptor valid flag not set"
"\n", nbft->filename); return -22; } } while (0)
634 "host descriptor valid flag not set")do { if (!(host->flags & NBFT_HOST_VALID)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "host descriptor valid flag not set"
"\n", nbft->filename); return -22; } } while (0)
;
635 verify(ctx, host->structure_id == NBFT_DESC_HOST,do { if (!(host->structure_id == NBFT_DESC_HOST)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in HOST descriptor"
"\n", nbft->filename); return -22; } } while (0)
636 "invalid ID in HOST descriptor")do { if (!(host->structure_id == NBFT_DESC_HOST)) { __libnvme_msg
(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: " "invalid ID in HOST descriptor"
"\n", nbft->filename); return -22; } } while (0)
;
637 nbft->host.id = (unsigned char *) &(host->host_id);
638 if (get_heap_obj(ctx, host, host_nqn_obj, 1, &nbft->host.nqn)__get_heap_obj(ctx, header, nbft->filename, "host", "host_nqn_obj"
, host->host_nqn_obj, 1, &nbft->host.nqn)
!= 0)
639 return -EINVAL22;
640 nbft->host.host_id_configured =
641 host->flags & NBFT_HOST_HOSTID_CONFIGURED;
642 nbft->host.host_nqn_configured =
643 host->flags & NBFT_HOST_HOSTNQN_CONFIGURED;
644
645 /*
646 * HFI
647 */
648 if (control->num_hfi > 0) {
649 struct nbft_hfi *raw_hfi_array;
650
651 verify(ctx, le32_to_cpu(control->hfio) +do { if (!(le32_to_cpu(control->hfio) + sizeof(struct nbft_hfi
) * control->num_hfi <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid hfi descriptor list offset" "\n", nbft->filename
); return -22; } } while (0)
652 sizeof(struct nbft_hfi) * control->num_hfi <=do { if (!(le32_to_cpu(control->hfio) + sizeof(struct nbft_hfi
) * control->num_hfi <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid hfi descriptor list offset" "\n", nbft->filename
); return -22; } } while (0)
653 le32_to_cpu(header->length),do { if (!(le32_to_cpu(control->hfio) + sizeof(struct nbft_hfi
) * control->num_hfi <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid hfi descriptor list offset" "\n", nbft->filename
); return -22; } } while (0)
654 "invalid hfi descriptor list offset")do { if (!(le32_to_cpu(control->hfio) + sizeof(struct nbft_hfi
) * control->num_hfi <= le32_to_cpu(header->length))
) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "file %s: "
"invalid hfi descriptor list offset" "\n", nbft->filename
); return -22; } } while (0)
;
655 raw_hfi_array = (struct nbft_hfi *)(raw_nbft +
656 le32_to_cpu(control->hfio));
657 read_hfi_descriptors(ctx, nbft, control->num_hfi, raw_hfi_array,
658 le16_to_cpu(control->hfil));
659 }
660
661 /*
662 * security
663 */
664 if (control->num_sec > 0) {
665 struct nbft_security *raw_security_array;
666
667 verify(ctx, le32_to_cpu(control->seco) +do { if (!(le32_to_cpu(control->seco) + le16_to_cpu(control
->secl) * control->num_sec <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid security profile desciptor list offset"
"\n", nbft->filename); return -22; } } while (0)
668 le16_to_cpu(control->secl) * control->num_sec <=do { if (!(le32_to_cpu(control->seco) + le16_to_cpu(control
->secl) * control->num_sec <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid security profile desciptor list offset"
"\n", nbft->filename); return -22; } } while (0)
669 le32_to_cpu(header->length),do { if (!(le32_to_cpu(control->seco) + le16_to_cpu(control
->secl) * control->num_sec <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid security profile desciptor list offset"
"\n", nbft->filename); return -22; } } while (0)
670 "invalid security profile desciptor list offset")do { if (!(le32_to_cpu(control->seco) + le16_to_cpu(control
->secl) * control->num_sec <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid security profile desciptor list offset"
"\n", nbft->filename); return -22; } } while (0)
;
671 raw_security_array = (struct nbft_security *)(raw_nbft +
672 le32_to_cpu(control->seco));
673 read_security_descriptors(ctx, nbft, control->num_sec,
674 raw_security_array,
675 le16_to_cpu(control->secl));
676 }
677
678 /*
679 * discovery
680 */
681 if (control->num_disc > 0) {
682 struct nbft_discovery *raw_discovery_array;
683
684 verify(ctx, le32_to_cpu(control->disco) +do { if (!(le32_to_cpu(control->disco) + le16_to_cpu(control
->discl) * control->num_disc <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid discovery profile descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
685 le16_to_cpu(control->discl) * control->num_disc <=do { if (!(le32_to_cpu(control->disco) + le16_to_cpu(control
->discl) * control->num_disc <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid discovery profile descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
686 le32_to_cpu(header->length),do { if (!(le32_to_cpu(control->disco) + le16_to_cpu(control
->discl) * control->num_disc <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid discovery profile descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
687 "invalid discovery profile descriptor list offset")do { if (!(le32_to_cpu(control->disco) + le16_to_cpu(control
->discl) * control->num_disc <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid discovery profile descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
;
688 raw_discovery_array = (struct nbft_discovery *)(raw_nbft +
689 le32_to_cpu(control->disco));
690 read_discovery_descriptors(ctx, nbft, control->num_disc,
691 raw_discovery_array, le16_to_cpu(control->discl));
692 }
693
694 /*
695 * subsystem namespace
696 */
697 if (control->num_ssns > 0) {
698 struct nbft_ssns *raw_ssns_array;
699
700 verify(ctx, le32_to_cpu(control->ssnso) +do { if (!(le32_to_cpu(control->ssnso) + le16_to_cpu(control
->ssnsl) * control->num_ssns <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid subsystem namespace descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
701 le16_to_cpu(control->ssnsl) * control->num_ssns <=do { if (!(le32_to_cpu(control->ssnso) + le16_to_cpu(control
->ssnsl) * control->num_ssns <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid subsystem namespace descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
702 le32_to_cpu(header->length),do { if (!(le32_to_cpu(control->ssnso) + le16_to_cpu(control
->ssnsl) * control->num_ssns <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid subsystem namespace descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
703 "invalid subsystem namespace descriptor list offset")do { if (!(le32_to_cpu(control->ssnso) + le16_to_cpu(control
->ssnsl) * control->num_ssns <= le32_to_cpu(header->
length))) { __libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0),
"file %s: " "invalid subsystem namespace descriptor list offset"
"\n", nbft->filename); return -22; } } while (0)
;
704 raw_ssns_array = (struct nbft_ssns *)(raw_nbft +
705 le32_to_cpu(control->ssnso));
706 read_ssns_descriptors(ctx, nbft, control->num_ssns,
707 raw_ssns_array, le16_to_cpu(control->ssnsl));
708 }
709
710 return 0;
711}
712
713__libnvme_public__attribute__((visibility("default"))) void libnvmf_free_nbft(
714 struct libnvme_global_ctx *ctx, struct libnbft_info *nbft)
715{
716 struct libnbft_hfi **hfi;
717 struct libnbft_security **sec;
718 struct libnbft_discovery **disc;
719 struct libnbft_subsystem_ns **ns;
720
721 for (hfi = nbft->hfi_list; hfi && *hfi; hfi++)
722 free(*hfi);
723 free(nbft->hfi_list);
724 for (disc = nbft->discovery_list; disc && *disc; disc++)
725 free(*disc);
726 free(nbft->discovery_list);
727 for (sec = nbft->security_list; sec && *sec; sec++)
728 free(*sec);
729 free(nbft->security_list);
730 for (ns = nbft->subsystem_ns_list; ns && *ns; ns++) {
731 free((*ns)->hfis);
732 free(*ns);
733 }
734 free(nbft->subsystem_ns_list);
735 free(nbft->raw_nbft);
736 free(nbft->filename);
737 free(nbft);
738}
739
740__libnvme_public__attribute__((visibility("default"))) int libnvmf_read_nbft(
741 struct libnvme_global_ctx *ctx, struct libnbft_info **nbft,
742 const char *filename)
743{
744 __u8 *raw_nbft = NULL((void*)0);
745 size_t raw_nbft_size;
746 FILE *raw_nbft_fp = NULL((void*)0);
747 int i;
748
749 /*
750 * read in raw nbft file
751 */
752 raw_nbft_fp = fopen(filename, "rb");
753 if (raw_nbft_fp
0.1
'raw_nbft_fp' is not equal to NULL
== NULL((void*)0)) {
1
Taking false branch
754 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Failed to open %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open %s: %s\n"
, filename, libnvme_strerror((*__errno_location ())))
755 filename, libnvme_strerror(errno))__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open %s: %s\n"
, filename, libnvme_strerror((*__errno_location ())))
;
756 return -EINVAL22;
757 }
758
759 i = fseek(raw_nbft_fp, 0L, SEEK_END2);
760 if (i
1.1
'i' is 0
) {
2
Taking false branch
761 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Failed to read from %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to read from %s: %s\n"
, filename, libnvme_strerror((*__errno_location ())))
762 filename, libnvme_strerror(errno))__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to read from %s: %s\n"
, filename, libnvme_strerror((*__errno_location ())))
;
763 fclose(raw_nbft_fp);
764 return -EINVAL22;
765 }
766
767 raw_nbft_size = ftell(raw_nbft_fp);
768 rewind(raw_nbft_fp);
3
After calling 'rewind' reading 'errno' is required to find out if the call has failed
769
770 raw_nbft = malloc(raw_nbft_size);
4
Value of 'errno' was not checked and may be overwritten by function 'malloc'
771 if (!raw_nbft) {
772 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to allocate memory for NBFT table"
)
773 "Failed to allocate memory for NBFT table")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to allocate memory for NBFT table"
)
;
774 fclose(raw_nbft_fp);
775 return -ENOMEM12;
776 }
777
778 i = fread(raw_nbft, sizeof(*raw_nbft), raw_nbft_size, raw_nbft_fp);
779 if (i != raw_nbft_size) {
780 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Failed to read from %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to read from %s: %s\n"
, filename, libnvme_strerror((*__errno_location ())))
781 filename, libnvme_strerror(errno))__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to read from %s: %s\n"
, filename, libnvme_strerror((*__errno_location ())))
;
782 fclose(raw_nbft_fp);
783 free(raw_nbft);
784 return -EINVAL22;
785 }
786 fclose(raw_nbft_fp);
787
788 /*
789 * alloc new struct libnbft_info, add raw nbft & filename to it,
790 * and add it to the list
791 */
792 *nbft = calloc(1, sizeof(struct libnbft_info));
793 if (!*nbft) {
794 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Could not allocate memory for NBFT\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Could not allocate memory for NBFT\n"
)
;
795 free(raw_nbft);
796 return -ENOMEM12;
797 }
798
799 (*nbft)->filename = strdup(filename);
800 (*nbft)->raw_nbft = raw_nbft;
801 (*nbft)->raw_nbft_size = raw_nbft_size;
802
803 if (parse_raw_nbft(ctx, *nbft)) {
804 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Failed to parse %s\n", filename)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to parse %s\n"
, filename)
;
805 libnvmf_free_nbft(ctx, *nbft);
806 return -EINVAL22;
807 }
808 return 0;
809}