write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
					uint16_t soffset,  uint16_t doffset,
					uint16_t length, uint8_t *pFrubuf)
{
	uint16_t tmp, finish;
	struct ipmi_rs * rsp;
	struct ipmi_rq req;
	uint8_t msg_data[255+3];
	uint16_t writeLength;
	uint16_t found_bloc = 0;

	finish = doffset + length;        /* destination offset */
	if (finish > fru->size)
	{
		lprintf(LOG_ERROR, "Return error");
		return -1;
	}

	if (fru->access && ((doffset & 1) || (length & 1))) {
		lprintf(LOG_ERROR, "Odd offset or length specified");
		return -1;
	}

	t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id);
	t_ipmi_fru_bloc * saved_fru_bloc = fru_bloc;

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

	/* initialize request size only once */
	if (fru->max_write_size == 0) {
		uint16_t max_rq_size = ipmi_intf_get_max_request_data_size(intf);

		/* validate lower bound of the maximum request data size */
		if (max_rq_size <= 3) {
			lprintf(LOG_ERROR, "Maximum request size is too small to send "
					"a write request");
			return -1;
		}

		/*
		 * Write FRU Info command returns the number of written bytes in
		 * a single byte field.
		 */
		if (max_rq_size - 3 > 255) {
			/*  Limit the max write size with 255 bytes. */
			fru->max_write_size = 255;
		} else {
			/* subtract 1 byte for FRU ID an 2 bytes for offset */
			fru->max_write_size = max_rq_size - 3;
		}

		/* check word access */
		if (fru->access) {
			fru->max_write_size &= ~1;
		}
	}

	do {
		uint16_t end_bloc;
		uint8_t protected_bloc = 0;

		/* Write per bloc, try to find the end of a bloc*/
		while (fru_bloc && fru_bloc->start + fru_bloc->size <= doffset) {
			fru_bloc = fru_bloc->next;
			found_bloc++;
		}

		if (fru_bloc && fru_bloc->start + fru_bloc->size < finish) {
			end_bloc = fru_bloc->start + fru_bloc->size;
		} else {
			end_bloc = finish;
		}

		/* calculate write length */
		tmp = end_bloc - doffset;

		/* check that write length is more than maximum request size */
		if (tmp > fru->max_write_size) {
			writeLength = fru->max_write_size;
		} else {
			writeLength = tmp;
		}

		/* copy fru data */
		memcpy(&msg_data[3], pFrubuf + soffset, writeLength);

		/* check word access */
		if (fru->access) {
			writeLength &= ~1;
		}

		tmp = doffset;
		if (fru->access) {
			tmp >>= 1;
		}

		msg_data[0] = id;
		msg_data[1] = (uint8_t)tmp;
		msg_data[2] = (uint8_t)(tmp >> 8);
		req.msg.data_len = writeLength + 3;

		if(fru_bloc) {
			lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)",
					writeLength, found_bloc, fru_bloc->blocId);
		} else {
			lprintf(LOG_INFO,"Writing %d bytes", writeLength);
		}

		rsp = intf->sendrecv(intf, &req);
		if (!rsp) {
			break;
		}

		if (fru_cc_rq2big(rsp->ccode)) {
			if (fru->max_write_size > FRU_AREA_MAXIMUM_BLOCK_SZ) {
				fru->max_write_size -= FRU_BLOCK_SZ;
				lprintf(LOG_INFO, "Retrying FRU write with request size %d",
						fru->max_write_size);
				continue;
			}
		} else if (rsp->ccode == IPMI_CC_FRU_WRITE_PROTECTED_OFFSET) {
			rsp->ccode = IPMI_CC_OK;
			// Write protected section
			protected_bloc = 1;
		}

		if (rsp->ccode)
			break;

		if (protected_bloc == 0) {
			// Write OK, bloc not protected, continue
			lprintf(LOG_INFO,"Wrote %d bytes", writeLength);
			doffset += writeLength;
			soffset += writeLength;
		} else {
			if(fru_bloc) {
				// Bloc protected, advise user and jump over protected bloc
				lprintf(LOG_INFO,
						"Bloc [%s] protected at offset: %i (size %i bytes)",
						fru_bloc->blocId, fru_bloc->start, fru_bloc->size);
				lprintf(LOG_INFO,"Jumping over this bloc");
			} else {
				lprintf(LOG_INFO,
						"Remaining FRU is protected following offset: %i",
						doffset);
			}
			soffset += end_bloc - doffset;
			doffset = end_bloc;
		}
	} while (doffset < finish);

	if (saved_fru_bloc) {
		free_fru_bloc(saved_fru_bloc);
	}

	return doffset >= finish;
}