xref: /illumos-gate/usr/src/lib/libipmi/common/ipmi_util.c (revision 3ce5372277f4657ad0e52d36c979527c4ca22de2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <libipmi.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdarg.h>
33 
34 #include "ipmi_impl.h"
35 
36 /*
37  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
38  * u, which must be an unsigned integer.
39  */
40 #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
41 
42 /*
43  * Error handling
44  */
45 int
46 ipmi_set_error(ipmi_handle_t *ihp, int error, const char *fmt, ...)
47 {
48 	va_list ap;
49 
50 	va_start(ap, fmt);
51 
52 	ihp->ih_errno = error;
53 	if (fmt == NULL)
54 		ihp->ih_errmsg[0] = '\0';
55 	else
56 		(void) vsnprintf(ihp->ih_errmsg, sizeof (ihp->ih_errmsg),
57 		    fmt, ap);
58 	va_end(ap);
59 
60 	return (-1);
61 }
62 
63 int
64 ipmi_errno(ipmi_handle_t *ihp)
65 {
66 	return (ihp->ih_errno);
67 }
68 
69 /* ARGSUSED */
70 const char *
71 ipmi_errmsg(ipmi_handle_t *ihp)
72 {
73 	int i;
74 	const char *str;
75 
76 	str = NULL;
77 	for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) {
78 		if (ipmi_errno_table[i].int_value == ihp->ih_errno) {
79 			str = ipmi_errno_table[i].int_name;
80 			break;
81 		}
82 	}
83 
84 	if (str == NULL && (str = strerror(ihp->ih_errno)) == NULL)
85 		str = "unknown failure";
86 
87 	if (ihp->ih_errmsg[0] == '\0')
88 		return (str);
89 
90 	(void) snprintf(ihp->ih_errbuf, sizeof (ihp->ih_errbuf),
91 	    "%s: %s", str, ihp->ih_errmsg);
92 	return (ihp->ih_errbuf);
93 }
94 
95 /*
96  * Memory allocation
97  */
98 void *
99 ipmi_alloc(ipmi_handle_t *ihp, size_t size)
100 {
101 	void *ptr;
102 
103 	if ((ptr = malloc(size)) == NULL)
104 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
105 
106 	return (ptr);
107 }
108 
109 void *
110 ipmi_zalloc(ipmi_handle_t *ihp, size_t size)
111 {
112 	void *ptr;
113 
114 	if ((ptr = calloc(size, 1)) == NULL)
115 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
116 
117 	return (ptr);
118 }
119 
120 char *
121 ipmi_strdup(ipmi_handle_t *ihp, const char *str)
122 {
123 	char *ptr;
124 
125 	if ((ptr = strdup(str)) == NULL)
126 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
127 
128 	return (ptr);
129 }
130 
131 /* ARGSUSED */
132 void
133 ipmi_free(ipmi_handle_t *ihp, void *ptr)
134 {
135 	free(ptr);
136 }
137 
138 /*
139  * Translation between #defines and strings.
140  */
141 void
142 ipmi_entity_name(uint8_t id, char *buf, size_t len)
143 {
144 	ipmi_name_trans_t *ntp;
145 
146 	for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) {
147 		if (ntp->int_value == id) {
148 			(void) strlcpy(buf, ntp->int_name, len);
149 			return;
150 		}
151 	}
152 
153 	(void) snprintf(buf, len, "0x%02x", id);
154 }
155 
156 void
157 ipmi_sensor_type_name(uint8_t type, char *buf, size_t len)
158 {
159 	ipmi_name_trans_t *ntp;
160 
161 	for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
162 		if (ntp->int_value == type) {
163 			(void) strlcpy(buf, ntp->int_name, len);
164 			return;
165 		}
166 	}
167 
168 	(void) snprintf(buf, len, "0x%02x", type);
169 }
170 
171 void
172 ipmi_sensor_units_name(uint8_t type, char *buf, size_t len)
173 {
174 	ipmi_name_trans_t *ntp;
175 
176 	for (ntp = &ipmi_units_type_table[0]; ntp->int_name != NULL; ntp++) {
177 		if (ntp->int_value == type) {
178 			(void) strlcpy(buf, ntp->int_name, len);
179 			return;
180 		}
181 	}
182 
183 	(void) snprintf(buf, len, "0x%02x", type);
184 }
185 
186 void
187 ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type,
188     char *buf, size_t len)
189 {
190 	uint8_t val;
191 	ipmi_name_trans_t *ntp;
192 
193 	if (reading_type == IPMI_RT_SPECIFIC) {
194 		val = sensor_type;
195 		ntp = &ipmi_sensor_type_table[0];
196 	} else {
197 		val = reading_type;
198 		ntp = &ipmi_reading_type_table[0];
199 	}
200 
201 	for (; ntp->int_name != NULL; ntp++) {
202 		if (ntp->int_value == val) {
203 			(void) strlcpy(buf, ntp->int_name, len);
204 			return;
205 		}
206 	}
207 
208 	if (reading_type == IPMI_RT_SPECIFIC)
209 		(void) snprintf(buf, len, "%02x/%02x", reading_type,
210 		    sensor_type);
211 	else
212 		(void) snprintf(buf, len, "%02x", reading_type);
213 }
214 
215 /*
216  * Converts a BCD decimal value to an integer.
217  */
218 int
219 ipmi_convert_bcd(int value)
220 {
221 	int ret = 0;
222 	int digit;
223 	int i;
224 
225 	for (i = 7; i >= 0; i--) {
226 		digit = ((value & (0xf << (i * 4))) >> (i * 4));
227 		ret += digit * 10 * i;
228 	}
229 
230 	return (ret);
231 }
232 
233 /*
234  * See sections 43.15 and 43.16
235  *
236  * This is a utility function for decoding the strings that are packed into
237  * sensor data records.  If the type is 6-bit packed ASCII, then it converts
238  * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
239  * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
240  */
241 void
242 ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
243 {
244 	int i, j = 0, chunks, leftovers;
245 	uint8_t tmp, lo;
246 
247 	if (len == 0) {
248 		*buf = '\0';
249 		return;
250 	}
251 	/*
252 	 * If the type is 8-bit ASCII, we can simply copy the string and return
253 	 */
254 	if (type == 0x3) {
255 		(void) strncpy(buf, data, len);
256 		*(buf+len) = '\0';
257 		return;
258 	} else if (type == 0x1 || type == 0x0) {
259 		/*
260 		 * Yuck - they either used BCD plus encoding, which we don't
261 		 * currently handle, or they used an unspecified encoding type.
262 		 * In these cases we'll set buf to an empty string.  We still
263 		 * need to return the length so that we can get to the next
264 		 * record.
265 		 */
266 		*buf = '\0';
267 		return;
268 	}
269 
270 	/*
271 	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
272 	 * data first
273 	 */
274 	chunks = len / 3;
275 	leftovers = len % 3;
276 
277 	/*
278 	 * First we decode the 6-bit string in chunks of 3 bytes as far as
279 	 * possible
280 	 */
281 	for (i = 0; i < chunks; i++) {
282 		tmp = BITX(*(data+j), 5, 0);
283 		*buf++ = (char)(tmp + 32);
284 
285 		lo = BITX(*(data+j++), 7, 6);
286 		tmp = BITX(*(data+j), 3, 0);
287 		tmp = (tmp << 2) | lo;
288 		*buf++ = (char)(tmp + 32);
289 
290 		lo = BITX(*(data+j++), 7, 4);
291 		tmp = BITX(*(data+j), 1, 0);
292 		tmp = (tmp << 4) | lo;
293 		*buf++ = (char)(tmp + 32);
294 
295 		tmp = BITX(*(data+j++), 7, 2);
296 		*buf++ = (char)(tmp + 32);
297 	}
298 	switch (leftovers) {
299 		case 1:
300 			tmp = BITX(*(data+j), 5, 0);
301 			*buf++ = (char)(tmp + 32);
302 			break;
303 		case 2:
304 			tmp = BITX(*(data+j), 5, 0);
305 			*buf++ = (char)(tmp + 32);
306 
307 			lo = BITX(*(data+j++), 7, 6);
308 			tmp = BITX(*(data+j), 3, 0);
309 			tmp = (tmp << 2) | lo;
310 			*buf++ = (char)(tmp + 32);
311 			break;
312 	}
313 	*buf = '\0';
314 }
315