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