1 /*****************************************************************************\
2 * $Id: ipmi-sdr-cache-read.c,v 1.33 2010-02-08 22:09:40 chu11 Exp $
3 *****************************************************************************
4 * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
5 * Copyright (C) 2006-2007 The Regents of the University of California.
6 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7 * Written by Albert Chu <chu11@llnl.gov>
8 * UCRL-CODE-222073
9 *
10 * This file is part of Ipmimonitoring, an IPMI sensor monitoring
11 * library. For details, see http://www.llnl.gov/linux/.
12 *
13 * Ipmimonitoring is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 3 of the License, or (at your
16 * option) any later version.
17 *
18 * Ipmimonitoring is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with Ipmimonitoring. If not, see <http://www.gnu.org/licenses/>.
25 \*****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif /* HAVE_CONFIG_H */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #if STDC_HEADERS
34 #include <string.h>
35 #endif /* STDC_HEADERS */
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #if HAVE_FCNTL_H
39 #include <fcntl.h>
40 #endif /* HAVE_FCNTL_H */
41 #if HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44 #include <sys/param.h>
45 #include <sys/mman.h>
46 #include <assert.h>
47 #include <errno.h>
48
49 #include "freeipmi/sdr/ipmi-sdr.h"
50 #include "freeipmi/record-format/ipmi-sdr-record-format.h"
51 #include "freeipmi/util/ipmi-util.h"
52
53 #include "ipmi-sdr-common.h"
54 #include "ipmi-sdr-defs.h"
55 #include "ipmi-sdr-trace.h"
56 #include "ipmi-sdr-util.h"
57
58 #include "freeipmi-portability.h"
59
60 static void
_sdr_set_current_offset(ipmi_sdr_ctx_t ctx,off_t new_offset)61 _sdr_set_current_offset (ipmi_sdr_ctx_t ctx, off_t new_offset)
62 {
63 assert (ctx);
64 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
65
66 ctx->current_offset.offset = new_offset;
67 ctx->current_offset.offset_dumped = 0;
68 }
69
70 int
ipmi_sdr_cache_open(ipmi_sdr_ctx_t ctx,ipmi_ctx_t ipmi_ctx,const char * filename)71 ipmi_sdr_cache_open (ipmi_sdr_ctx_t ctx,
72 ipmi_ctx_t ipmi_ctx,
73 const char *filename)
74 {
75 uint8_t sdr_version;
76 uint16_t record_count;
77 uint32_t most_recent_addition_timestamp, most_recent_erase_timestamp;
78 char sdr_version_buf;
79 char sdr_cache_magic_buf[4];
80 char sdr_cache_version_buf[4];
81 char record_count_buf[2];
82 char most_recent_addition_timestamp_buf[4];
83 char most_recent_erase_timestamp_buf[4];
84 struct stat stat_buf;
85
86 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
87 {
88 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
89 return (-1);
90 }
91
92 if (!filename)
93 {
94 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
95 return (-1);
96 }
97
98 if (ctx->operation != IPMI_SDR_OPERATION_UNINITIALIZED)
99 {
100 if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE)
101 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_ALREADY_INITIALIZED);
102 else
103 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
104 return (-1);
105 }
106
107 if (stat (filename, &stat_buf) < 0)
108 {
109 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
110 goto cleanup;
111 }
112
113 /* File Size must be atleast magic_buf + file_version_buf +
114 * sdr_version_buf + record_count_buf +
115 * most_recent_addition_timestamp_buf +
116 * most_recent_erase_timestamp-buf in size.
117 */
118
119 ctx->file_size = stat_buf.st_size;
120 if (ctx->file_size < (4 + 4 + 1 + 2 + 4 + 4))
121 {
122 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
123 goto cleanup;
124 }
125
126 if ((ctx->fd = open (filename, O_RDONLY)) < 0)
127 {
128 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
129 goto cleanup;
130 }
131
132 ctx->sdr_cache = (uint8_t *)mmap (NULL,
133 ctx->file_size,
134 PROT_READ,
135 MAP_PRIVATE,
136 ctx->fd,
137 0);
138 if (!ctx->sdr_cache || ctx->sdr_cache == ((void *) -1))
139 {
140 ERRNO_TRACE (errno);
141 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
142 goto cleanup;
143 }
144
145 memcpy (sdr_cache_magic_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
146 ctx->records_start_offset += 4;
147 memcpy (sdr_cache_version_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
148 ctx->records_start_offset += 4;
149 memcpy (&sdr_version_buf, ctx->sdr_cache + ctx->records_start_offset, 1);
150 ctx->records_start_offset += 1;
151 memcpy (record_count_buf, ctx->sdr_cache + ctx->records_start_offset, 2);
152 ctx->records_start_offset += 2;
153 memcpy (most_recent_addition_timestamp_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
154 ctx->records_start_offset += 4;
155 memcpy (most_recent_erase_timestamp_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
156 ctx->records_start_offset += 4;
157
158 if ((uint8_t)sdr_cache_magic_buf[0] != IPMI_SDR_CACHE_FILE_MAGIC_0
159 || (uint8_t)sdr_cache_magic_buf[1] != IPMI_SDR_CACHE_FILE_MAGIC_1
160 || (uint8_t)sdr_cache_magic_buf[2] != IPMI_SDR_CACHE_FILE_MAGIC_2
161 || (uint8_t)sdr_cache_magic_buf[3] != IPMI_SDR_CACHE_FILE_MAGIC_3)
162 {
163 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
164 goto cleanup;
165 }
166
167 if (((uint8_t)sdr_cache_version_buf[0] != IPMI_SDR_CACHE_FILE_VERSION_1_0
168 || (uint8_t)sdr_cache_version_buf[1] != IPMI_SDR_CACHE_FILE_VERSION_1_1
169 || (uint8_t)sdr_cache_version_buf[2] != IPMI_SDR_CACHE_FILE_VERSION_1_2
170 || (uint8_t)sdr_cache_version_buf[3] != IPMI_SDR_CACHE_FILE_VERSION_1_3)
171 && ((uint8_t)sdr_cache_version_buf[0] != IPMI_SDR_CACHE_FILE_VERSION_1_2_0
172 || (uint8_t)sdr_cache_version_buf[1] != IPMI_SDR_CACHE_FILE_VERSION_1_2_1
173 || (uint8_t)sdr_cache_version_buf[2] != IPMI_SDR_CACHE_FILE_VERSION_1_2_2
174 || (uint8_t)sdr_cache_version_buf[3] != IPMI_SDR_CACHE_FILE_VERSION_1_2_3))
175 {
176 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
177 goto cleanup;
178 }
179
180 ctx->sdr_version = (uint8_t)sdr_version_buf;
181 ctx->record_count = ((uint16_t)record_count_buf[0] & 0xFF);
182 ctx->record_count |= ((uint16_t)record_count_buf[1] & 0xFF) << 8;
183 ctx->most_recent_addition_timestamp = ((uint32_t)most_recent_addition_timestamp_buf[0] & 0xFF);
184 ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[1] & 0xFF) << 8;
185 ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[2] & 0xFF) << 16;
186 ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[3] & 0xFF) << 24;
187 ctx->most_recent_erase_timestamp = ((uint32_t)most_recent_erase_timestamp_buf[0] & 0xFF);
188 ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[1] & 0xFF) << 8;
189 ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[2] & 0xFF) << 16;
190 ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[3] & 0xFF) << 24;
191
192 if (ipmi_ctx)
193 {
194 if (sdr_info (ctx,
195 ipmi_ctx,
196 &sdr_version,
197 &record_count,
198 &most_recent_addition_timestamp,
199 &most_recent_erase_timestamp) < 0)
200 goto cleanup;
201
202 if (ctx->sdr_version != sdr_version
203 || ctx->most_recent_addition_timestamp != most_recent_addition_timestamp
204 || ctx->most_recent_erase_timestamp != most_recent_erase_timestamp)
205 {
206 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_OUT_OF_DATE);
207 goto cleanup;
208 }
209 }
210
211 if ((uint8_t)sdr_cache_version_buf[0] == IPMI_SDR_CACHE_FILE_VERSION_1_2_0
212 && (uint8_t)sdr_cache_version_buf[1] == IPMI_SDR_CACHE_FILE_VERSION_1_2_1
213 && (uint8_t)sdr_cache_version_buf[2] == IPMI_SDR_CACHE_FILE_VERSION_1_2_2
214 && (uint8_t)sdr_cache_version_buf[3] == IPMI_SDR_CACHE_FILE_VERSION_1_2_3)
215 {
216 uint8_t header_checksum_buf[512];
217 unsigned int header_checksum_buf_len = 0;
218 uint8_t header_checksum, header_checksum_cache;
219 uint8_t trailer_checksum, trailer_checksum_cache;
220 char total_bytes_written_buf[4];
221 unsigned int total_bytes_written;
222 unsigned int header_bytes_len;
223 unsigned int trailer_bytes_len;
224
225 /* File Size must be atleast magic_buf + file_version_buf +
226 * sdr_version_buf + record_count_buf +
227 * most_recent_addition_timestamp_buf +
228 * most_recent_erase_timestamp-buf + header_checksum + trailer
229 * bytes written + trailer records checksum.
230 */
231
232 header_bytes_len = 4 + 4 + 1 + 2 + 4 + 4 + 1;
233 trailer_bytes_len = 4 + 1;
234
235 if (ctx->file_size < (header_bytes_len + trailer_bytes_len))
236 {
237 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
238 goto cleanup;
239 }
240
241 memcpy (&header_checksum_cache, ctx->sdr_cache + ctx->records_start_offset, 1);
242 ctx->records_start_offset += 1;
243
244 memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_magic_buf, 4);
245 header_checksum_buf_len += 4;
246 memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_version_buf, 4);
247 header_checksum_buf_len += 4;
248 memcpy(&header_checksum_buf[header_checksum_buf_len], &sdr_version_buf, 1);
249 header_checksum_buf_len += 1;
250 memcpy(&header_checksum_buf[header_checksum_buf_len], record_count_buf, 2);
251 header_checksum_buf_len += 2;
252 memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_addition_timestamp_buf, 4);
253 header_checksum_buf_len += 4;
254 memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_erase_timestamp_buf, 4);
255 header_checksum_buf_len += 4;
256
257 header_checksum = ipmi_checksum (header_checksum_buf, header_checksum_buf_len);
258 if (header_checksum != header_checksum_cache)
259 {
260 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
261 goto cleanup;
262 }
263
264 /* total_bytes_written is written before checksum */
265 /* checksum of records is last byte written */
266 memcpy (total_bytes_written_buf, ctx->sdr_cache + ctx->file_size - 5, 4);
267 memcpy (&trailer_checksum_cache, ctx->sdr_cache + ctx->file_size - 1, 1);
268
269 total_bytes_written = ((uint32_t)total_bytes_written_buf[0] & 0xFF);
270 total_bytes_written |= ((uint32_t)total_bytes_written_buf[1] & 0xFF) << 8;
271 total_bytes_written |= ((uint32_t)total_bytes_written_buf[2] & 0xFF) << 16;
272 total_bytes_written |= ((uint32_t)total_bytes_written_buf[3] & 0xFF) << 24;
273
274 if (total_bytes_written != ctx->file_size)
275 {
276 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
277 goto cleanup;
278 }
279
280 /* -1 for checksum */
281 trailer_checksum = ipmi_checksum (ctx->sdr_cache + ctx->records_start_offset,
282 total_bytes_written - ctx->records_start_offset - 1);
283
284 if (trailer_checksum != trailer_checksum_cache)
285 {
286 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
287 goto cleanup;
288 }
289
290 ctx->records_end_offset = ctx->file_size - trailer_bytes_len;
291 }
292 else /* (uint8_t)sdr_cache_version_buf[0] == IPMI_SDR_CACHE_FILE_VERSION_1_0
293 && (uint8_t)sdr_cache_version_buf[1] == IPMI_SDR_CACHE_FILE_VERSION_1_1
294 && (uint8_t)sdr_cache_version_buf[2] == IPMI_SDR_CACHE_FILE_VERSION_1_2
295 && (uint8_t)sdr_cache_version_buf[3] == IPMI_SDR_CACHE_FILE_VERSION_1_3 */
296 ctx->records_end_offset = ctx->file_size;
297
298 _sdr_set_current_offset (ctx, ctx->records_start_offset);
299 ctx->operation = IPMI_SDR_OPERATION_READ_CACHE;
300 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
301 return (0);
302
303 cleanup:
304 /* ignore potential error, cleanup path */
305 if (ctx->fd >= 0)
306 close (ctx->fd);
307 /* ignore potential error, cleanup path */
308 if (ctx->sdr_cache)
309 munmap ((void *)ctx->sdr_cache, ctx->file_size);
310 sdr_init_ctx (ctx);
311 return (-1);
312 }
313
314 int
ipmi_sdr_cache_sdr_version(ipmi_sdr_ctx_t ctx,uint8_t * sdr_version)315 ipmi_sdr_cache_sdr_version (ipmi_sdr_ctx_t ctx, uint8_t *sdr_version)
316 {
317 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
318 {
319 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
320 return (-1);
321 }
322
323 if (!sdr_version)
324 {
325 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
326 return (-1);
327 }
328
329 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
330 {
331 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
332 return (-1);
333 }
334
335 *sdr_version = ctx->sdr_version;
336 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
337 return (0);
338 }
339
340 int
ipmi_sdr_cache_record_count(ipmi_sdr_ctx_t ctx,uint16_t * record_count)341 ipmi_sdr_cache_record_count (ipmi_sdr_ctx_t ctx, uint16_t *record_count)
342 {
343 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
344 {
345 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
346 return (-1);
347 }
348
349 if (!record_count)
350 {
351 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
352 return (-1);
353 }
354
355 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
356 {
357 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
358 return (-1);
359 }
360
361 *record_count = ctx->record_count;
362 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
363 return (0);
364 }
365
366 int
ipmi_sdr_cache_most_recent_addition_timestamp(ipmi_sdr_ctx_t ctx,uint32_t * most_recent_addition_timestamp)367 ipmi_sdr_cache_most_recent_addition_timestamp (ipmi_sdr_ctx_t ctx, uint32_t *most_recent_addition_timestamp)
368 {
369 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
370 {
371 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
372 return (-1);
373 }
374
375 if (!most_recent_addition_timestamp)
376 {
377 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
378 return (-1);
379 }
380
381 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
382 {
383 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
384 return (-1);
385 }
386
387 *most_recent_addition_timestamp = ctx->most_recent_addition_timestamp;
388 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
389 return (0);
390 }
391
392 int
ipmi_sdr_cache_most_recent_erase_timestamp(ipmi_sdr_ctx_t ctx,uint32_t * most_recent_erase_timestamp)393 ipmi_sdr_cache_most_recent_erase_timestamp (ipmi_sdr_ctx_t ctx, uint32_t *most_recent_erase_timestamp)
394 {
395 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
396 {
397 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
398 return (-1);
399 }
400
401 if (!most_recent_erase_timestamp)
402 {
403 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
404 return (-1);
405 }
406
407 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
408 {
409 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
410 return (-1);
411 }
412
413 *most_recent_erase_timestamp = ctx->most_recent_erase_timestamp;
414 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
415 return (0);
416 }
417
418 int
ipmi_sdr_cache_first(ipmi_sdr_ctx_t ctx)419 ipmi_sdr_cache_first (ipmi_sdr_ctx_t ctx)
420 {
421 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
422 {
423 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
424 return (-1);
425 }
426
427 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
428 {
429 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
430 return (-1);
431 }
432
433 _sdr_set_current_offset (ctx, ctx->records_start_offset);
434
435 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
436 return (0);
437 }
438
439 int
ipmi_sdr_cache_next(ipmi_sdr_ctx_t ctx)440 ipmi_sdr_cache_next (ipmi_sdr_ctx_t ctx)
441 {
442 unsigned int record_length;
443
444 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
445 {
446 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
447 return (-1);
448 }
449
450 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
451 {
452 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
453 return (-1);
454 }
455
456 record_length = (uint8_t)((ctx->sdr_cache + ctx->current_offset.offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);
457
458 if ((ctx->current_offset.offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
459 return (0);
460
461 _sdr_set_current_offset (ctx, ctx->current_offset.offset + IPMI_SDR_RECORD_HEADER_LENGTH + record_length);
462
463 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
464 return (1);
465 }
466
467 int
ipmi_sdr_cache_seek(ipmi_sdr_ctx_t ctx,unsigned int index)468 ipmi_sdr_cache_seek (ipmi_sdr_ctx_t ctx, unsigned int index)
469 {
470 off_t offset;
471 unsigned int i;
472
473 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
474 {
475 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
476 return (-1);
477 }
478
479 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
480 {
481 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
482 return (-1);
483 }
484
485 if (index >= ctx->record_count)
486 {
487 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
488 return (-1);
489 }
490
491 offset = ctx->records_start_offset;
492 for (i = 0; i < index; i++)
493 {
494 unsigned int record_length;
495
496 record_length = (uint8_t)((ctx->sdr_cache + offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);
497
498 if ((offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
499 break;
500
501 offset += IPMI_SDR_RECORD_HEADER_LENGTH;
502 offset += record_length;
503 }
504
505 _sdr_set_current_offset (ctx, offset);
506
507 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
508 return (0);
509 }
510
511 int
ipmi_sdr_cache_search_record_id(ipmi_sdr_ctx_t ctx,uint16_t record_id)512 ipmi_sdr_cache_search_record_id (ipmi_sdr_ctx_t ctx, uint16_t record_id)
513 {
514 off_t offset;
515 int found = 0;
516
517 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
518 {
519 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
520 return (-1);
521 }
522
523 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
524 {
525 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
526 return (-1);
527 }
528
529 offset = ctx->records_start_offset;
530 while (offset < ctx->records_end_offset)
531 {
532 uint8_t *ptr = ctx->sdr_cache + offset;
533 uint16_t record_id_current;
534 unsigned int record_length;
535
536 /* Record ID stored little-endian */
537 record_id_current = (uint16_t)ptr[IPMI_SDR_RECORD_ID_INDEX_LS] & 0xFF;
538 record_id_current |= ((uint16_t)ptr[IPMI_SDR_RECORD_ID_INDEX_MS] & 0xFF) << 8;
539
540 if (record_id == record_id_current)
541 {
542 found++;
543 _sdr_set_current_offset (ctx, offset);
544 break;
545 }
546
547 record_length = (uint8_t)((ctx->sdr_cache + offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);
548
549 if ((offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
550 break;
551
552 offset += IPMI_SDR_RECORD_HEADER_LENGTH;
553 offset += record_length;
554 }
555
556 if (!found)
557 {
558 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_NOT_FOUND);
559 return (-1);
560 }
561
562 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
563 return (0);
564 }
565
566 int
ipmi_sdr_cache_search_sensor(ipmi_sdr_ctx_t ctx,uint8_t sensor_number,uint8_t sensor_owner_id)567 ipmi_sdr_cache_search_sensor (ipmi_sdr_ctx_t ctx, uint8_t sensor_number, uint8_t sensor_owner_id)
568 {
569 off_t offset;
570 int found = 0;
571
572 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
573 {
574 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
575 return (-1);
576 }
577
578 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
579 {
580 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
581 return (-1);
582 }
583
584 offset = ctx->records_start_offset;
585 while (offset < ctx->records_end_offset)
586 {
587 uint8_t *ptr = ctx->sdr_cache + offset;
588 uint8_t record_type_current;
589 unsigned int record_length;
590
591 record_type_current = ptr[IPMI_SDR_RECORD_TYPE_INDEX];
592
593 if (record_type_current == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
594 || record_type_current == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
595 || record_type_current == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
596 {
597 uint8_t sensor_number_current;
598 uint8_t sensor_owner_id_current;
599
600 sensor_owner_id_current = ptr[IPMI_SDR_RECORD_SENSOR_OWNER_ID_INDEX];
601 sensor_number_current = ptr[IPMI_SDR_RECORD_SENSOR_NUMBER_INDEX];
602
603 if (sensor_owner_id_current == sensor_owner_id
604 && sensor_number_current == sensor_number)
605 {
606 found++;
607 _sdr_set_current_offset (ctx, offset);
608 break;
609 }
610
611 /* Compact sensor records can do record sharing, so check
612 * for this case if the sensor_owner_id matches up.
613 */
614 if (sensor_owner_id_current == sensor_owner_id
615 && (record_type_current == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
616 || record_type_current == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD))
617 {
618 uint8_t share_count;
619
620 if (record_type_current == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD)
621 {
622 share_count = ptr[IPMI_SDR_RECORD_COMPACT_SHARE_COUNT];
623 share_count &= IPMI_SDR_RECORD_COMPACT_SHARE_COUNT_BITMASK;
624 share_count >>= IPMI_SDR_RECORD_COMPACT_SHARE_COUNT_SHIFT;
625 }
626 else
627 {
628 share_count = ptr[IPMI_SDR_RECORD_EVENT_SHARE_COUNT];
629 share_count &= IPMI_SDR_RECORD_EVENT_SHARE_COUNT_BITMASK;
630 share_count >>= IPMI_SDR_RECORD_EVENT_SHARE_COUNT_SHIFT;
631 }
632
633 /* IPMI spec gives the following example:
634 *
635 * "If the starting sensor number was 10, and the share
636 * count was 3, then sensors 10, 11, and 12 would share
637 * the record"
638 */
639 if (share_count > 1
640 && (sensor_number > sensor_number_current
641 && sensor_number <= (sensor_number_current + (share_count - 1))))
642 {
643 found++;
644 _sdr_set_current_offset (ctx, offset);
645 break;
646 }
647 }
648 }
649
650 record_length = (uint8_t)((ctx->sdr_cache + offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);
651
652 if ((offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
653 break;
654
655 offset += IPMI_SDR_RECORD_HEADER_LENGTH;
656 offset += record_length;
657 }
658
659 if (!found)
660 {
661 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_NOT_FOUND);
662 return (-1);
663 }
664
665 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
666 return (0);
667 }
668
669 int
ipmi_sdr_cache_record_read(ipmi_sdr_ctx_t ctx,void * buf,unsigned int buflen)670 ipmi_sdr_cache_record_read (ipmi_sdr_ctx_t ctx,
671 void *buf,
672 unsigned int buflen)
673 {
674 unsigned int record_length;
675
676 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
677 {
678 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
679 return (-1);
680 }
681
682 if (!buf || !buflen)
683 {
684 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
685 return (-1);
686 }
687
688 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
689 {
690 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
691 return (-1);
692 }
693
694 record_length = (uint8_t)((ctx->sdr_cache + ctx->current_offset.offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);
695
696 if (buflen < (record_length + IPMI_SDR_RECORD_HEADER_LENGTH))
697 {
698 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_OVERFLOW);
699 return (-1);
700 }
701
702 sdr_check_read_status (ctx);
703
704 memcpy (buf, ctx->sdr_cache + ctx->current_offset.offset, record_length + IPMI_SDR_RECORD_HEADER_LENGTH);
705 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
706 return (record_length + IPMI_SDR_RECORD_HEADER_LENGTH);
707 }
708
709 static int
_sdr_save_current_offset(ipmi_sdr_ctx_t ctx)710 _sdr_save_current_offset (ipmi_sdr_ctx_t ctx)
711 {
712 struct ipmi_sdr_offset *saved_offset = NULL;
713
714 assert (ctx);
715 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
716
717 if (!(saved_offset = (struct ipmi_sdr_offset *)malloc (sizeof (struct ipmi_sdr_offset))))
718 {
719 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_OUT_OF_MEMORY);
720 return (-1);
721 }
722
723 memcpy (saved_offset, &ctx->current_offset, sizeof (struct ipmi_sdr_offset));
724
725 if (!list_push (ctx->saved_offsets, saved_offset))
726 {
727 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
728 goto cleanup;
729 }
730
731 return (0);
732
733 cleanup:
734 free (saved_offset);
735 return (-1);
736 }
737
738 static int
_sdr_reset_current_offset(ipmi_sdr_ctx_t ctx)739 _sdr_reset_current_offset (ipmi_sdr_ctx_t ctx)
740 {
741 struct ipmi_sdr_offset *saved_offset = NULL;
742
743 assert (ctx);
744 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
745 assert (list_count (ctx->saved_offsets) > 0);
746
747 if (!(saved_offset = list_pop (ctx->saved_offsets)))
748 {
749 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
750 return (-1);
751 }
752
753 memcpy (&ctx->current_offset, saved_offset, sizeof (struct ipmi_sdr_offset));
754 free (saved_offset);
755 return (0);
756 }
757
758 int
ipmi_sdr_cache_iterate(ipmi_sdr_ctx_t ctx,Ipmi_Sdr_Cache_Iterate_Callback iterate_callback,void * iterate_callback_data)759 ipmi_sdr_cache_iterate (ipmi_sdr_ctx_t ctx,
760 Ipmi_Sdr_Cache_Iterate_Callback iterate_callback,
761 void *iterate_callback_data)
762 {
763 uint16_t record_count;
764 unsigned int i;
765 int tmpret;
766 int rv = -1;
767
768 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
769 {
770 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
771 return (-1);
772 }
773
774 if (!iterate_callback)
775 {
776 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
777 return (-1);
778 }
779
780 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
781 {
782 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
783 return (-1);
784 }
785
786 if (_sdr_save_current_offset (ctx) < 0)
787 return (-1);
788
789 if (ipmi_sdr_cache_record_count (ctx, &record_count) < 0)
790 {
791 SDR_SET_INTERNAL_ERRNUM (ctx);
792 goto cleanup;
793 }
794
795 if (ipmi_sdr_cache_first (ctx) < 0)
796 {
797 SDR_SET_INTERNAL_ERRNUM (ctx);
798 goto cleanup;
799 }
800
801 for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (ctx))
802 {
803 uint8_t sdr_record[IPMI_SDR_MAX_RECORD_LENGTH];
804 int sdr_record_len;
805 uint8_t record_type;
806 int ret;
807
808 memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH);
809
810 if ((sdr_record_len = ipmi_sdr_cache_record_read (ctx,
811 sdr_record,
812 IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
813 {
814 SDR_SET_INTERNAL_ERRNUM (ctx);
815 goto cleanup;
816 }
817
818 record_type = sdr_record[IPMI_SDR_RECORD_TYPE_INDEX];
819
820 ctx->callback_lock = 1;
821 ret = iterate_callback (ctx,
822 record_type,
823 sdr_record,
824 (unsigned int)sdr_record_len,
825 iterate_callback_data);
826 ctx->callback_lock = 0;
827
828 if (ret < 0)
829 {
830 rv = ret;
831 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_ERROR_RETURNED_IN_CALLBACK);
832 goto cleanup;
833 }
834
835 if (ret > 0)
836 {
837 rv = ret;
838 goto out;
839 }
840 }
841
842 rv = 0;
843 out:
844 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
845 cleanup:
846 tmpret = _sdr_reset_current_offset (ctx);
847 if (rv)
848 return (rv);
849 return (tmpret);
850 }
851
852 int
ipmi_sdr_cache_close(ipmi_sdr_ctx_t ctx)853 ipmi_sdr_cache_close (ipmi_sdr_ctx_t ctx)
854 {
855 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
856 {
857 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
858 return (-1);
859 }
860
861 if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
862 {
863 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
864 return (-1);
865 }
866
867 if (ctx->callback_lock)
868 {
869 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CONTEXT_PERFORMING_OTHER_OPERATION);
870 return (-1);
871 }
872
873 /* ignore potential error, cleanup path */
874 if (ctx->fd >= 0)
875 close (ctx->fd);
876 /* ignore potential error, cleanup path */
877 if (ctx->sdr_cache)
878 munmap ((void *)ctx->sdr_cache, ctx->file_size);
879 sdr_init_ctx (ctx);
880
881 ctx->operation = IPMI_SDR_OPERATION_UNINITIALIZED;
882 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
883 return (0);
884 }
885