xref: /illumos-gate/usr/src/lib/libipmi/common/ipmi_util.c (revision 99dda20867d903eec23291ba1ecb18a82d70096b)
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_reading_name(uint8_t sensor_type, uint8_t reading_type,
173     char *buf, size_t len)
174 {
175 	uint8_t val;
176 	ipmi_name_trans_t *ntp;
177 
178 	if (reading_type == IPMI_RT_SPECIFIC) {
179 		val = sensor_type;
180 		ntp = &ipmi_sensor_type_table[0];
181 	} else {
182 		val = reading_type;
183 		ntp = &ipmi_reading_type_table[0];
184 	}
185 
186 	for (; ntp->int_name != NULL; ntp++) {
187 		if (ntp->int_value == val) {
188 			(void) strlcpy(buf, ntp->int_name, len);
189 			return;
190 		}
191 	}
192 
193 	if (reading_type == IPMI_RT_SPECIFIC)
194 		(void) snprintf(buf, len, "%02x/%02x", reading_type,
195 		    sensor_type);
196 	else
197 		(void) snprintf(buf, len, "%02x", reading_type);
198 }
199 
200 /*
201  * Converts a BCD decimal value to an integer.
202  */
203 int
204 ipmi_convert_bcd(int value)
205 {
206 	int ret = 0;
207 	int digit;
208 	int i;
209 
210 	for (i = 7; i >= 0; i--) {
211 		digit = ((value & (0xf << (i * 4))) >> (i * 4));
212 		ret += digit * 10 * i;
213 	}
214 
215 	return (ret);
216 }
217 
218 /*
219  * See sections 43.15 and 43.16
220  *
221  * This is a utility function for decoding the strings that are packed into
222  * sensor data records.  If the type is 6-bit packed ASCII, then it converts
223  * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
224  * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
225  */
226 void
227 ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
228 {
229 	int i, j = 0, chunks, leftovers;
230 	uint8_t tmp, lo;
231 
232 	if (len == 0) {
233 		*buf = '\0';
234 		return;
235 	}
236 	/*
237 	 * If the type is 8-bit ASCII, we can simply copy the string and return
238 	 */
239 	if (type == 0x3) {
240 		(void) strncpy(buf, data, len);
241 		*(buf+len) = '\0';
242 		return;
243 	} else if (type == 0x1 || type == 0x0) {
244 		/*
245 		 * Yuck - they either used BCD plus encoding, which we don't
246 		 * currently handle, or they used an unspecified encoding type.
247 		 * In these cases we'll set buf to an empty string.  We still
248 		 * need to return the length so that we can get to the next
249 		 * record.
250 		 */
251 		*buf = '\0';
252 		return;
253 	}
254 
255 	/*
256 	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
257 	 * data first
258 	 */
259 	chunks = len / 3;
260 	leftovers = len % 3;
261 
262 	/*
263 	 * First we decode the 6-bit string in chunks of 3 bytes as far as
264 	 * possible
265 	 */
266 	for (i = 0; i < chunks; i++) {
267 		tmp = BITX(*(data+j), 5, 0);
268 		*buf++ = (char)(tmp + 32);
269 
270 		lo = BITX(*(data+j++), 7, 6);
271 		tmp = BITX(*(data+j), 3, 0);
272 		tmp = (tmp << 2) | lo;
273 		*buf++ = (char)(tmp + 32);
274 
275 		lo = BITX(*(data+j++), 7, 4);
276 		tmp = BITX(*(data+j), 1, 0);
277 		tmp = (tmp << 4) | lo;
278 		*buf++ = (char)(tmp + 32);
279 
280 		tmp = BITX(*(data+j++), 7, 2);
281 		*buf++ = (char)(tmp + 32);
282 	}
283 	switch (leftovers) {
284 		case 1:
285 			tmp = BITX(*(data+j), 5, 0);
286 			*buf++ = (char)(tmp + 32);
287 			break;
288 		case 2:
289 			tmp = BITX(*(data+j), 5, 0);
290 			*buf++ = (char)(tmp + 32);
291 
292 			lo = BITX(*(data+j++), 7, 6);
293 			tmp = BITX(*(data+j), 3, 0);
294 			tmp = (tmp << 2) | lo;
295 			*buf++ = (char)(tmp + 32);
296 			break;
297 	}
298 	*buf = '\0';
299 }
300