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
ipmi_set_error(ipmi_handle_t * ihp,int error,const char * fmt,...)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
ipmi_errno(ipmi_handle_t * ihp)64 ipmi_errno(ipmi_handle_t *ihp)
65 {
66 return (ihp->ih_errno);
67 }
68
69 /* ARGSUSED */
70 const char *
ipmi_errmsg(ipmi_handle_t * ihp)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 *
ipmi_alloc(ipmi_handle_t * ihp,size_t size)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 *
ipmi_zalloc(ipmi_handle_t * ihp,size_t size)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 *
ipmi_strdup(ipmi_handle_t * ihp,const char * str)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
ipmi_free(ipmi_handle_t * ihp,void * ptr)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
ipmi_entity_name(uint8_t id,char * buf,size_t len)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
ipmi_sensor_type_name(uint8_t type,char * buf,size_t len)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
ipmi_sensor_units_name(uint8_t type,char * buf,size_t len)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
ipmi_sensor_reading_name(uint8_t sensor_type,uint8_t reading_type,char * buf,size_t len)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
ipmi_convert_bcd(int value)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
ipmi_decode_string(uint8_t type,uint8_t len,char * data,char * buf)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