xref: /titanic_51/usr/src/lib/libfru/libfru/PayloadReader.cc (revision 821a83dbe7cba700cd57da95bf981850118f369e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*821a83dbSps154918  * Common Development and Distribution License (the "License").
6*821a83dbSps154918  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*821a83dbSps154918  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2334e5f34eSkmohan  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "PayloadReader.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #define	ITER_CONT_BYTE_LEN 4
347c478bd9Sstevel@tonic-gate #define	IS_ITERATED(pathDef) \
357c478bd9Sstevel@tonic-gate (pathDef->def->iterationType != FRU_NOT_ITERATED)
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate // functions to place bit data properly.
387c478bd9Sstevel@tonic-gate static fru_errno_t
397c478bd9Sstevel@tonic-gate writeBits(uint64_t bitData, size_t bitLength,
407c478bd9Sstevel@tonic-gate 	uint8_t *data, size_t dataLength, size_t bitOffset)
417c478bd9Sstevel@tonic-gate {
427c478bd9Sstevel@tonic-gate 	if ((bitLength > 64) &&
437c478bd9Sstevel@tonic-gate 		(bitOffset > 64) &&
447c478bd9Sstevel@tonic-gate 		(dataLength > 8) &&
457c478bd9Sstevel@tonic-gate 		(bitOffset > (dataLength * 8)))
467c478bd9Sstevel@tonic-gate 		return (FRU_FAILURE);
477c478bd9Sstevel@tonic-gate 	// move the bit data into place
487c478bd9Sstevel@tonic-gate 	bitData = (bitData << (64-bitLength));
497c478bd9Sstevel@tonic-gate 	bitData = (bitData >> bitOffset);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 	// create a mask to clear the old data.
527c478bd9Sstevel@tonic-gate 	uint64_t mask = 0;
537c478bd9Sstevel@tonic-gate 	for (size_t i = 0; i < bitLength; i++) {
547c478bd9Sstevel@tonic-gate 		mask = ((mask << 1) + 1);
557c478bd9Sstevel@tonic-gate 	}
567c478bd9Sstevel@tonic-gate 	mask = (mask << (64-bitLength));
577c478bd9Sstevel@tonic-gate 	mask = (mask >> bitOffset);
5834e5f34eSkmohan 	mask = (mask ^ 0xFFFFFFFFFFFFFFFFULL);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	// get the data out of the byte array.
617c478bd9Sstevel@tonic-gate 	uint64_t rd = 0;
627c478bd9Sstevel@tonic-gate 	memcpy((void *)&rd, (void *)data, dataLength);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	// clear the old data
657c478bd9Sstevel@tonic-gate 	rd = (rd & mask);
667c478bd9Sstevel@tonic-gate 	// put in the new data.
677c478bd9Sstevel@tonic-gate 	rd = (rd | bitData);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	// write the data back to the buffer.
707c478bd9Sstevel@tonic-gate 	memcpy((void *)data, (void *)&rd, dataLength);
717c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static fru_errno_t
757c478bd9Sstevel@tonic-gate readBits(size_t bitLength, uint8_t *data,
767c478bd9Sstevel@tonic-gate 	size_t dataLength, int bitOffset, uint64_t *ret)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	if ((bitLength > 64) ||
797c478bd9Sstevel@tonic-gate 		(bitLength < 0) ||
807c478bd9Sstevel@tonic-gate 		(bitOffset > 64) ||
817c478bd9Sstevel@tonic-gate 		(dataLength > 8) ||
827c478bd9Sstevel@tonic-gate 		(bitOffset > (dataLength * 8)))
837c478bd9Sstevel@tonic-gate 		return (FRU_FAILURE);
847c478bd9Sstevel@tonic-gate 	// get the data out of the byte array.
857c478bd9Sstevel@tonic-gate 	uint64_t rc = 0;
867c478bd9Sstevel@tonic-gate 	memcpy((void *)&rc, (void *)data, dataLength);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	rc = (rc << bitOffset);
897c478bd9Sstevel@tonic-gate 	rc = (rc >> (64 - bitLength));
907c478bd9Sstevel@tonic-gate 	*ret = rc;
917c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate // ===========================================================================
957c478bd9Sstevel@tonic-gate // caller is to be sure elemDef is contained by recDef.
967c478bd9Sstevel@tonic-gate int
977c478bd9Sstevel@tonic-gate PayloadReader::getOffsetIntoRecord(fru_regdef_t *recDef,
987c478bd9Sstevel@tonic-gate 				fru_regdef_t *elemDef)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	int rc = 0;
1017c478bd9Sstevel@tonic-gate 	for (int i = 0; i < recDef->enumCount; i++) {
1027c478bd9Sstevel@tonic-gate 		if (strcmp(recDef->enumTable[i].text, elemDef->name) == 0)
1037c478bd9Sstevel@tonic-gate 			return (rc);
1047c478bd9Sstevel@tonic-gate 		const fru_regdef_t *tmpDef = fru_reg_lookup_def_by_name(
1057c478bd9Sstevel@tonic-gate 					(char *)recDef->enumTable[i].text);
1067c478bd9Sstevel@tonic-gate 		rc += tmpDef->payloadLen;
1077c478bd9Sstevel@tonic-gate 	}
108*821a83dbSps154918 	return(0);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate // ===========================================================================
1127c478bd9Sstevel@tonic-gate // return -1 on error.
1137c478bd9Sstevel@tonic-gate int
1147c478bd9Sstevel@tonic-gate PayloadReader::calcOffset(int iterType,
1157c478bd9Sstevel@tonic-gate 			uint8_t head, uint8_t tail,
1167c478bd9Sstevel@tonic-gate 			uint8_t iterThere, uint8_t iterPoss,
1177c478bd9Sstevel@tonic-gate 			size_t length, int index,
1187c478bd9Sstevel@tonic-gate 			fru_errno_t *err)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	*err = FRU_SUCCESS;
1217c478bd9Sstevel@tonic-gate 	switch (iterType) {
1227c478bd9Sstevel@tonic-gate 		case FRU_FIFO:
1237c478bd9Sstevel@tonic-gate 		case FRU_Linear:
1247c478bd9Sstevel@tonic-gate 		{
1257c478bd9Sstevel@tonic-gate 			if (index == PathDef::lastIteration)
1267c478bd9Sstevel@tonic-gate 				return (length * tail);
1277c478bd9Sstevel@tonic-gate 			return (length * index);
1287c478bd9Sstevel@tonic-gate 		break;
1297c478bd9Sstevel@tonic-gate 		}
1307c478bd9Sstevel@tonic-gate 		case FRU_Circular:
1317c478bd9Sstevel@tonic-gate 		case FRU_LIFO:
1327c478bd9Sstevel@tonic-gate 		{
1337c478bd9Sstevel@tonic-gate 			if (index == PathDef::lastIteration) {
1347c478bd9Sstevel@tonic-gate 				if (iterType == FRU_LIFO)
1357c478bd9Sstevel@tonic-gate 					return (length * head);
1367c478bd9Sstevel@tonic-gate 				return (length * tail);
1377c478bd9Sstevel@tonic-gate 			}
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 			// For reading they are oposite.
1407c478bd9Sstevel@tonic-gate 			if (iterType == FRU_Circular) {
1417c478bd9Sstevel@tonic-gate 				return (length * ((head + index) % iterPoss));
1427c478bd9Sstevel@tonic-gate 			} else {
1437c478bd9Sstevel@tonic-gate 				int abs = tail - index;
1447c478bd9Sstevel@tonic-gate 				if (abs < 0)
1457c478bd9Sstevel@tonic-gate 					// abs is negative here
1467c478bd9Sstevel@tonic-gate 					abs = iterPoss + abs;
1477c478bd9Sstevel@tonic-gate 				return (length * abs);
1487c478bd9Sstevel@tonic-gate 			}
1497c478bd9Sstevel@tonic-gate 		break;
1507c478bd9Sstevel@tonic-gate 		}
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 	*err = FRU_FAILURE;
1537c478bd9Sstevel@tonic-gate 	return (-1);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate // ===========================================================================
1577c478bd9Sstevel@tonic-gate // return -1 on error.
1587c478bd9Sstevel@tonic-gate int
1597c478bd9Sstevel@tonic-gate PayloadReader::getIterationOffset(uint8_t *iter, int iterLen,
1607c478bd9Sstevel@tonic-gate 				PathDef *path, int *rcIterThere,
1617c478bd9Sstevel@tonic-gate 				fru_errno_t *err,
1627c478bd9Sstevel@tonic-gate 				int onlyFindingIterThereFlag)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	int rc = 0;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	// read the iteration control bytes first because we may ONLY need
1677c478bd9Sstevel@tonic-gate 	// them.
1687c478bd9Sstevel@tonic-gate 	uint8_t head = iter[0];
1697c478bd9Sstevel@tonic-gate 	uint8_t tail = iter[1];
1707c478bd9Sstevel@tonic-gate 	uint8_t iterThere = iter[2];
1717c478bd9Sstevel@tonic-gate 	uint8_t iterPoss = iter[3];
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	// the '+' symbol on anything is an error here
1747c478bd9Sstevel@tonic-gate 	if (path->iterIndex == PathDef::addIteration) {
1757c478bd9Sstevel@tonic-gate 		*err = FRU_INVALPATH;
1767c478bd9Sstevel@tonic-gate 		return (-1);
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	// check assumptions for next calls.
1807c478bd9Sstevel@tonic-gate 	if (iterPoss != path->def->iterationCount) {
1817c478bd9Sstevel@tonic-gate 		*err = FRU_DATACORRUPT;
1827c478bd9Sstevel@tonic-gate 		return (-1);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	if (onlyFindingIterThereFlag == ITER_THERE_ONLY) {
1867c478bd9Sstevel@tonic-gate 		if (rcIterThere != NULL) {
1877c478bd9Sstevel@tonic-gate 			*rcIterThere = iterThere;
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 		*err = FRU_SUCCESS;
1907c478bd9Sstevel@tonic-gate 		return (ITER_CONT_BYTE_LEN);
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if ((path->iterIndex != PathDef::addIteration) &&
1947c478bd9Sstevel@tonic-gate 		(path->iterIndex != PathDef::lastIteration) &&
1957c478bd9Sstevel@tonic-gate 		(path->iterIndex >= iterThere)) {
1967c478bd9Sstevel@tonic-gate 		*err = FRU_DATANOTFOUND;
1977c478bd9Sstevel@tonic-gate 		return (-1);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	// don't forget to skip the iteration control bytes!!!
2017c478bd9Sstevel@tonic-gate 	int length = ((path->def->payloadLen - ITER_CONT_BYTE_LEN)
2027c478bd9Sstevel@tonic-gate 			/path->def->iterationCount);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	rc = calcOffset(path->def->iterationType,
2057c478bd9Sstevel@tonic-gate 			head, tail, iterThere, iterPoss,
2067c478bd9Sstevel@tonic-gate 			length, path->iterIndex, err);
2077c478bd9Sstevel@tonic-gate 	if (rc == -1) {
2087c478bd9Sstevel@tonic-gate 		// error set by calcOffset
2097c478bd9Sstevel@tonic-gate 		return (-1);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	*err = FRU_SUCCESS;
2137c478bd9Sstevel@tonic-gate 	return (ITER_CONT_BYTE_LEN + rc);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate // ===========================================================================
2177c478bd9Sstevel@tonic-gate // Iff onlyFindingIterThereFlag is set data is ignored and dataLen will be set
2187c478bd9Sstevel@tonic-gate // to the number of iterations which are actually in the seeprom.
2197c478bd9Sstevel@tonic-gate fru_errno_t
2207c478bd9Sstevel@tonic-gate PayloadReader::readRecurse(PathDef *path,
2217c478bd9Sstevel@tonic-gate 			uint8_t *cur, size_t curLen,
2227c478bd9Sstevel@tonic-gate 			void **data, size_t *dataLen,
2237c478bd9Sstevel@tonic-gate 			int onlyFindingIterThereFlag)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	fru_errno_t rc = FRU_SUCCESS;
2267c478bd9Sstevel@tonic-gate 	size_t calc_data_len = 0;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	if (path->next == NULL) {
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		// alway go ahead and do the iterated thing.  If we are not a
2317c478bd9Sstevel@tonic-gate 		// field then the onlyFindingIterThereFlag should be set.
2327c478bd9Sstevel@tonic-gate 		// Check this afterward.
2337c478bd9Sstevel@tonic-gate 		int offset = 0;
2347c478bd9Sstevel@tonic-gate 		int iterThere = 0;
2357c478bd9Sstevel@tonic-gate 		// zzz altering the length things again...
2367c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(path)) {
2377c478bd9Sstevel@tonic-gate 			// we are iterated.
2387c478bd9Sstevel@tonic-gate 			calc_data_len = (path->def->payloadLen
2397c478bd9Sstevel@tonic-gate 						-ITER_CONT_BYTE_LEN)/
2407c478bd9Sstevel@tonic-gate 					path->def->iterationCount;
2417c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets for bit iterations...
2427c478bd9Sstevel@tonic-gate 			offset = getIterationOffset(cur, curLen, path,
2437c478bd9Sstevel@tonic-gate 				&iterThere, &rc,
2447c478bd9Sstevel@tonic-gate 				onlyFindingIterThereFlag);
2457c478bd9Sstevel@tonic-gate 			if (offset == -1)
2467c478bd9Sstevel@tonic-gate 				return (rc);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 			// done
2497c478bd9Sstevel@tonic-gate 			if (onlyFindingIterThereFlag) {
2507c478bd9Sstevel@tonic-gate 				*dataLen = iterThere;
2517c478bd9Sstevel@tonic-gate 				return (FRU_SUCCESS);
2527c478bd9Sstevel@tonic-gate 			}
2537c478bd9Sstevel@tonic-gate 		} else {
2547c478bd9Sstevel@tonic-gate 			// done but this thing was not an iteration!!!
2557c478bd9Sstevel@tonic-gate 			if (onlyFindingIterThereFlag) {
2567c478bd9Sstevel@tonic-gate 				return (FRU_INVALPATH);
2577c478bd9Sstevel@tonic-gate 			}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 			calc_data_len = path->def->payloadLen;
2607c478bd9Sstevel@tonic-gate 			offset = 0;
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 		// end zzz
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		// now make sure we have a field.
2657c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Record) {
2667c478bd9Sstevel@tonic-gate 			return (FRU_NOTFIELD);
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 		// allocate and copy.
2707c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Binary) {
2717c478bd9Sstevel@tonic-gate 			uint64_t *eData = (uint64_t *)malloc(sizeof (*eData));
2727c478bd9Sstevel@tonic-gate 			if (eData == NULL) {
2737c478bd9Sstevel@tonic-gate 				return (FRU_FAILURE);
2747c478bd9Sstevel@tonic-gate 			}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			int bitLength = path->def->dataLength;
2777c478bd9Sstevel@tonic-gate 			// iterated bit field adjust acordingly.
2787c478bd9Sstevel@tonic-gate 			if (IS_ITERATED(path)) {
2797c478bd9Sstevel@tonic-gate 				bitLength = (bitLength-(ITER_CONT_BYTE_LEN*8))/
2807c478bd9Sstevel@tonic-gate 					path->def->iterationCount;
2817c478bd9Sstevel@tonic-gate 			}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 			rc = readBits(bitLength, &(cur[offset]),
2847c478bd9Sstevel@tonic-gate 					calc_data_len, 0, eData);
2857c478bd9Sstevel@tonic-gate 			if (rc != FRU_SUCCESS) {
2867c478bd9Sstevel@tonic-gate 				free(eData);
2877c478bd9Sstevel@tonic-gate 				return (rc);
2887c478bd9Sstevel@tonic-gate 			}
2897c478bd9Sstevel@tonic-gate 			*data = (void *)eData;
2907c478bd9Sstevel@tonic-gate 			*dataLen = sizeof (*eData);
2917c478bd9Sstevel@tonic-gate 		} else if (path->def->dataType == FDTYPE_Enumeration) {
2927c478bd9Sstevel@tonic-gate 			unsigned char *eData
2937c478bd9Sstevel@tonic-gate 				= (unsigned char *)malloc(sizeof (uint64_t));
2947c478bd9Sstevel@tonic-gate 			if (eData == NULL) {
2957c478bd9Sstevel@tonic-gate 				return (FRU_FAILURE);
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 			/* copy the correct number of bytes to eData */
2987c478bd9Sstevel@tonic-gate 			memset(eData, 0x00, sizeof (uint64_t));
2997c478bd9Sstevel@tonic-gate 			memcpy(&(eData[(sizeof (uint64_t) - (calc_data_len))]),
3007c478bd9Sstevel@tonic-gate 				&(cur[offset]),
3017c478bd9Sstevel@tonic-gate 				(calc_data_len));
3027c478bd9Sstevel@tonic-gate 			*data = (void*)eData;
3037c478bd9Sstevel@tonic-gate 			*dataLen = sizeof (uint64_t);
3047c478bd9Sstevel@tonic-gate 		} else {
3057c478bd9Sstevel@tonic-gate 			void *rc_data = malloc(calc_data_len);
3067c478bd9Sstevel@tonic-gate 			if (rc_data == NULL) {
3077c478bd9Sstevel@tonic-gate 				return (FRU_FAILURE);
3087c478bd9Sstevel@tonic-gate 			}
3097c478bd9Sstevel@tonic-gate 			memcpy(rc_data, &(cur[offset]), calc_data_len);
3107c478bd9Sstevel@tonic-gate 			*data = rc_data;
3117c478bd9Sstevel@tonic-gate 			*dataLen = calc_data_len;
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	// At this point we know the entry is some sort of record.
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	int newOffset = 0, newLength = 0;
3207c478bd9Sstevel@tonic-gate 	if (IS_ITERATED(path)) {
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets for bit iterations...
3237c478bd9Sstevel@tonic-gate 		newOffset = getIterationOffset(cur, curLen,
3247c478bd9Sstevel@tonic-gate 				path, NULL, &rc, NORMAL_READ);
3257c478bd9Sstevel@tonic-gate 		if (newOffset == -1)
3267c478bd9Sstevel@tonic-gate 			return (rc);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	newOffset += getOffsetIntoRecord(path->def, path->next->def);
3307c478bd9Sstevel@tonic-gate 	newLength = path->next->def->payloadLen;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	return (readRecurse(path->next, &(cur[newOffset]), newLength,
3337c478bd9Sstevel@tonic-gate 		data, dataLen, onlyFindingIterThereFlag));
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate // ===========================================================================
3377c478bd9Sstevel@tonic-gate // will send the data back in (data,dataLen)
3387c478bd9Sstevel@tonic-gate fru_errno_t
3397c478bd9Sstevel@tonic-gate PayloadReader::readData(PathDef *path, Ancestor *curDef,
3407c478bd9Sstevel@tonic-gate 			int instWICur,
3417c478bd9Sstevel@tonic-gate 			uint8_t *payload, size_t payloadLen,
3427c478bd9Sstevel@tonic-gate 			void **data, size_t *dataLen)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	int offset = curDef->getInstOffset(instWICur);
3457c478bd9Sstevel@tonic-gate 	return (readRecurse(path, &(payload[offset]), payloadLen-offset,
3467c478bd9Sstevel@tonic-gate 		data, dataLen, NORMAL_READ));
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate // ===========================================================================
3507c478bd9Sstevel@tonic-gate fru_errno_t
3517c478bd9Sstevel@tonic-gate PayloadReader::findIterThere(PathDef *path, Ancestor *curDef,
3527c478bd9Sstevel@tonic-gate 				int instWICur,
3537c478bd9Sstevel@tonic-gate 				uint8_t *payload, size_t payloadLen,
3547c478bd9Sstevel@tonic-gate 				int *numThere)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	int offset = curDef->getInstOffset(instWICur);
3577c478bd9Sstevel@tonic-gate 	size_t tmp_num = 0;
3587c478bd9Sstevel@tonic-gate 	fru_errno_t err = readRecurse(path, &(payload[offset]),
3597c478bd9Sstevel@tonic-gate 		payloadLen-offset, NULL, &tmp_num, ITER_THERE_ONLY);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if (err == FRU_SUCCESS) {
3627c478bd9Sstevel@tonic-gate 		int tmp_num_there = (int)tmp_num;
3637c478bd9Sstevel@tonic-gate 		if (tmp_num_there != tmp_num) {
3647c478bd9Sstevel@tonic-gate 			return (FRU_FAILURE);
3657c478bd9Sstevel@tonic-gate 		}
3667c478bd9Sstevel@tonic-gate 		*numThere = tmp_num_there;
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	return (err);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate static fru_errno_t
3727c478bd9Sstevel@tonic-gate update_iter_cont_bytes(PathDef *path, uint8_t *cur, size_t curLen)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	// update the iteration control information
3757c478bd9Sstevel@tonic-gate 	uint8_t *head = &(cur[0]);
3767c478bd9Sstevel@tonic-gate 	uint8_t *tail = &(cur[1]);
3777c478bd9Sstevel@tonic-gate 	uint8_t *numThere = &(cur[2]);
3787c478bd9Sstevel@tonic-gate 	// This never changes.
3797c478bd9Sstevel@tonic-gate 	uint8_t numPoss = cur[3];
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (numPoss != path->def->iterationCount) {
3827c478bd9Sstevel@tonic-gate 		return (FRU_DATACORRUPT);
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	// Remember that when the iteration is added the head and the tail both
3867c478bd9Sstevel@tonic-gate 	// equal 0 (ie point to 0).  So if we are empty when we are updating
3877c478bd9Sstevel@tonic-gate 	// then we don't have to alter the head or tail values.  We simply add
3887c478bd9Sstevel@tonic-gate 	// one to the numThere.
3897c478bd9Sstevel@tonic-gate 	if (*numThere != 0) {
3907c478bd9Sstevel@tonic-gate 		switch (path->def->iterationType) {
3917c478bd9Sstevel@tonic-gate 			case FRU_Linear:
3927c478bd9Sstevel@tonic-gate 				// this will flag an error when Linear can't
3937c478bd9Sstevel@tonic-gate 				// hold anymore.
3947c478bd9Sstevel@tonic-gate 				if ((*tail + 1) == numPoss)
3957c478bd9Sstevel@tonic-gate 					return (FRU_ITERFULL);
3967c478bd9Sstevel@tonic-gate 			/* Fall through */
3977c478bd9Sstevel@tonic-gate 			case FRU_FIFO:
3987c478bd9Sstevel@tonic-gate 				// if we are not at the end move the tail.
3997c478bd9Sstevel@tonic-gate 				if (*tail != (numPoss-1))
4007c478bd9Sstevel@tonic-gate 					*tail = *tail+1;
4017c478bd9Sstevel@tonic-gate 			break;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 			case FRU_Circular:
4047c478bd9Sstevel@tonic-gate 			case FRU_LIFO:
4057c478bd9Sstevel@tonic-gate 				// this is the same except LIFO is read
4067c478bd9Sstevel@tonic-gate 				// BACKWARDS
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 				// move the tail.
4097c478bd9Sstevel@tonic-gate 				*tail = *tail + 1;
4107c478bd9Sstevel@tonic-gate 				// if the tail hits the end wrap around.
4117c478bd9Sstevel@tonic-gate 				if (*tail == numPoss)
4127c478bd9Sstevel@tonic-gate 					*tail = 0;
4137c478bd9Sstevel@tonic-gate 				// if tail catches head move the head.
4147c478bd9Sstevel@tonic-gate 				if (*tail == *head) {
4157c478bd9Sstevel@tonic-gate 					// if head hits the end wrap around.
4167c478bd9Sstevel@tonic-gate 					if (++(*head) == numPoss)
4177c478bd9Sstevel@tonic-gate 						*head = 0;
4187c478bd9Sstevel@tonic-gate 				}
4197c478bd9Sstevel@tonic-gate 			break;
4207c478bd9Sstevel@tonic-gate 		}
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 	if ((*numThere) < numPoss) {
4237c478bd9Sstevel@tonic-gate 		// add one IFF we are not full
4247c478bd9Sstevel@tonic-gate 		*numThere = *numThere + 1;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate // ===========================================================================
4317c478bd9Sstevel@tonic-gate fru_errno_t
4327c478bd9Sstevel@tonic-gate PayloadReader::updateRecurse(PathDef *path,
4337c478bd9Sstevel@tonic-gate 				uint8_t *cur, size_t curLen,
4347c478bd9Sstevel@tonic-gate 				void *data, size_t dataLen)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	fru_errno_t rc = FRU_SUCCESS;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (path->next == NULL) {
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		// Delay checking for Records until after this which will
4417c478bd9Sstevel@tonic-gate 		// allow for [+] notation for Iterated Records.
4427c478bd9Sstevel@tonic-gate 		// if this is updating an iteration AND we are adding one...
4437c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(path) &&
4447c478bd9Sstevel@tonic-gate 			(path->iterIndex == PathDef::addIteration)) {
4457c478bd9Sstevel@tonic-gate 			return (update_iter_cont_bytes(path, cur, curLen));
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Record) {
4497c478bd9Sstevel@tonic-gate 			return (FRU_NOTFIELD);
4507c478bd9Sstevel@tonic-gate 		}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		int offset = 0;
4537c478bd9Sstevel@tonic-gate 		int calcLen = 0;
4547c478bd9Sstevel@tonic-gate 		int dummy = 0;
4557c478bd9Sstevel@tonic-gate 		// zzz altering the length things again...
4567c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(path)) {
4577c478bd9Sstevel@tonic-gate 			// we are iterated.
4587c478bd9Sstevel@tonic-gate 			calcLen = (path->def->payloadLen-ITER_CONT_BYTE_LEN)/
4597c478bd9Sstevel@tonic-gate 				path->def->iterationCount;
4607c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets
4617c478bd9Sstevel@tonic-gate 			offset = getIterationOffset(cur, curLen,
4627c478bd9Sstevel@tonic-gate 				path, &dummy, &rc, NORMAL_READ);
4637c478bd9Sstevel@tonic-gate 			if (offset == -1)
4647c478bd9Sstevel@tonic-gate 				return (rc);
4657c478bd9Sstevel@tonic-gate 		} else {
4667c478bd9Sstevel@tonic-gate 			calcLen = path->def->payloadLen;
4677c478bd9Sstevel@tonic-gate 			offset = 0;
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 		// end zzz
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		// once again convert enums for the user again.
4727c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Binary) {
4737c478bd9Sstevel@tonic-gate 			int bitLength = path->def->dataLength;
4747c478bd9Sstevel@tonic-gate 			// iterated bit field adjust acordingly.
4757c478bd9Sstevel@tonic-gate 			if (path->def->iterationType != FRU_NOT_ITERATED) {
4767c478bd9Sstevel@tonic-gate 				bitLength = (bitLength - 32)/
4777c478bd9Sstevel@tonic-gate 					path->def->iterationCount;
4787c478bd9Sstevel@tonic-gate 			}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 			rc = writeBits (*(uint64_t *)data, bitLength,
4817c478bd9Sstevel@tonic-gate 					&(cur[offset]), calcLen, 0);
4827c478bd9Sstevel@tonic-gate 			if (rc != FRU_SUCCESS)
4837c478bd9Sstevel@tonic-gate 				return (rc);
4847c478bd9Sstevel@tonic-gate 		} else if (path->def->dataType == FDTYPE_Enumeration) {
4857c478bd9Sstevel@tonic-gate 			unsigned char *tmp = (unsigned char *)data;
4867c478bd9Sstevel@tonic-gate 			memcpy(&(cur[offset]),
4877c478bd9Sstevel@tonic-gate 				&(tmp[(sizeof (uint64_t) - (calcLen))]),
4887c478bd9Sstevel@tonic-gate 				calcLen);
4897c478bd9Sstevel@tonic-gate 		} else {
4907c478bd9Sstevel@tonic-gate 			// copy into and return.
4917c478bd9Sstevel@tonic-gate 			memcpy(&(cur[offset]), data, dataLen);
4927c478bd9Sstevel@tonic-gate 		}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	int newOffset = 0, newLength = 0;
4987c478bd9Sstevel@tonic-gate 	int dummy = 0;
4997c478bd9Sstevel@tonic-gate 	if (path->def->iterationType != FRU_NOT_ITERATED) {
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets
5027c478bd9Sstevel@tonic-gate 		newOffset = getIterationOffset(cur, curLen, path,
5037c478bd9Sstevel@tonic-gate 					&dummy, &rc, NORMAL_READ);
5047c478bd9Sstevel@tonic-gate 		if (newOffset == -1)
5057c478bd9Sstevel@tonic-gate 			return (rc);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 	newOffset += getOffsetIntoRecord(path->def, path->next->def);
5087c478bd9Sstevel@tonic-gate 	newLength = path->next->def->payloadLen;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	return (updateRecurse(path->next, &(cur[newOffset]), newLength,
5117c478bd9Sstevel@tonic-gate 		data, dataLen));
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate // ===========================================================================
5157c478bd9Sstevel@tonic-gate // will update the data in payload which can then be written back.
5167c478bd9Sstevel@tonic-gate fru_errno_t
5177c478bd9Sstevel@tonic-gate PayloadReader::updateData(PathDef *path, Ancestor *ancestorDef,
5187c478bd9Sstevel@tonic-gate 			int instWICur,
5197c478bd9Sstevel@tonic-gate 			uint8_t *payload, size_t payloadLen,
5207c478bd9Sstevel@tonic-gate 			void *data, size_t dataLen)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate 	// verify the user data first before doing any major work.
5237c478bd9Sstevel@tonic-gate 	int calcLen = 0;
5247c478bd9Sstevel@tonic-gate 	PathDef *prev = path;
5257c478bd9Sstevel@tonic-gate 	PathDef *cur = path;
5267c478bd9Sstevel@tonic-gate 	while (cur != NULL) {
5277c478bd9Sstevel@tonic-gate 		prev = cur;
5287c478bd9Sstevel@tonic-gate 		cur = cur->next;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	// unless we are updateing with [+] symbol
5327c478bd9Sstevel@tonic-gate 	// (which means we don't have any data length at all.)
5337c478bd9Sstevel@tonic-gate 	if (prev->iterIndex != PathDef::addIteration) {
5347c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(prev)) {
5357c478bd9Sstevel@tonic-gate 			calcLen = (prev->def->payloadLen-ITER_CONT_BYTE_LEN)/
5367c478bd9Sstevel@tonic-gate 				prev->def->iterationCount;
5377c478bd9Sstevel@tonic-gate 		} else {
5387c478bd9Sstevel@tonic-gate 				calcLen = prev->def->payloadLen;
5397c478bd9Sstevel@tonic-gate 		}
5407c478bd9Sstevel@tonic-gate 		// the sizeof the data for Binary or Enumeration MUST
5417c478bd9Sstevel@tonic-gate 		// be uint64_t
5427c478bd9Sstevel@tonic-gate 		if ((prev->def->dataType == FDTYPE_Enumeration) ||
5437c478bd9Sstevel@tonic-gate 			(prev->def->dataType == FDTYPE_Binary)) {
5447c478bd9Sstevel@tonic-gate 			if (dataLen != sizeof (uint64_t))
5457c478bd9Sstevel@tonic-gate 				return (FRU_INVALDATASIZE);
5467c478bd9Sstevel@tonic-gate 		// all others must be shorter than the space available.
5477c478bd9Sstevel@tonic-gate 		} else {
5487c478bd9Sstevel@tonic-gate 			if (dataLen > calcLen)
5497c478bd9Sstevel@tonic-gate 				return (FRU_INVALDATASIZE);
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	int offset = ancestorDef->getInstOffset(instWICur);
5547c478bd9Sstevel@tonic-gate 	return (updateRecurse(path, &(payload[offset]), payloadLen-offset,
5557c478bd9Sstevel@tonic-gate 		data, dataLen));
5567c478bd9Sstevel@tonic-gate }
557