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