From a87957ac7fb088674229b8189758caf6d7c3ca07 Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Wed, 17 Nov 2004 23:16:44 +0000 Subject: [PATCH] handle errors gracefully, check values before malloc, add external function for entity association lookups --- ipmitool/lib/ipmi_fru.c | 304 ++++++++++++++++++++++++---------------- 1 file changed, 180 insertions(+), 124 deletions(-) diff --git a/ipmitool/lib/ipmi_fru.c b/ipmitool/lib/ipmi_fru.c index bbce0af..d317cf0 100644 --- a/ipmitool/lib/ipmi_fru.c +++ b/ipmitool/lib/ipmi_fru.c @@ -62,20 +62,22 @@ static char * get_fru_area_str(unsigned char * data, int * offset) k = ((data[off] & 0xC0) >> 6); /* bits 6,7 contain format */ len = data[off++]; - len &= 0x3f; /* bits 0:5 contain length */ + len &= 0x3f; /* bits 0:5 contain length */ switch(k) { - case 0: /* 0: binary/unspecified */ - size = (len*2); /* (hex dump -> 2x length) */ + case 0: /* 0: binary/unspecified */ + size = (len*2); /* (hex dump -> 2x length) */ break; - case 2: /* 2: 6-bit ASCII */ + case 2: /* 2: 6-bit ASCII */ size = ((((len+2)*4)/3) & ~3);/* (4 chars per group of 1-3 bytes) */ break; - case 3: /* 3: 8-bit ASCII */ - case 1: /* 1: BCD plus */ - size = len; /* (no length adjustment) */ + case 3: /* 3: 8-bit ASCII */ + case 1: /* 1: BCD plus */ + size = len; /* (no length adjustment) */ } + if (size < 1) + return NULL; str = malloc(size+1); if (!str) return NULL; @@ -85,7 +87,7 @@ static char * get_fru_area_str(unsigned char * data, int * offset) else { switch(k) { case 0: - strcpy(str, buf2str(&data[off], len)); + strncpy(str, buf2str(&data[off], len)); break; case 1: @@ -140,9 +142,20 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, unsigned char id, struct ipmi_rq req; unsigned char msg_data[4]; - finish = offset + length; - if (finish > fru->size) + if (offset > fru->size) { + if (verbose) + printf("Read FRU Area offset incorrect: %d > %d\n", + offset, fru->size); return -1; + } + + finish = offset + length; + if (finish > fru->size) { + finish = fru->size; + if (verbose) + printf("Read FRU Area length %d too large, adjusting to %d\n", + offset + length, finish - offset); + } memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_STORAGE; @@ -155,7 +168,7 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, unsigned char id, do { tmp = fru->access ? off >> 1 : off; msg_data[0] = id; - msg_data[1] = (unsigned char)tmp; + msg_data[1] = (unsigned char)(tmp & 0xff); msg_data[2] = (unsigned char)(tmp >> 8); tmp = finish - off; if (tmp > fru_data_rqst_size) @@ -164,12 +177,23 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, unsigned char id, msg_data[3] = (unsigned char)tmp; rsp = intf->sendrecv(intf, &req); - if (!rsp) + if (!rsp) { + if (verbose) + printf("FRU Read failed\n"); break; - if ((rsp->ccode==0xc7 || rsp->ccode==0xc8) && --fru_data_rqst_size > 8) - continue; - if (rsp->ccode) + } + if (rsp->ccode) { + if (verbose) + printf("FRU Read failed: %s\n", + val2str(rsp->ccode, completion_code_vals)); + if ((rsp->ccode==0xc7 || rsp->ccode==0xc8) && --fru_data_rqst_size > 8) { + if (verbose) + printf("Retrying FRU read with request size %d\n", + fru_data_rqst_size); + continue; + } break; + } tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0]; memcpy((frubuf + off), rsp->data + 1, tmp); @@ -179,7 +203,7 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, unsigned char id, return (off >= finish); } -static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) +static void __ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) { struct ipmi_rs * rsp; struct ipmi_rq req; @@ -212,13 +236,13 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) req.msg.data_len = 1; rsp = intf->sendrecv(intf, &req); - if (!rsp) + if (!rsp) { + printf(" Device not present (No Response)\n"); return; - - if(rsp->ccode) - { - if (rsp->ccode == 0xc3) - printf (" Timeout accessing FRU info. (Device not present?)\n"); + } + if(rsp->ccode) { + printf(" Device not present (%s)\n", + val2str(rsp->ccode, completion_code_vals)); return; } fru.size = (rsp->data[1] << 8) | rsp->data[0]; @@ -227,8 +251,10 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) if (verbose > 1) printf("fru.size = %d bytes (accessed by %s)\n", fru.size, fru.access ? "words" : "bytes"); - if (!fru.size) + if (!fru.size) { + printf(" FRU size is zero!\n"); return; + } msg_data[0] = id; msg_data[1] = 0; @@ -246,10 +272,13 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) if (!rsp) return; - if(rsp->ccode) - { - if (rsp->ccode == 0xc3) - printf (" Timeout while reading FRU data. (Device not present?)\n"); + if (!rsp) { + printf(" Device not present (No Response)\n"); + return; + } + if(rsp->ccode) { + printf(" Device not present (%s)\n", + val2str(rsp->ccode, completion_code_vals)); return; } @@ -260,7 +289,7 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) if (header.version != 0x01) { - printf (" Unknown FRU header version %02x.\n", header.version); + printf (" Unknown FRU header version %02x.\n", header.version); return; } @@ -279,6 +308,8 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) printf("fru.header.offset.multi: 0x%x\n", area_offsets[OFF_MULTI]); } + if (fru.size < 1) + return; fru_data = malloc(fru.size+1); if (!fru_data) return; @@ -302,16 +333,18 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) chassis.part = get_fru_area_str(fru_data, &i); chassis.serial = get_fru_area_str(fru_data, &i); - printf(" Chassis Type : %s\n", chassis_type_desc[chassis.type]); - printf(" Chassis Part : %s\n", chassis.part); - printf(" Chassis Serial : %s\n", chassis.serial); + printf(" Chassis Type : %s\n", chassis_type_desc[chassis.type]); + if (strlen(chassis.part) > 0) + printf(" Chassis Part Number : %s\n", chassis.part); + if (strlen(chassis.serial) > 0) + printf(" Chassis Serial : %s\n", chassis.serial); while (fru_data[i] != 0xc1 && i < area_offsets[OFF_CHASSIS] + chassis.area_len) { char *extra; extra = get_fru_area_str(fru_data, &i); - if (extra [0]) printf(" Chassis Extra : %s\n", extra); + if (extra [0]) printf(" Chassis Extra : %s\n", extra); free(extra); } @@ -340,20 +373,24 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) board.part = get_fru_area_str(fru_data, &i); board.fru = get_fru_area_str(fru_data, &i); - printf(" Board Mfg : %s\n", board.mfg); - printf(" Board Product : %s\n", board.prod); - printf(" Board Serial : %s\n", board.serial); - printf(" Board Part : %s\n", board.part); + if (strlen(board.mfg) > 0) + printf(" Board Manufacturer : %s\n", board.mfg); + if (strlen(board.prod) > 0) + printf(" Board Product : %s\n", board.prod); + if (strlen(board.serial) > 0) + printf(" Board Serial : %s\n", board.serial); + if (strlen(board.part) > 0) + printf(" Board Part Number : %s\n", board.part); - if (verbose > 0) - printf(" Board FRU ID : %s\n", board.fru); + if ((verbose > 0) && (strlen(board.fru) > 0)) + printf(" Board FRU ID : %s\n", board.fru); while (fru_data[i] != 0xc1 && i < area_offsets[OFF_BOARD] + board.area_len) { char *extra; extra = get_fru_area_str(fru_data, &i); - if (extra [0]) printf(" Board Extra : %s\n", extra); + if (extra [0]) printf(" Board Extra : %s\n", extra); free(extra); } @@ -386,22 +423,28 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) product.asset = get_fru_area_str(fru_data, &i); product.fru = get_fru_area_str(fru_data, &i); - printf(" Product Mfg : %s\n", product.mfg); - printf(" Product Name : %s\n", product.name); - printf(" Product Part : %s\n", product.part); - printf(" Product Version : %s\n", product.version); - printf(" Product Serial : %s\n", product.serial); - printf(" Product Asset : %s\n", product.asset); + if (strlen(product.mfg) > 0) + printf(" Product Manufacturer : %s\n", product.mfg); + if (strlen(product.name) > 0) + printf(" Product Name : %s\n", product.name); + if (strlen(product.part) > 0) + printf(" Product Part Number : %s\n", product.part); + if (strlen(product.version) > 0) + printf(" Product Version : %s\n", product.version); + if (strlen(product.serial) > 0) + printf(" Product Serial : %s\n", product.serial); + if (strlen(product.asset) > 0) + printf(" Product Asset Tag : %s\n", product.asset); - if (verbose > 0) - printf(" Product FRU ID : %s\n", product.fru); + if ((verbose > 0) && (strlen(product.fru) > 0)) + printf(" Product FRU ID : %s\n", product.fru); while (fru_data[i] != 0xc1 && i < area_offsets[OFF_PRODUCT] + product.area_len) { char *extra; extra = get_fru_area_str(fru_data, &i); - if (extra [0]) printf(" Product Extra : %s\n", extra); + if (extra [0]) printf(" Product Extra : %s\n", extra); free(extra); } @@ -443,7 +486,7 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) if (read_fru_area(intf, &fru, id, last_off, len, fru_data) > 0) last_off += len; else { - printf("ERROR: reading FRU data\n"); + printf("ERROR: reading FRU multirecord data\n"); break; } } @@ -466,16 +509,16 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) peak_hold_up_time = (ps->peak_cap_ht & 0xf000) >> 12; peak_capacity = ps->peak_cap_ht & 0x0fff; - printf (" Power Supply Record\n"); - printf (" Capacity : %d W\n", ps->capacity); - printf (" Peak VA : %d VA\n", ps->peak_va); - printf (" Inrush Current : %d A\n", ps->inrush_current); - printf (" Inrush Interval : %d ms\n", ps->inrush_interval); - printf (" Input Voltage Range 1 : %d-%d V\n", ps->lowend_input1 / 100, ps->highend_input1 / 100); - printf (" Input Voltage Range 2 : %d-%d V\n", ps->lowend_input2 / 100, ps->highend_input2 / 100); - printf (" Input Frequency Range : %d-%d Hz\n", ps->lowend_freq, ps->highend_freq); - printf (" A/C Dropout Tolerance : %d ms\n", ps->dropout_tolerance); - printf (" Flags : %s%s%s%s%s\n", + printf (" Power Supply Record\n"); + printf (" Capacity : %d W\n", ps->capacity); + printf (" Peak VA : %d VA\n", ps->peak_va); + printf (" Inrush Current : %d A\n", ps->inrush_current); + printf (" Inrush Interval : %d ms\n", ps->inrush_interval); + printf (" Input Voltage Range 1 : %d-%d V\n", ps->lowend_input1 / 100, ps->highend_input1 / 100); + printf (" Input Voltage Range 2 : %d-%d V\n", ps->lowend_input2 / 100, ps->highend_input2 / 100); + printf (" Input Frequency Range : %d-%d Hz\n", ps->lowend_freq, ps->highend_freq); + printf (" A/C Dropout Tolerance : %d ms\n", ps->dropout_tolerance); + printf (" Flags : %s%s%s%s%s\n", ps->predictive_fail ? "'Predictive fail' " : "", ps->pfc ? "'Power factor correction' " : "", ps->autoswitch ? "'Autoswitch voltage' " : "", @@ -483,16 +526,16 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) ps->predictive_fail ? ps->rps_threshold ? ps->tach ? "'Two pulses per rotation'" : "'One pulse per rotation'" : ps->tach ? "'Failure on pin de-assertion'" : "'Failure on pin assertion'" : ""); - printf (" Peak capacity : %d W\n", peak_capacity); - printf (" Peak capacity holdup : %d s\n", peak_hold_up_time); + printf (" Peak capacity : %d W\n", peak_capacity); + printf (" Peak capacity holdup : %d s\n", peak_hold_up_time); if (ps->combined_capacity == 0) - printf (" Combined capacity : not specified\n"); + printf (" Combined capacity : not specified\n"); else - printf (" Combined capacity : %d W (%s and %s)\n", ps->combined_capacity, + printf (" Combined capacity : %d W (%s and %s)\n", ps->combined_capacity, combined_voltage_desc [ps->combined_voltage1], combined_voltage_desc [ps->combined_voltage2]); if (ps->predictive_fail) - printf (" Fan lower threshold : %d RPS\n", ps->rps_threshold); + printf (" Fan lower threshold : %d RPS\n", ps->rps_threshold); break; @@ -508,15 +551,15 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) dc->max_current = BSWAP_16(dc->max_current); #endif - printf (" DC Output Record\n"); - printf (" Output Number : %d\n", dc->output_number); - printf (" Standby power : %s\n", dc->standby ? "Yes" : "No"); - printf (" Nominal voltage : %.2f V\n", (double) dc->nominal_voltage / 100); - printf (" Max negative deviation : %.2f V\n", (double) dc->max_neg_dev / 100); - printf (" Max positive deviation : %.2f V\n", (double) dc->max_pos_dev / 100); - printf (" Ripple and noise pk-pk : %d mV\n", dc->ripple_and_noise); - printf (" Minimum current draw : %.3f A\n", (double) dc->min_current / 1000); - printf (" Maximum current draw : %.3f A\n", (double) dc->max_current / 1000); + printf (" DC Output Record\n"); + printf (" Output Number : %d\n", dc->output_number); + printf (" Standby power : %s\n", dc->standby ? "Yes" : "No"); + printf (" Nominal voltage : %.2f V\n", (double) dc->nominal_voltage / 100); + printf (" Max negative deviation : %.2f V\n", (double) dc->max_neg_dev / 100); + printf (" Max positive deviation : %.2f V\n", (double) dc->max_pos_dev / 100); + printf (" Ripple and noise pk-pk : %d mV\n", dc->ripple_and_noise); + printf (" Minimum current draw : %.3f A\n", (double) dc->min_current / 1000); + printf (" Maximum current draw : %.3f A\n", (double) dc->max_current / 1000); break; case FRU_RECORD_TYPE_DC_LOAD: @@ -531,14 +574,14 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) dl->max_current = BSWAP_16(dl->max_current); #endif - printf (" DC Load Record\n"); - printf (" Output Number : %d\n", dl->output_number); - printf (" Nominal voltage : %.2f V\n", (double) dl->nominal_voltage / 100); - printf (" Min voltage allowed : %.2f V\n", (double) dl->min_voltage / 100); - printf (" Max voltage allowed : %.2f V\n", (double) dl->max_voltage / 100); - printf (" Ripple and noise pk-pk : %d mV\n", dl->ripple_and_noise); - printf (" Minimum current load : %.3f A\n", (double) dl->min_current / 1000); - printf (" Maximum current load : %.3f A\n", (double) dl->max_current / 1000); + printf (" DC Load Record\n"); + printf (" Output Number : %d\n", dl->output_number); + printf (" Nominal voltage : %.2f V\n", (double) dl->nominal_voltage / 100); + printf (" Min voltage allowed : %.2f V\n", (double) dl->min_voltage / 100); + printf (" Max voltage allowed : %.2f V\n", (double) dl->max_voltage / 100); + printf (" Ripple and noise pk-pk : %d mV\n", dl->ripple_and_noise); + printf (" Minimum current load : %.3f A\n", (double) dl->min_current / 1000); + printf (" Maximum current load : %.3f A\n", (double) dl->max_current / 1000); break; } i += h->len + sizeof (struct fru_multirec_header); @@ -548,16 +591,66 @@ static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id) free(fru_data); } +void ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) +{ + char desc[17]; + unsigned char sav_addr; + + if (!fru) { + __ipmi_fru_print(intf, 0); + return; + } + + if (fru->dev_type != 0x10 && + (fru->dev_type_modifier != 0x02 || + fru->dev_type < 0x08 || fru->dev_type > 0x0f)) + return; + + memset(desc, 0, sizeof(desc)); + memcpy(desc, fru->id_string, fru->id_code & 0x01f); + desc[fru->id_code & 0x01f] = 0; + printf("FRU Device Description : %s (ID %d)\n", desc, fru->device_id); + + switch (fru->dev_type_modifier) { + case 0x00: + case 0x02: + sav_addr = intf->target_addr; + intf->target_addr = fru->dev_slave_addr; + + if (intf->target_addr == IPMI_BMC_SLAVE_ADDR && + fru->device_id == 0) + printf(" (Builtin FRU device)\n"); + else + __ipmi_fru_print(intf, fru->device_id); + + intf->target_addr = sav_addr; + break; + case 0x01: + ipmi_spd_print(intf, fru->device_id); + break; + default: + if (verbose) + printf(" Unsupported device 0x%02x " + "type 0x%02x with modifier 0x%02x\n", + fru->device_id, fru->dev_type, + fru->dev_type_modifier); + else + printf(" Unsupported device\n"); + } + printf("\n"); +} + static void ipmi_fru_print_all(struct ipmi_intf * intf) { struct ipmi_sdr_iterator * itr; struct sdr_get_rs * header; - struct sdr_record_fru_device_locator * fru; + struct sdr_record_fru_locator * fru; char desc[17]; unsigned char sav_addr; - printf ("Builtin FRU device\n"); - ipmi_fru_print(intf, 0); /* TODO: Figure out if FRU device 0 may show up in SDR records. */ + printf("FRU Device Description : Builtin FRU Device (ID 0)\n"); + ipmi_fru_print(intf, NULL); /* TODO: Figure out if FRU device 0 may show up in SDR records. */ + printf("\n"); if (!(itr = ipmi_sdr_start(intf))) return; @@ -567,48 +660,11 @@ static void ipmi_fru_print_all(struct ipmi_intf * intf) if (header->type != SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR) continue; - fru = (struct sdr_record_fru_device_locator *) ipmi_sdr_get_record(intf, header, itr); + fru = (struct sdr_record_fru_locator *)ipmi_sdr_get_record(intf, header, itr); if (!fru) continue; - if (fru->device_type != 0x10 - && (fru->device_type_modifier != 0x02 - || fru->device_type < 0x08 || fru->device_type > 0x0f)) - continue; - - memset(desc, 0, sizeof(desc)); - memcpy(desc, fru->id_string, fru->id_code & 0x01f); - desc[fru->id_code & 0x01f] = 0; - printf("\nFRU Device Description: %s Device ID: %d\n", desc, fru->keys.fru_device_id); - - switch (fru->device_type_modifier) { - case 0x00: - case 0x02: - sav_addr = intf->target_addr; - intf->target_addr = ((fru->keys.dev_access_addr << 1) - | (fru->keys.__reserved2 << 7)); - - if (intf->target_addr == IPMI_BMC_SLAVE_ADDR - && fru->keys.fru_device_id == 0) - printf(" (Builtin FRU device)\n"); - else - ipmi_fru_print(intf, fru->keys.fru_device_id); - - intf->target_addr = sav_addr; - break; - case 0x01: - ipmi_spd_print(intf, fru->keys.fru_device_id); - break; - default: - if (verbose) - printf(" Unsupported device 0x%02x " - "type 0x%02x with modifier 0x%02x\n", - fru->keys.fru_device_id, fru->device_type, - fru->device_type_modifier); - else - printf(" Unsupported device\n"); - } - - free (fru); + ipmi_fru_print(intf, fru); + free(fru); } ipmi_sdr_end(intf, itr);