build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id)
{
	t_ipmi_fru_bloc * p_first, * p_bloc, * p_new;
	struct ipmi_rs * rsp;
	struct ipmi_rq req;
	struct fru_header header;
	struct fru_multirec_header rec_hdr;
	uint8_t msg_data[4];
	uint32_t off;
	uint16_t i;

	/*
	* get COMMON Header format
	*/
	msg_data[0] = id;
	msg_data[1] = 0;
	msg_data[2] = 0;
	msg_data[3] = 8;

	memset(&req, 0, sizeof(req));
	req.msg.netfn = IPMI_NETFN_STORAGE;
	req.msg.cmd = GET_FRU_DATA;
	req.msg.data = msg_data;
	req.msg.data_len = 4;

	rsp = intf->sendrecv(intf, &req);

	if (!rsp) {
		lprintf(LOG_ERR, " Device not present (No Response)");
		return NULL;
	}

	if (rsp->ccode) {
		lprintf(LOG_ERR," Device not present (%s)",
				val2str(rsp->ccode, completion_code_vals));
		return NULL;
	}

	if (verbose > 1) {
		printbuf(rsp->data, rsp->data_len, "FRU DATA");
	}

	memcpy(&header, rsp->data + 1, 8);

	/* verify header checksum */
	if (ipmi_csum((uint8_t *)&header, 8)) {
		lprintf(LOG_ERR, " Bad header checksum");
		return NULL;
	}

	if (header.version != 1) {
		lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version);
		return NULL;
	}

	/******************************************
		Malloc and fill up the bloc contents
	*******************************************/

	// Common header
	p_first = malloc(sizeof(struct ipmi_fru_bloc));
	if (!p_first) {
		lprintf(LOG_ERR, "ipmitool: malloc failure");
		return NULL;
	}

	p_bloc = p_first;
	p_bloc->next = NULL;
	p_bloc->start= 0;
	p_bloc->size = fru->size;
	strcpy((char *)p_bloc->blocId, "Common Header Section");

	for (i = 0; i < 4; i++) {
		if (header.offsets[i]) {
			p_new = malloc(sizeof(struct ipmi_fru_bloc));
			if (!p_new) {
				lprintf(LOG_ERR, "ipmitool: malloc failure");
				free_fru_bloc(p_first);
				return NULL;
			}

			p_new->next = NULL;
			p_new->start = header.offsets[i] * 8;
			p_new->size = fru->size - p_new->start;

			strncpy((char *)p_new->blocId, section_id[i], sizeof(p_new->blocId));
			/* Make sure string is null terminated */
			p_new->blocId[sizeof(p_new->blocId)-1] = 0;

			p_bloc->next = p_new;
			p_bloc->size = p_new->start - p_bloc->start;
			p_bloc = p_new;
		}
	}

	// Multi
	if (header.offset.multi) {
		off = header.offset.multi * 8;

		do {
			/*
			 * check for odd offset for the case of fru devices
			 * accessed by words
			 */
			if (fru->access && (off & 1)) {
				lprintf(LOG_ERR, " Unaligned offset for a block: %d", off);
				/* increment offset */
				off++;
				break;
			}

			if (read_fru_area(intf, fru, id, off, 5,
					(uint8_t *) &rec_hdr) < 0) {
				break;
			}

			p_new = malloc(sizeof(struct ipmi_fru_bloc));
			if (!p_new) {
				lprintf(LOG_ERR, "ipmitool: malloc failure");
				free_fru_bloc(p_first);
				return NULL;
			}

			p_new->next = NULL;
			p_new->start = off;
			p_new->size = fru->size - p_new->start;
			sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i",
					rec_hdr.type);

			p_bloc->next = p_new;
			p_bloc->size = p_new->start - p_bloc->start;
			p_bloc = p_new;

			off += rec_hdr.len + sizeof(struct fru_multirec_header);

			/* verify record header */
			if (ipmi_csum((uint8_t *)&rec_hdr,
					sizeof(struct fru_multirec_header))) {
				/* can't reliably judge for the rest space */
				break;
			}
		} while (!(rec_hdr.format & 0x80) && (off < fru->size));

		lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off);

		if (fru->size > off) {
			// Bloc for remaining space
			p_new = malloc(sizeof(struct ipmi_fru_bloc));
			if (!p_new) {
				lprintf(LOG_ERR, "ipmitool: malloc failure");
				free_fru_bloc(p_first);
				return NULL;
			}

			p_new->next = NULL;
			p_new->start = off;
			p_new->size = fru->size - p_new->start;
			strcpy((char *)p_new->blocId, "Unused space");

			p_bloc->next = p_new;
			p_bloc->size = p_new->start - p_bloc->start;
		}
	}

	/* Dump blocs */
	for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) {
		lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++);
		lprintf(LOG_DEBUG ,"Bloc Id   : %s", p_bloc->blocId);
		lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start);
		lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size);
		lprintf(LOG_DEBUG ,"");
	}

	return p_first;
}
build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id)
{
	t_ipmi_fru_bloc * p_first, * p_bloc, * p_new;
	struct ipmi_rs * rsp;
	struct ipmi_rq req;
	struct fru_header header;
	struct fru_multirec_header rec_hdr;
	uint8_t msg_data[4];
	uint32_t off;
	uint16_t i;

	 
	msg_data[0] = id;
	msg_data[1] = 0;
	msg_data[2] = 0;
	msg_data[3] = 8;

	memset(&req, 0, sizeof(req));
	req.msg.netfn = IPMI_NETFN_STORAGE;
	req.msg.cmd = GET_FRU_DATA;
	req.msg.data = msg_data;
	req.msg.data_len = 4;

	rsp = intf->sendrecv(intf, &req);

	if (!rsp) {
		lprintf(LOG_ERR, " Device not present (No Response)");
		return NULL;
	}

	if (rsp->ccode) {
		lprintf(LOG_ERR," Device not present (%s)",
				val2str(rsp->ccode, completion_code_vals));
		return NULL;
	}

	if (verbose > 1) {
		printbuf(rsp->data, rsp->data_len, "FRU DATA");
	}

	memcpy(&header, rsp->data + 1, 8);

	 
	if (ipmi_csum((uint8_t *)&header, 8)) {
		lprintf(LOG_ERR, " Bad header checksum");
		return NULL;
	}

	if (header.version != 1) {
		lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version);
		return NULL;
	}

	 

	 
	p_first = malloc(sizeof(struct ipmi_fru_bloc));
	if (!p_first) {
		lprintf(LOG_ERR, "ipmitool: malloc failure");
		return NULL;
	}

	p_bloc = p_first;
	p_bloc->next = NULL;
	p_bloc->start= 0;
	p_bloc->size = fru->size;
	strcpy((char *)p_bloc->blocId, "Common Header Section");

	for (i = 0; i < 4; i++) {
		if (header.offsets[i]) {
			p_new = malloc(sizeof(struct ipmi_fru_bloc));
			if (!p_new) {
				lprintf(LOG_ERR, "ipmitool: malloc failure");
				free_fru_bloc(p_first);
				return NULL;
			}

			p_new->next = NULL;
			p_new->start = header.offsets[i] * 8;
			p_new->size = fru->size - p_new->start;

			strncpy((char *)p_new->blocId, section_id[i], sizeof(p_new->blocId));
			 
			p_new->blocId[sizeof(p_new->blocId)-1] = 0;

			p_bloc->next = p_new;
			p_bloc->size = p_new->start - p_bloc->start;
			p_bloc = p_new;
		}
	}

	 
	if (header.offset.multi) {
		off = header.offset.multi * 8;

		do {
			 
			if (fru->access && (off & 1)) {
				lprintf(LOG_ERR, " Unaligned offset for a block: %d", off);
				 
				off++;
				break;
			}

			if (read_fru_area(intf, fru, id, off, 5,
					(uint8_t *) &rec_hdr) < 0) {
				break;
			}

			p_new = malloc(sizeof(struct ipmi_fru_bloc));
			if (!p_new) {
				lprintf(LOG_ERR, "ipmitool: malloc failure");
				free_fru_bloc(p_first);
				return NULL;
			}

			p_new->next = NULL;
			p_new->start = off;
			p_new->size = fru->size - p_new->start;
			sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i",
					rec_hdr.type);

			p_bloc->next = p_new;
			p_bloc->size = p_new->start - p_bloc->start;
			p_bloc = p_new;

			off += rec_hdr.len + sizeof(struct fru_multirec_header);

			 
			if (ipmi_csum((uint8_t *)&rec_hdr,
					sizeof(struct fru_multirec_header))) {
				 
				break;
			}
		} while (!(rec_hdr.format & 0x80) && (off < fru->size));

		lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off);

		if (fru->size > off) {
			 
			p_new = malloc(sizeof(struct ipmi_fru_bloc));
			if (!p_new) {
				lprintf(LOG_ERR, "ipmitool: malloc failure");
				free_fru_bloc(p_first);
				return NULL;
			}

			p_new->next = NULL;
			p_new->start = off;
			p_new->size = fru->size - p_new->start;
			strcpy((char *)p_new->blocId, "Unused space");

			p_bloc->next = p_new;
			p_bloc->size = p_new->start - p_bloc->start;
		}
	}

	 
	for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) {
		lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++);
		lprintf(LOG_DEBUG ,"Bloc Id   : %s", p_bloc->blocId);
		lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start);
		lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size);
		lprintf(LOG_DEBUG ,"");
	}

	return p_first;
}