blob: 8771a9294aa2ba7dc162a0a377d1385b9522e61e [file] [log] [blame]
Vishwa4be4b7a2015-10-31 22:55:50 -05001#include <vector>
2#include <stdlib.h>
3#include <dlfcn.h>
4#include <errno.h>
5#include <stdio.h>
Vishwa4be4b7a2015-10-31 22:55:50 -05006#include <systemd/sd-bus.h>
Chris Austenb45c4cb2015-11-01 06:34:56 -06007#include <unistd.h>
vishwa13555bd2015-11-10 12:10:38 -06008#include <host-ipmid/ipmid-api.h>
vishwac93d6d42015-12-16 11:55:16 -06009#include <iostream>
10#include <memory>
11#include <algorithm>
12#include <fstream>
13#include "frup.h"
14#include "fru-area.H"
Vishwa4be4b7a2015-10-31 22:55:50 -050015
16// OpenBMC System Manager dbus framework
vishwa13555bd2015-11-10 12:10:38 -060017const char *sys_bus_name = "org.openbmc.managers.System";
18const char *sys_object_name = "/org/openbmc/managers/System";
19const char *sys_intf_name = "org.openbmc.managers.System";
Vishwa4be4b7a2015-10-31 22:55:50 -050020
vishwac93d6d42015-12-16 11:55:16 -060021//----------------------------------------------------------------
22// Constructor
23//----------------------------------------------------------------
24ipmi_fru::ipmi_fru(const uint8_t fruid, const ipmi_fru_area_type type,
25 sd_bus *bus_type, bool bmc_fru)
26{
27 iv_fruid = fruid;
28 iv_type = type;
29 iv_bmc_fru = bmc_fru;
30 iv_bus_type = bus_type;
31 iv_valid = false;
32 iv_data = NULL;
33 iv_present = false;
34
35 if(iv_type == IPMI_FRU_AREA_INTERNAL_USE)
36 {
37 iv_name = "INTERNAL_";
38 }
39 else if(iv_type == IPMI_FRU_AREA_CHASSIS_INFO)
40 {
41 iv_name = "CHASSIS_";
42 }
43 else if(iv_type == IPMI_FRU_AREA_BOARD_INFO)
44 {
45 iv_name = "BOARD_";
46 }
47 else if(iv_type == IPMI_FRU_AREA_PRODUCT_INFO)
48 {
49 iv_name = "PRODUCT_";
50 }
51 else if(iv_type == IPMI_FRU_AREA_MULTI_RECORD)
52 {
53 iv_name = "MULTI_";
54 }
55 else
56 {
57 iv_name = IPMI_FRU_AREA_TYPE_MAX;
58 fprintf(stderr, "ERROR: Invalid Area type :[%d]\n",iv_type);
59 }
60}
61
62//-----------------------------------------------------
63// For a FRU area type, accepts the data and updates
64// area specific data.
65//-----------------------------------------------------
66void ipmi_fru::set_data(const uint8_t *data, const size_t len)
67{
68 iv_len = len;
69 iv_data = new uint8_t[len];
70 memcpy(iv_data, data, len);
71}
72
73//-----------------------------------------------------
74// Sets the dbus parameters
75//-----------------------------------------------------
76void ipmi_fru::update_dbus_paths(const char *bus_name,
77 const char *obj_path, const char *intf_name)
78{
79 iv_bus_name = bus_name;
80 iv_obj_path = obj_path;
81 iv_intf_name = intf_name;
82}
83
84//-------------------
85// Destructor
86//-------------------
87ipmi_fru::~ipmi_fru()
88{
89 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
90 sd_bus_message *response = NULL;
91 int rc = 0;
92
93 if(iv_data != NULL)
94 {
95 delete [] iv_data;
96 iv_data = NULL;
97 }
98
99 // If we have not been successful in doing some updates and we are a BMC
100 // fru, then need to set the fault bits.
101 bool valid_dbus = !(iv_bus_name.empty()) &&
102 !(iv_obj_path.empty()) &&
103 !(iv_intf_name.empty());
104
105 // Based on bmc_fru, success in updating the FRU inventory we need to set
106 // some special bits.
107 if(iv_bmc_fru && valid_dbus)
108 {
109 // Set the Fault bit if we did not successfully process the fru
110 const char *fault_bit = iv_valid ? "False" : "True";
111
112 rc = sd_bus_call_method(iv_bus_type, // On the System Bus
113 iv_bus_name.c_str(), // Service to contact
114 iv_obj_path.c_str(), // Object path
115 iv_intf_name.c_str(), // Interface name
116 "setFault", // Method to be called
117 &bus_error, // object to return error
118 &response, // Response message on success
119 "s", // input message (string)
120 fault_bit); // First argument to setFault
121
122 if(rc <0)
123 {
124 fprintf(stderr,"Failed to set Fault bit, value:[%s] for fruid:[%d], path:[%s]\n",
125 fault_bit, iv_fruid, iv_obj_path.c_str());
126 }
127 else
128 {
129 printf("Fault bit set to :[%s] for fruid:[%d], Path:[%s]\n",
130 fault_bit, iv_fruid,iv_obj_path.c_str());
131 }
132
133 sd_bus_error_free(&bus_error);
134 sd_bus_message_unref(response);
135
136 // Set the Present bits
137 const char *present_bit = iv_present ? "True" : "False";
138
139 rc = sd_bus_call_method(iv_bus_type, // On the System Bus
140 iv_bus_name.c_str(), // Service to contact
141 iv_obj_path.c_str(), // Object path
142 iv_intf_name.c_str(), // Interface name
143 "setPresent", // Method to be called
144 &bus_error, // object to return error
145 &response, // Response message on success
146 "s", // input message (string)
147 present_bit); // First argument to setPresent
148 if(rc < 0)
149 {
150 fprintf(stderr,"Failed to set Present bit for fruid:[%d], path:[%s]\n",
151 iv_fruid, iv_obj_path.c_str());
152 }
153 else
154 {
155 printf("Present bit set to :[%s] for fruid:[%d]\n",
156 iv_obj_path.c_str(), iv_fruid);
157 }
158
159 sd_bus_error_free(&bus_error);
160 sd_bus_message_unref(response);
161 }
162}
163
164// Sets up the sd_bus structures for the given fru type
165int ipmi_fru::setup_sd_bus_paths(void)
166{
167 // Need this to get respective DBUS objects
168 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
169 sd_bus_message *response = NULL;
170 int rc = 0;
171
172 // What we need is BOARD_1, PRODUCT_1, CHASSIS_1 etc..
173 char *inv_bus_name, *inv_obj_path, *inv_intf_name;
174 char fru_area_name[16] = {0};
175 sprintf(fru_area_name,"%s%d",iv_name.c_str(), iv_fruid);
176
177#ifdef __IPMI_DEBUG__
178 printf("Getting sd_bus for :[%s]\n",fru_area_name);
179#endif
180
181 // We want to call a method "getObjectFromId" on System Bus that is
182 // made available over OpenBmc system services.
183 rc = sd_bus_call_method(iv_bus_type, // On the System Bus
184 sys_bus_name, // Service to contact
185 sys_object_name, // Object path
186 sys_intf_name, // Interface name
187 "getObjectFromId", // Method to be called
188 &bus_error, // object to return error
189 &response, // Response message on success
190 "ss", // input message (string,string)
191 "FRU_STR", // First argument to getObjectFromId
192 fru_area_name); // Second Argument
193
194 if(rc < 0)
195 {
196 fprintf(stderr, "Failed to resolve fruid:[%d] to dbus: [%s]\n", iv_fruid, bus_error.message);
197 }
198 else
199 {
200 // Method getObjectFromId returns 3 parameters and all are strings, namely
201 // bus_name , object_path and interface name for accessing that particular
202 // FRU over Inventory SDBUS manager. 'sss' here mentions that format.
203 rc = sd_bus_message_read(response, "(sss)", &inv_bus_name, &inv_obj_path, &inv_intf_name);
204 if(rc < 0)
205 {
206 fprintf(stderr, "Failed to parse response message:[%s]\n", strerror(-rc));
207 }
208 else
209 {
210 // Update the paths in the area object
211 update_dbus_paths(inv_bus_name, inv_obj_path, inv_intf_name);
212 }
213 }
214
215#ifdef __IPMI_DEBUG__
216 printf("fru_area=[%s], inv_bus_name=[%s], inv_obj_path=[%s], inv_intf_name=[%s]\n",
217 fru_area_name, inv_bus_name, inv_obj_path, inv_intf_name);
218#endif
219
220 sd_bus_error_free(&bus_error);
221 sd_bus_message_unref(response);
222
223 return rc;
224}
225
Vishwa4be4b7a2015-10-31 22:55:50 -0500226//------------------------------------------------
vishwaf3ca3522015-12-02 10:35:13 -0600227// Takes the pointer to stream of bytes and length
vishwac93d6d42015-12-16 11:55:16 -0600228// and returns the 8 bit checksum
229// This algo is per IPMI V2.0 spec
Vishwa4be4b7a2015-10-31 22:55:50 -0500230//-------------------------------------------------
vishwac93d6d42015-12-16 11:55:16 -0600231unsigned char calculate_crc(const unsigned char *data, size_t len)
Vishwa4be4b7a2015-10-31 22:55:50 -0500232{
233 char crc = 0;
vishwac93d6d42015-12-16 11:55:16 -0600234 size_t byte = 0;
Vishwa4be4b7a2015-10-31 22:55:50 -0500235
236 for(byte = 0; byte < len; byte++)
237 {
238 crc += *data++;
239 }
vishwaf3ca3522015-12-02 10:35:13 -0600240
Vishwa4be4b7a2015-10-31 22:55:50 -0500241 return(-crc);
242}
243
244//---------------------------------------------------------------------
245// Accepts a fru area offset in commom hdr and tells which area it is.
246//---------------------------------------------------------------------
vishwac93d6d42015-12-16 11:55:16 -0600247ipmi_fru_area_type get_fru_area_type(uint8_t area_offset)
Vishwa4be4b7a2015-10-31 22:55:50 -0500248{
249 ipmi_fru_area_type type = IPMI_FRU_AREA_TYPE_MAX;
250
251 switch(area_offset)
252 {
253 case IPMI_FRU_INTERNAL_OFFSET:
254 type = IPMI_FRU_AREA_INTERNAL_USE;
255 break;
256
257 case IPMI_FRU_CHASSIS_OFFSET:
258 type = IPMI_FRU_AREA_CHASSIS_INFO;
259 break;
260
261 case IPMI_FRU_BOARD_OFFSET:
262 type = IPMI_FRU_AREA_BOARD_INFO;
263 break;
264
265 case IPMI_FRU_PRODUCT_OFFSET:
266 type = IPMI_FRU_AREA_PRODUCT_INFO;
267 break;
268
269 case IPMI_FRU_MULTI_OFFSET:
270 type = IPMI_FRU_AREA_MULTI_RECORD;
271 break;
272
273 default:
274 type = IPMI_FRU_AREA_TYPE_MAX;
275 }
276
277 return type;
278}
279
vishwac93d6d42015-12-16 11:55:16 -0600280///-----------------------------------------------
281// Validates the data for crc and mandatory fields
282///-----------------------------------------------
283int verify_fru_data(const uint8_t *data, const size_t len)
284{
285 uint8_t checksum = 0;
286 int rc = -1;
287
288 // Validate for first byte to always have a value of [1]
289 if(data[0] != IPMI_FRU_HDR_BYTE_ZERO)
290 {
291 fprintf(stderr, "Invalid entry:[%d] in byte-0\n",data[0]);
292 return rc;
293 }
294#ifdef __IPMI_DEBUG__
295 else
296 {
297 printf("SUCCESS: Validated [0x%X] in entry_1 of fru_data\n",data[0]);
298 }
299#endif
300
301 // See if the calculated CRC matches with the embedded one.
302 // CRC to be calculated on all except the last one that is CRC itself.
303 checksum = calculate_crc(data, len - 1);
304 if(checksum != data[len-1])
305 {
306#ifdef __IPMI_DEBUG__
307 fprintf(stderr, "Checksum mismatch."
308 " Calculated:[0x%X], Embedded:[0x%X]\n",
309 checksum, data[len]);
310#endif
311 return rc;
312 }
313#ifdef __IPMI_DEBUG__
314 else
315 {
316 printf("SUCCESS: Checksum matches:[0x%X]\n",checksum);
317 }
318#endif
319
320 return EXIT_SUCCESS;
321}
322
Vishwa4be4b7a2015-10-31 22:55:50 -0500323//------------------------------------------------------------------------
324// Takes FRU data, invokes Parser for each fru record area and updates
325// Inventory
326//------------------------------------------------------------------------
vishwac93d6d42015-12-16 11:55:16 -0600327int ipmi_update_inventory(fru_area_vec_t & area_vec)
Vishwa4be4b7a2015-10-31 22:55:50 -0500328{
vishwac93d6d42015-12-16 11:55:16 -0600329 // Generic error reporter
Vishwa4be4b7a2015-10-31 22:55:50 -0500330 int rc = 0;
vishwaf3ca3522015-12-02 10:35:13 -0600331
Vishwa4be4b7a2015-10-31 22:55:50 -0500332 // Dictionary object to hold Name:Value pair
333 sd_bus_message *fru_dict = NULL;
334
335 // SD Bus error report mechanism.
336 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
337
vishwac93d6d42015-12-16 11:55:16 -0600338 // Response from sd bus calls
Vishwa4be4b7a2015-10-31 22:55:50 -0500339 sd_bus_message *response = NULL;
340
Vishwa4be4b7a2015-10-31 22:55:50 -0500341 // For each FRU area, extract the needed data , get it parsed and update
342 // the Inventory.
343 for(auto& iter : area_vec)
344 {
vishwac93d6d42015-12-16 11:55:16 -0600345 // Start fresh on each.
Vishwa4be4b7a2015-10-31 22:55:50 -0500346 sd_bus_error_free(&bus_error);
347 sd_bus_message_unref(response);
348 sd_bus_message_unref(fru_dict);
vishwaf3ca3522015-12-02 10:35:13 -0600349
Vishwa4be4b7a2015-10-31 22:55:50 -0500350 // Constructor to allow further initializations and customization.
vishwac93d6d42015-12-16 11:55:16 -0600351 rc = sd_bus_message_new_method_call((iter)->get_bus_type(),
Vishwa4be4b7a2015-10-31 22:55:50 -0500352 &fru_dict,
vishwac93d6d42015-12-16 11:55:16 -0600353 (iter)->get_bus_name(),
354 (iter)->get_obj_path(),
355 (iter)->get_intf_name(),
Vishwa4be4b7a2015-10-31 22:55:50 -0500356 "update");
357 if(rc < 0)
358 {
vishwac93d6d42015-12-16 11:55:16 -0600359 fprintf(stderr,"ERROR: creating a update method call for bus_name:[%s]\n",
360 (iter)->get_bus_name());
Vishwa4be4b7a2015-10-31 22:55:50 -0500361 break;
362 }
363
364 // A Dictionary ({}) having (string, variant)
365 rc = sd_bus_message_open_container(fru_dict, 'a', "{sv}");
366 if(rc < 0)
367 {
368 fprintf(stderr,"ERROR:[%d] creating a dict container:\n",errno);
369 break;
370 }
371
372 // Fill the container with information
vishwac93d6d42015-12-16 11:55:16 -0600373 rc = parse_fru_area((iter)->get_type(), (void *)(iter)->get_data(), (iter)->get_len(), fru_dict);
Vishwa4be4b7a2015-10-31 22:55:50 -0500374 if(rc < 0)
375 {
376 fprintf(stderr,"ERROR parsing FRU records\n");
377 break;
378 }
379
380 sd_bus_message_close_container(fru_dict);
381
382 // Now, Make the actual call to update the FRU inventory database with the
383 // dictionary given by FRU Parser. There is no response message expected for
384 // this.
vishwac93d6d42015-12-16 11:55:16 -0600385 rc = sd_bus_call((iter)->get_bus_type(), // On the System Bus
386 fru_dict, // With the Name:value dictionary array
387 0, //
388 &bus_error, // Object to return error.
389 &response); // Response message if any.
Vishwa4be4b7a2015-10-31 22:55:50 -0500390
391 if(rc < 0)
392 {
393 fprintf(stderr, "ERROR:[%s] updating FRU inventory for ID:[0x%X]\n",
vishwac93d6d42015-12-16 11:55:16 -0600394 bus_error.message, (iter)->get_fruid());
395 break;
Vishwa4be4b7a2015-10-31 22:55:50 -0500396 }
vishwac93d6d42015-12-16 11:55:16 -0600397 else if((iter)->is_bmc_fru())
vishwaf3ca3522015-12-02 10:35:13 -0600398 {
vishwac93d6d42015-12-16 11:55:16 -0600399 // For FRUs that are accessible by HostBoot, host boot does all of
400 // these.
401 printf("SUCCESS: Updated:[%s_%d] successfully. Setting Valid bit\n",
402 (iter)->get_name(), (iter)->get_fruid());
vishwaf3ca3522015-12-02 10:35:13 -0600403
vishwac93d6d42015-12-16 11:55:16 -0600404 (iter)->set_valid(true);
vishwaf3ca3522015-12-02 10:35:13 -0600405 }
Vishwa4be4b7a2015-10-31 22:55:50 -0500406 else
407 {
vishwac93d6d42015-12-16 11:55:16 -0600408 printf("SUCCESS: Updated:[%s_%d] successfully\n",
409 (iter)->get_name(), (iter)->get_fruid());
Vishwa4be4b7a2015-10-31 22:55:50 -0500410 }
411 } // END walking the vector of areas and updating
412
413 sd_bus_error_free(&bus_error);
414 sd_bus_message_unref(response);
415 sd_bus_message_unref(fru_dict);
Vishwa4be4b7a2015-10-31 22:55:50 -0500416
417 return rc;
418}
419
vishwac93d6d42015-12-16 11:55:16 -0600420///----------------------------------------------------
421// Checks if a particular fru area is populated or not
422///----------------------------------------------------
423bool remove_invalid_area(const std::unique_ptr<ipmi_fru> &fru_area)
Vishwa4be4b7a2015-10-31 22:55:50 -0500424{
vishwac93d6d42015-12-16 11:55:16 -0600425 // Filter the ones that do not have dbus reference.
426 if((strlen((fru_area)->get_bus_name()) == 0) ||
427 (strlen((fru_area)->get_obj_path()) == 0) ||
428 (strlen((fru_area)->get_intf_name()) == 0))
429 {
430 return true;
431 }
432 return false;
433}
Vishwa4be4b7a2015-10-31 22:55:50 -0500434
vishwac93d6d42015-12-16 11:55:16 -0600435///----------------------------------------------------------------------------------
436// Populates various FRU areas
437// @prereq : This must be called only after validating common header.
438///----------------------------------------------------------------------------------
439int ipmi_populate_fru_areas(uint8_t *fru_data, const size_t data_len,
440 fru_area_vec_t & fru_area_vec)
441{
vishwa13555bd2015-11-10 12:10:38 -0600442 size_t area_offset = 0;
vishwac93d6d42015-12-16 11:55:16 -0600443 int rc = -1;
Vishwa4be4b7a2015-10-31 22:55:50 -0500444
vishwac93d6d42015-12-16 11:55:16 -0600445 // Now walk the common header and see if the file size has atleast the last
446 // offset mentioned by the common_hdr. If the file size is less than the
447 // offset of any if the fru areas mentioned in the common header, then we do
448 // not have a complete file.
449 for(uint8_t fru_entry = IPMI_FRU_INTERNAL_OFFSET;
450 fru_entry < (sizeof(struct common_header) -2); fru_entry++)
451 {
452 // Actual offset in the payload is the offset mentioned in common header
453 // multipled by 8. Common header is always the first 8 bytes.
454 area_offset = fru_data[fru_entry] * IPMI_EIGHT_BYTES;
455 if(area_offset && (data_len < (area_offset + 2)))
456 {
457 // Our file size is less than what it needs to be. +2 because we are
458 // using area len that is at 2 byte off area_offset
459 fprintf(stderr, "fru file is incomplete. Size:[%d]\n",data_len);
460 return rc;
461 }
462 else if(area_offset)
463 {
464 // Read 2 bytes to know the actual size of area.
465 uint8_t area_hdr[2] = {0};
466 memcpy(area_hdr, &((uint8_t *)fru_data)[area_offset], sizeof(area_hdr));
Vishwa4be4b7a2015-10-31 22:55:50 -0500467
vishwac93d6d42015-12-16 11:55:16 -0600468 // Size of this area will be the 2nd byte in the fru area header.
469 size_t area_len = area_hdr[1] * IPMI_EIGHT_BYTES;
470 uint8_t area_data[area_len] = {0};
Vishwa4be4b7a2015-10-31 22:55:50 -0500471
vishwac93d6d42015-12-16 11:55:16 -0600472 printf("fru data size:[%d], area offset:[%d], area_size:[%d]\n",
473 data_len, area_offset, area_len);
Vishwa4be4b7a2015-10-31 22:55:50 -0500474
vishwac93d6d42015-12-16 11:55:16 -0600475 // See if we really have that much buffer. We have area offset amd
476 // from there, the actual len.
477 if(data_len < (area_len + area_offset))
478 {
479 fprintf(stderr, "Incomplete Fru file.. Size:[%d]\n",data_len);
480 return rc;
481 }
482
483 // Save off the data.
484 memcpy(area_data, &((uint8_t *)fru_data)[area_offset], area_len);
485
486 // Validate the crc
487 rc = verify_fru_data(area_data, area_len);
488 if(rc < 0)
489 {
490 fprintf(stderr, "Error validating fru area. offset:[%d]\n",area_offset);
491 return rc;
492 }
493 else
494 {
495 printf("Successfully verified area checksum. offset:[%d]\n",area_offset);
496 }
497
498 // We already have a vector that is passed to us containing all
499 // of the fields populated. Update the data portion now.
500 for(auto& iter : fru_area_vec)
501 {
502 if((iter)->get_type() == get_fru_area_type(fru_entry))
503 {
504 (iter)->set_data(area_data, area_len);
505 }
506 }
507 } // If we have fru data present
508 } // Walk common_hdr
509
510 // Not all the fields will be populated in a fru data. Mostly all cases will
511 // not have more than 2 or 3.
512 fru_area_vec.erase(std::remove_if(fru_area_vec.begin(), fru_area_vec.end(),
513 remove_invalid_area), fru_area_vec.end());
514
515 return EXIT_SUCCESS;
516}
517
518///---------------------------------------------------------
519// Validates the fru data per ipmi common header constructs.
520// Returns with updated common_hdr and also file_size
521//----------------------------------------------------------
522int ipmi_validate_common_hdr(const uint8_t *fru_data, const size_t data_len)
523{
524 int rc = -1;
Vishwa4be4b7a2015-10-31 22:55:50 -0500525
526 uint8_t common_hdr[sizeof(struct common_header)] = {0};
vishwac93d6d42015-12-16 11:55:16 -0600527 if(data_len >= sizeof(common_hdr))
Vishwa4be4b7a2015-10-31 22:55:50 -0500528 {
vishwac93d6d42015-12-16 11:55:16 -0600529 memcpy(common_hdr, fru_data, sizeof(common_hdr));
Vishwa4be4b7a2015-10-31 22:55:50 -0500530 }
531 else
532 {
vishwac93d6d42015-12-16 11:55:16 -0600533 fprintf(stderr, "Incomplete fru data file. Size:[%d]\n", data_len);
534 return rc;
Vishwa4be4b7a2015-10-31 22:55:50 -0500535 }
536
vishwac93d6d42015-12-16 11:55:16 -0600537 // Verify the crc and size
538 rc = verify_fru_data(common_hdr, sizeof(common_hdr));
539 if(rc < 0)
Vishwa4be4b7a2015-10-31 22:55:50 -0500540 {
vishwac93d6d42015-12-16 11:55:16 -0600541 fprintf(stderr, "Failed to validate common header\n");
542 return rc;
Vishwa4be4b7a2015-10-31 22:55:50 -0500543 }
544
vishwac93d6d42015-12-16 11:55:16 -0600545 return EXIT_SUCCESS;
546}
Vishwa4be4b7a2015-10-31 22:55:50 -0500547
vishwac93d6d42015-12-16 11:55:16 -0600548//------------------------------------------------------------
549// Cleanup routine
550//------------------------------------------------------------
551int cleanup_error(FILE *fru_fp, fru_area_vec_t & fru_area_vec)
552{
553 if(fru_fp != NULL)
Vishwa4be4b7a2015-10-31 22:55:50 -0500554 {
vishwac93d6d42015-12-16 11:55:16 -0600555 fclose(fru_fp);
556 fru_fp = NULL;
557 }
vishwaf3ca3522015-12-02 10:35:13 -0600558
Vishwa4be4b7a2015-10-31 22:55:50 -0500559 if(!(fru_area_vec.empty()))
560 {
vishwac93d6d42015-12-16 11:55:16 -0600561 fru_area_vec.clear();
Vishwa4be4b7a2015-10-31 22:55:50 -0500562 }
vishwaf3ca3522015-12-02 10:35:13 -0600563
vishwac93d6d42015-12-16 11:55:16 -0600564 return -1;
Vishwa4be4b7a2015-10-31 22:55:50 -0500565}
566
567///-----------------------------------------------------
568// Accepts the filename and validates per IPMI FRU spec
569//----------------------------------------------------
vishwaf3ca3522015-12-02 10:35:13 -0600570int ipmi_validate_fru_area(const uint8_t fruid, const char *fru_file_name,
vishwac93d6d42015-12-16 11:55:16 -0600571 sd_bus *bus_type, const bool bmc_fru)
Vishwa4be4b7a2015-10-31 22:55:50 -0500572{
vishwac93d6d42015-12-16 11:55:16 -0600573 size_t data_len = 0;
574 size_t bytes_read = 0;
575 int rc = -1;
Vishwa4be4b7a2015-10-31 22:55:50 -0500576
vishwac93d6d42015-12-16 11:55:16 -0600577 // Vector that holds individual IPMI FRU AREAs. Although MULTI and INTERNAL
578 // are not used, keeping it here for completeness.
579 fru_area_vec_t fru_area_vec;
580 for(uint8_t fru_entry = IPMI_FRU_INTERNAL_OFFSET;
581 fru_entry < (sizeof(struct common_header) -2); fru_entry++)
582 {
583 // Create an object and push onto a vector.
584 std::unique_ptr<ipmi_fru> fru_area = std::make_unique<ipmi_fru>
585 (fruid, get_fru_area_type(fru_entry), bus_type, bmc_fru);
586
587 // Physically being present
588 bool present = std::ifstream(fru_file_name);
589 fru_area->set_present(present);
590
591 // And update the sd_bus paths as well.
592 fru_area->setup_sd_bus_paths();
593 fru_area_vec.emplace_back(std::move(fru_area));
594 }
595
596 FILE *fru_fp = fopen(fru_file_name,"rb");
597 if(fru_fp == NULL)
Vishwa4be4b7a2015-10-31 22:55:50 -0500598 {
599 fprintf(stderr, "ERROR: opening:[%s]\n",fru_file_name);
600 perror("Error:");
vishwac93d6d42015-12-16 11:55:16 -0600601 return cleanup_error(fru_fp, fru_area_vec);
Vishwa4be4b7a2015-10-31 22:55:50 -0500602 }
603
vishwac93d6d42015-12-16 11:55:16 -0600604 // Get the size of the file to see if it meets minimum requirement
605 if(fseek(fru_fp, 0, SEEK_END))
Vishwa4be4b7a2015-10-31 22:55:50 -0500606 {
607 perror("Error:");
vishwac93d6d42015-12-16 11:55:16 -0600608 return cleanup_error(fru_fp, fru_area_vec);
Vishwa4be4b7a2015-10-31 22:55:50 -0500609 }
610
vishwac93d6d42015-12-16 11:55:16 -0600611 // Allocate a buffer to hold entire file content
612 data_len = ftell(fru_fp);
613 uint8_t fru_data[data_len] = {0};
Vishwa4be4b7a2015-10-31 22:55:50 -0500614
vishwac93d6d42015-12-16 11:55:16 -0600615 rewind(fru_fp);
616 bytes_read = fread(fru_data, data_len, 1, fru_fp);
Vishwa4be4b7a2015-10-31 22:55:50 -0500617 if(bytes_read != 1)
618 {
vishwac93d6d42015-12-16 11:55:16 -0600619 fprintf(stderr, "Failed reading fru data. Bytes_read=[%d]\n",bytes_read);
Vishwa4be4b7a2015-10-31 22:55:50 -0500620 perror("Error:");
vishwac93d6d42015-12-16 11:55:16 -0600621 return cleanup_error(fru_fp, fru_area_vec);
Vishwa4be4b7a2015-10-31 22:55:50 -0500622 }
Vishwa4be4b7a2015-10-31 22:55:50 -0500623
vishwac93d6d42015-12-16 11:55:16 -0600624 // We are done reading.
625 fclose(fru_fp);
626 fru_fp = NULL;
627
628 rc = ipmi_validate_common_hdr(fru_data, data_len);
vishwaf3ca3522015-12-02 10:35:13 -0600629 if(rc < 0)
Vishwa4be4b7a2015-10-31 22:55:50 -0500630 {
vishwac93d6d42015-12-16 11:55:16 -0600631 return cleanup_error(fru_fp, fru_area_vec);
632 }
633
634 // Now that we validated the common header, populate various fru sections if we have them here.
635 rc = ipmi_populate_fru_areas(fru_data, data_len, fru_area_vec);
636 if(rc < 0)
637 {
638 fprintf(stderr,"Populating FRU areas failed for:[%d]\n",fruid);
639 return cleanup_error(fru_fp, fru_area_vec);
Vishwa4be4b7a2015-10-31 22:55:50 -0500640 }
641 else
642 {
vishwac93d6d42015-12-16 11:55:16 -0600643 printf("SUCCESS: Populated FRU areas for:[%s]\n",fru_file_name);
Vishwa4be4b7a2015-10-31 22:55:50 -0500644 }
645
vishwac93d6d42015-12-16 11:55:16 -0600646#ifdef __IPMI_DEBUG__
647 for(auto& iter : fru_area_vec)
Vishwa4be4b7a2015-10-31 22:55:50 -0500648 {
vishwac93d6d42015-12-16 11:55:16 -0600649 printf("FRU ID : [%d]\n",(iter)->get_fruid());
650 printf("AREA NAME : [%s]\n",(iter)->get_name());
651 printf("TYPE : [%d]\n",(iter)->get_type());
652 printf("LEN : [%d]\n",(iter)->get_len());
653 printf("BUS NAME : [%s]\n", (iter)->get_bus_name());
654 printf("OBJ PATH : [%s]\n", (iter)->get_obj_path());
655 printf("INTF NAME :[%s]\n", (iter)->get_intf_name());
Vishwa4be4b7a2015-10-31 22:55:50 -0500656 }
vishwac93d6d42015-12-16 11:55:16 -0600657#endif
658
659 // If the vector is populated with everything, then go ahead and update the
660 // inventory.
661 if(!(fru_area_vec.empty()))
662 {
663
664#ifdef __IPMI_DEBUG__
665 printf("\n SIZE of vector is : [%d] \n",fru_area_vec.size());
666#endif
667 rc = ipmi_update_inventory(fru_area_vec);
668 if(rc <0)
669 {
670 fprintf(stderr, "Error updating inventory\n");
671 }
672 }
673
674 // we are done with all that we wanted to do. This will do the job of
675 // calling any destructors too.
676 fru_area_vec.clear();
Vishwa4be4b7a2015-10-31 22:55:50 -0500677
678 return rc;
679}