1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "checks_ipmi.h"
21 
22 #ifdef HAVE_OPENIPMI
23 
24 /* Theoretically it should be enough max 16 bytes for sensor ID and terminating '\0' (see SDR record format in IPMI */
25 /* v2 spec). OpenIPMI author Corey Minyard explained at	*/
26 /* www.mail-archive.com/openipmi-developer@lists.sourceforge.net/msg02013.html: */
27 /* "...Since you can use BCD and the field is 16 bytes max, you can get up to 32 bytes in the ID string. Adding the */
28 /* sensor sharing and that's another three bytes (I believe 142 is the maximum number you can get), so 35 bytes is  */
29 /* the maximum, I believe." */
30 #define IPMI_SENSOR_ID_SZ	36
31 
32 /* delete inactive hosts after this period */
33 #define INACTIVE_HOST_LIMIT	3 * SEC_PER_HOUR
34 
35 #define IPMI_THRESHOLDS_NUM	6
36 #define MAX_DISCRETE_STATES	15
37 
38 #define ZBX_IPMI_TAG_ID				"id"
39 #define ZBX_IPMI_TAG_NAME			"name"
40 #define ZBX_IPMI_TAG_SENSOR			"sensor"
41 #define ZBX_IPMI_TAG_READING			"reading"
42 #define ZBX_IPMI_TAG_STATE			"state"
43 #define ZBX_IPMI_TAG_TYPE			"type"
44 #define ZBX_IPMI_TAG_TEXT			"text"
45 
46 #define ZBX_IPMI_TAG_UNITS			"units"
47 #define ZBX_IPMI_TAG_VALUE			"value"
48 #define ZBX_IPMI_TAG_THRESHOLD			"threshold"
49 #define ZBX_IPMI_TAG_LOWER			"lower"
50 #define ZBX_IPMI_TAG_UPPER			"upper"
51 #define ZBX_IPMI_TAG_NON_CRIT			"non_crit"
52 #define ZBX_IPMI_TAG_CRIT			"crit"
53 #define ZBX_IPMI_TAG_NON_RECOVER		"non_recover"
54 
55 #define ZBX_IPMI_THRESHOLD_STATUS_DISABLED	0
56 #define ZBX_IPMI_THRESHOLD_STATUS_ENABLED	1
57 
58 #include "log.h"
59 
60 #include <OpenIPMI/ipmiif.h>
61 #include <OpenIPMI/ipmi_posix.h>
62 #include <OpenIPMI/ipmi_lan.h>
63 #include <OpenIPMI/ipmi_auth.h>
64 
65 #define RETURN_IF_CB_DATA_NULL(x, y)							\
66 	if (NULL == (x))								\
67 	{										\
68 		zabbix_log(LOG_LEVEL_WARNING, "%s() called with cb_data:NULL", (y));	\
69 		return;									\
70 	}
71 
72 typedef union
73 {
74 	double		threshold;
75 	zbx_uint64_t	discrete;
76 }
77 zbx_ipmi_sensor_value_t;
78 
79 typedef struct
80 {
81 	int	status;	/* Is this threshold enabled? */
82 	double	val;
83 }
84 zbx_ipmi_sensor_threshold_t;
85 
86 typedef struct
87 {
88 	ipmi_sensor_t			*sensor;
89 	char				id[IPMI_SENSOR_ID_SZ];
90 	enum ipmi_str_type_e		id_type;	/* For sensors IPMI specifications mention Unicode, BCD plus, */
91 							/* 6-bit ASCII packed, 8-bit ASCII+Latin1.  */
92 	int				id_sz;		/* "id" value length in bytes */
93 	zbx_ipmi_sensor_value_t		value;
94 	int				reading_type;	/* "Event/Reading Type Code", e.g. Threshold, */
95 							/* Discrete, 'digital' Discrete. */
96 	int				type;		/* "Sensor Type Code", e.g. Temperature, Voltage, */
97 							/* Current, Fan, Physical Security (Chassis Intrusion), etc. */
98 	char				*full_name;
99 	int				state;
100 	zbx_ipmi_sensor_threshold_t	thresholds[IPMI_THRESHOLDS_NUM];
101 }
102 zbx_ipmi_sensor_t;
103 
104 typedef struct
105 {
106 	ipmi_control_t		*control;
107 	char			*c_name;
108 	int			num_values;
109 	int			*val;
110 	char			*full_name;
111 }
112 zbx_ipmi_control_t;
113 
114 typedef struct zbx_ipmi_host
115 {
116 	char			*ip;
117 	int			port;
118 	int			authtype;
119 	int			privilege;
120 	int			ret;
121 	char			*username;
122 	char			*password;
123 	zbx_ipmi_sensor_t	*sensors;
124 	zbx_ipmi_control_t	*controls;
125 	int			sensor_count;
126 	int			control_count;
127 	ipmi_con_t		*con;
128 	int			domain_up;
129 	int			done;
130 	time_t			lastaccess;	/* Time of last access attempt. Used to detect and delete inactive */
131 						/* (disabled) IPMI hosts from OpenIPMI to stop polling them. */
132 	unsigned int		domain_nr;	/* Domain number. It is converted to text string and used as */
133 						/* domain name. */
134 	char			*err;
135 	struct zbx_ipmi_host	*next;
136 }
137 zbx_ipmi_host_t;
138 
139 static unsigned int	domain_nr = 0;		/* for making a sequence of domain names "0", "1", "2", ... */
140 static zbx_ipmi_host_t	*hosts = NULL;		/* head of single-linked list of monitored hosts */
141 static os_handler_t	*os_hnd;
142 
zbx_sensor_id_to_str(char * str,size_t str_sz,const char * id,enum ipmi_str_type_e id_type,int id_sz)143 static char	*zbx_sensor_id_to_str(char *str, size_t str_sz, const char *id, enum ipmi_str_type_e id_type, int id_sz)
144 {
145 	/* minimum size of 'str' buffer, str_sz, is 35 bytes to avoid truncation */
146 	int	i;
147 	char	*p = str;
148 	size_t	id_len;
149 
150 	if (0 == id_sz)		/* id is meaningful only if length > 0 (see SDR record format in IPMI v2 spec) */
151 	{
152 		*str = '\0';
153 		return str;
154 	}
155 
156 	if (IPMI_SENSOR_ID_SZ < id_sz)
157 	{
158 		zbx_strlcpy(str, "ILLEGAL-SENSOR-ID-SIZE", str_sz);
159 		THIS_SHOULD_NEVER_HAPPEN;
160 		return str;
161 	}
162 
163 	switch (id_type)
164 	{
165 		case IPMI_ASCII_STR:
166 		case IPMI_UNICODE_STR:
167 			id_len = str_sz > (size_t)id_sz ? (size_t)id_sz : str_sz - 1;
168 			memcpy(str, id, id_len);
169 			*(str + id_len) = '\0';
170 			break;
171 		case IPMI_BINARY_STR:
172 			/* "BCD Plus" or "6-bit ASCII packed" encoding - print it as a hex string. */
173 
174 			*p++ = '0';	/* prefix to distinguish from ASCII/Unicode strings */
175 			*p++ = 'x';
176 			for (i = 0; i < id_sz; i++, p += 2)
177 			{
178 				zbx_snprintf(p, str_sz - (size_t)(2 + i + i), "%02x",
179 						(unsigned int)(unsigned char)*(id + i));
180 			}
181 			*p = '\0';
182 			break;
183 		default:
184 			zbx_strlcpy(str, "ILLEGAL-SENSOR-ID-TYPE", str_sz);
185 			THIS_SHOULD_NEVER_HAPPEN;
186 	}
187 	return str;
188 }
189 
190 /******************************************************************************
191  *                                                                            *
192  * Function: zbx_get_ipmi_host                                                *
193  *                                                                            *
194  * Purpose: Find element in the global list 'hosts' using parameters as       *
195  *          search criteria                                                   *
196  *                                                                            *
197  * Return value: pointer to list element with host data                       *
198  *               NULL if not found                                            *
199  *                                                                            *
200  ******************************************************************************/
zbx_get_ipmi_host(const char * ip,const int port,int authtype,int privilege,const char * username,const char * password)201 static zbx_ipmi_host_t	*zbx_get_ipmi_host(const char *ip, const int port, int authtype, int privilege,
202 		const char *username, const char *password)
203 {
204 	zbx_ipmi_host_t	*h;
205 
206 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __func__, ip, port);
207 
208 	h = hosts;
209 	while (NULL != h)
210 	{
211 		if (0 == strcmp(ip, h->ip) && port == h->port && authtype == h->authtype &&
212 				privilege == h->privilege && 0 == strcmp(username, h->username) &&
213 				0 == strcmp(password, h->password))
214 		{
215 			break;
216 		}
217 
218 		h = h->next;
219 	}
220 
221 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)h);
222 
223 	return h;
224 }
225 
226 /******************************************************************************
227  *                                                                            *
228  * Function: zbx_allocate_ipmi_host                                           *
229  *                                                                            *
230  * Purpose: create a new element in the global list 'hosts'                   *
231  *                                                                            *
232  * Return value: pointer to the new list element with host data               *
233  *                                                                            *
234  ******************************************************************************/
zbx_allocate_ipmi_host(const char * ip,int port,int authtype,int privilege,const char * username,const char * password)235 static zbx_ipmi_host_t	*zbx_allocate_ipmi_host(const char *ip, int port, int authtype, int privilege,
236 		const char *username, const char *password)
237 {
238 	zbx_ipmi_host_t	*h;
239 
240 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __func__, ip, port);
241 
242 	h = (zbx_ipmi_host_t *)zbx_malloc(NULL, sizeof(zbx_ipmi_host_t));
243 
244 	memset(h, 0, sizeof(zbx_ipmi_host_t));
245 
246 	h->ip = strdup(ip);
247 	h->port = port;
248 	h->authtype = authtype;
249 	h->privilege = privilege;
250 	h->username = strdup(username);
251 	h->password = strdup(password);
252 	h->domain_nr = domain_nr++;
253 
254 	h->next = hosts;
255 	hosts = h;
256 
257 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)h);
258 
259 	return h;
260 }
261 
zbx_get_ipmi_sensor(const zbx_ipmi_host_t * h,const ipmi_sensor_t * sensor)262 static zbx_ipmi_sensor_t	*zbx_get_ipmi_sensor(const zbx_ipmi_host_t *h, const ipmi_sensor_t *sensor)
263 {
264 	int			i;
265 	zbx_ipmi_sensor_t	*s = NULL;
266 
267 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p psensor:%p", __func__, (const void *)h,
268 			(const void *)sensor);
269 
270 	for (i = 0; i < h->sensor_count; i++)
271 	{
272 		if (h->sensors[i].sensor == sensor)
273 		{
274 			s = &h->sensors[i];
275 			break;
276 		}
277 	}
278 
279 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
280 
281 	return s;
282 }
283 
zbx_get_ipmi_sensor_by_id(const zbx_ipmi_host_t * h,const char * id)284 static zbx_ipmi_sensor_t	*zbx_get_ipmi_sensor_by_id(const zbx_ipmi_host_t *h, const char *id)
285 {
286 	int			i;
287 	zbx_ipmi_sensor_t	*s = NULL;
288 
289 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id, h->ip, h->port);
290 
291 	for (i = 0; i < h->sensor_count; i++)
292 	{
293 		if (0 == strcmp(h->sensors[i].id, id))
294 		{
295 			/* Some devices present a sensor as both a threshold sensor and a discrete sensor. We work */
296 			/* around this by preferring the threshold sensor in such case, as it is most widely used. */
297 
298 			s = &h->sensors[i];
299 
300 			if (IPMI_EVENT_READING_TYPE_THRESHOLD == s->reading_type)
301 				break;
302 		}
303 	}
304 
305 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
306 
307 	return s;
308 }
309 
zbx_get_ipmi_sensor_by_full_name(const zbx_ipmi_host_t * h,const char * full_name)310 static zbx_ipmi_sensor_t	*zbx_get_ipmi_sensor_by_full_name(const zbx_ipmi_host_t *h, const char *full_name)
311 {
312 	int			i;
313 	zbx_ipmi_sensor_t	*s = NULL;
314 
315 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d", __func__, full_name, h->ip, h->port);
316 
317 	for (i = 0; i < h->sensor_count; i++)
318 	{
319 		if (0 == strcmp(h->sensors[i].full_name, full_name))
320 		{
321 			s = &h->sensors[i];
322 			break;
323 		}
324 	}
325 
326 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
327 
328 	return s;
329 }
330 
331 /******************************************************************************
332  *                                                                            *
333  * Function: get_domain_offset                                                *
334  *                                                                            *
335  * Purpose: Check if an item name starts from domain name and find the domain *
336  *          name length                                                       *
337  *                                                                            *
338  * Parameters: h         - [IN] ipmi host                                     *
339  *             full_name - [IN] item name                                     *
340  *                                                                            *
341  * Return value: 0 or offset for skipping the domain name                     *
342  *                                                                            *
343  ******************************************************************************/
get_domain_offset(const zbx_ipmi_host_t * h,const char * full_name)344 static size_t	get_domain_offset(const zbx_ipmi_host_t *h, const char *full_name)
345 {
346 	char	domain_name[IPMI_DOMAIN_NAME_LEN];
347 	size_t	offset;
348 
349 	zbx_snprintf(domain_name, sizeof(domain_name), "%u", h->domain_nr);
350 	offset = strlen(domain_name);
351 
352 	if (offset >= strlen(full_name) || 0 != strncmp(domain_name, full_name, offset))
353 		offset = 0;
354 
355 	return offset;
356 }
357 /******************************************************************************
358  *                                                                            *
359  * Function: zbx_get_sensor_id                                                *
360  *                                                                            *
361  * Purpose:  Converts sensor id to printable string and return id_type        *
362  *                                                                            *
363  * Parameters: sensor    - [IN] ipmi sensor                                   *
364  *             id        - [OUT] sensor id                                    *
365  *             sz        - [IN] sensor id buffer length                       *
366  *             id_sz     - [OUT] sensor id length                             *
367  *             id_type   - [OUT] type of sensor id                            *
368  *             id_str    - [OUT] sensor id string                             *
369  *             id_str_sz - [IN] sensor id string buffer length                *
370  *                                                                            *
371  * Return value: pointer to sensor id string                                  *
372  *                                                                            *
373  ******************************************************************************/
zbx_get_sensor_id(ipmi_sensor_t * sensor,char * id,int sz,int * id_sz,enum ipmi_str_type_e * id_type,char * id_str,int id_str_sz)374 static char *zbx_get_sensor_id(ipmi_sensor_t *sensor, char *id, int sz, int *id_sz, enum ipmi_str_type_e *id_type,
375 		char *id_str, int id_str_sz )
376 {
377 	*id_sz = ipmi_sensor_get_id_length(sensor);
378 	memset(id, 0, (size_t)sz);
379 	ipmi_sensor_get_id(sensor, id, sz);
380 	*id_type = ipmi_sensor_get_id_type(sensor);
381 	return zbx_sensor_id_to_str(id_str, (size_t)id_str_sz, id, *id_type, *id_sz);
382 }
383 
zbx_allocate_ipmi_sensor(zbx_ipmi_host_t * h,ipmi_sensor_t * sensor)384 static zbx_ipmi_sensor_t	*zbx_allocate_ipmi_sensor(zbx_ipmi_host_t *h, ipmi_sensor_t *sensor)
385 {
386 	char			id_str[2 * IPMI_SENSOR_ID_SZ + 1];
387 	zbx_ipmi_sensor_t	*s;
388 	char			id[IPMI_SENSOR_ID_SZ];
389 	enum ipmi_str_type_e	id_type;
390 	int			id_sz;
391 	size_t			sz;
392 	char			full_name[IPMI_SENSOR_NAME_LEN];
393 	int 			i;
394 
395 	zbx_get_sensor_id(sensor, id, sizeof(id), &id_sz, &id_type, id_str, sizeof(id_str));
396 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id_str, h->ip, h->port);
397 
398 	h->sensor_count++;
399 	sz = (size_t)h->sensor_count * sizeof(zbx_ipmi_sensor_t);
400 
401 	if (NULL == h->sensors)
402 		h->sensors = (zbx_ipmi_sensor_t *)zbx_malloc(h->sensors, sz);
403 	else
404 		h->sensors = (zbx_ipmi_sensor_t *)zbx_realloc(h->sensors, sz);
405 
406 	s = &h->sensors[h->sensor_count - 1];
407 	s->sensor = sensor;
408 	memcpy(s->id, id, sizeof(id));
409 	s->id_type = id_type;
410 	s->id_sz = id_sz;
411 	memset(&s->value, 0, sizeof(s->value));
412 	s->reading_type = ipmi_sensor_get_event_reading_type(sensor);
413 	s->type = ipmi_sensor_get_sensor_type(sensor);
414 
415 	ipmi_sensor_get_name(s->sensor, full_name, sizeof(full_name));
416 	s->full_name = zbx_strdup(NULL, full_name + get_domain_offset(h, full_name));
417 	for (i = IPMI_LOWER_NON_CRITICAL; i <= IPMI_UPPER_NON_RECOVERABLE; i++)
418 		s->thresholds[i].status = ZBX_IPMI_THRESHOLD_STATUS_DISABLED;
419 
420 	zabbix_log(LOG_LEVEL_DEBUG, "Added sensor: host:'%s:%d' id_type:%d id_sz:%d id:'%s' reading_type:0x%x "
421 			"('%s') type:0x%x ('%s') domain:'%u' name:'%s'", h->ip, h->port, (int)s->id_type, s->id_sz,
422 			zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz),
423 			(unsigned int)s->reading_type, ipmi_sensor_get_event_reading_type_string(s->sensor),
424 			(unsigned int)s->type, ipmi_sensor_get_sensor_type_string(s->sensor), h->domain_nr,
425 			s->full_name);
426 
427 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
428 
429 	return s;
430 }
431 
zbx_delete_ipmi_sensor(zbx_ipmi_host_t * h,const ipmi_sensor_t * sensor)432 static void	zbx_delete_ipmi_sensor(zbx_ipmi_host_t *h, const ipmi_sensor_t *sensor)
433 {
434 	char	id_str[2 * IPMI_SENSOR_ID_SZ + 1];
435 	int	i;
436 	size_t	sz;
437 
438 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p psensor:%p", __func__, (void *)h, (const void *)sensor);
439 
440 	for (i = 0; i < h->sensor_count; i++)
441 	{
442 		if (h->sensors[i].sensor != sensor)
443 			continue;
444 
445 		sz = sizeof(zbx_ipmi_sensor_t);
446 
447 		zabbix_log(LOG_LEVEL_DEBUG, "sensor '%s@[%s]:%d' deleted",
448 				zbx_sensor_id_to_str(id_str, sizeof(id_str), h->sensors[i].id, h->sensors[i].id_type,
449 				h->sensors[i].id_sz), h->ip, h->port);
450 
451 		zbx_free(h->sensors[i].full_name);
452 
453 		h->sensor_count--;
454 		if (h->sensor_count != i)
455 			memmove(&h->sensors[i], &h->sensors[i + 1], sz * (size_t)(h->sensor_count - i));
456 		h->sensors = (zbx_ipmi_sensor_t *)zbx_realloc(h->sensors, sz * (size_t)h->sensor_count);
457 
458 		break;
459 	}
460 
461 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
462 }
463 
zbx_get_ipmi_control(const zbx_ipmi_host_t * h,const ipmi_control_t * control)464 static zbx_ipmi_control_t	*zbx_get_ipmi_control(const zbx_ipmi_host_t *h, const ipmi_control_t *control)
465 {
466 	int			i;
467 	zbx_ipmi_control_t	*c = NULL;
468 
469 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p pcontrol:%p", __func__, (const void *)h, (const void *)control);
470 
471 	for (i = 0; i < h->control_count; i++)
472 	{
473 		if (h->controls[i].control == control)
474 		{
475 			c = &h->controls[i];
476 			break;
477 		}
478 	}
479 
480 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
481 
482 	return c;
483 }
484 
zbx_get_ipmi_control_by_name(const zbx_ipmi_host_t * h,const char * c_name)485 static zbx_ipmi_control_t	*zbx_get_ipmi_control_by_name(const zbx_ipmi_host_t *h, const char *c_name)
486 {
487 	int			i;
488 	zbx_ipmi_control_t	*c = NULL;
489 
490 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() control: %s@[%s]:%d", __func__, c_name, h->ip, h->port);
491 
492 	for (i = 0; i < h->control_count; i++)
493 	{
494 		if (0 == strcmp(h->controls[i].c_name, c_name))
495 		{
496 			c = &h->controls[i];
497 			break;
498 		}
499 	}
500 
501 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
502 
503 	return c;
504 }
505 
zbx_get_ipmi_control_by_full_name(const zbx_ipmi_host_t * h,const char * full_name)506 static zbx_ipmi_control_t	*zbx_get_ipmi_control_by_full_name(const zbx_ipmi_host_t *h, const char *full_name)
507 {
508 	int			i;
509 	zbx_ipmi_control_t	*c = NULL;
510 
511 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() control:'%s@[%s]:%d", __func__, full_name, h->ip, h->port);
512 
513 	for (i = 0; i < h->control_count; i++)
514 	{
515 		if (0 == strcmp(h->controls[i].full_name, full_name))
516 		{
517 			c = &h->controls[i];
518 			break;
519 		}
520 	}
521 
522 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
523 
524 	return c;
525 }
526 
zbx_allocate_ipmi_control(zbx_ipmi_host_t * h,ipmi_control_t * control)527 static zbx_ipmi_control_t	*zbx_allocate_ipmi_control(zbx_ipmi_host_t *h, ipmi_control_t *control)
528 {
529 	size_t			sz, dm_sz;
530 	zbx_ipmi_control_t	*c;
531 	char			*c_name = NULL;
532 	char			full_name[IPMI_SENSOR_NAME_LEN];
533 
534 	sz = (size_t)ipmi_control_get_id_length(control);
535 	c_name = (char *)zbx_malloc(c_name, sz + 1);
536 	ipmi_control_get_id(control, c_name, sz);
537 
538 	ipmi_control_get_name(control, full_name, sizeof(full_name));
539 	dm_sz = get_domain_offset(h, full_name);
540 
541 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() Added control: host'%s:%d' id:'%s' domain:'%u' name:'%s'",
542 			__func__, h->ip, h->port, c_name, h->domain_nr, full_name + dm_sz);
543 
544 	h->control_count++;
545 	sz = (size_t)h->control_count * sizeof(zbx_ipmi_control_t);
546 
547 	if (NULL == h->controls)
548 		h->controls = (zbx_ipmi_control_t *)zbx_malloc(h->controls, sz);
549 	else
550 		h->controls = (zbx_ipmi_control_t *)zbx_realloc(h->controls, sz);
551 
552 	c = &h->controls[h->control_count - 1];
553 
554 	memset(c, 0, sizeof(zbx_ipmi_control_t));
555 
556 	c->control = control;
557 	c->c_name = c_name;
558 	c->num_values = ipmi_control_get_num_vals(control);
559 	sz = sizeof(int) * (size_t)c->num_values;
560 	c->val = (int *)zbx_malloc(c->val, sz);
561 	memset(c->val, 0, sz);
562 	c->full_name = zbx_strdup(NULL, full_name + dm_sz);
563 
564 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
565 
566 	return c;
567 }
568 
zbx_delete_ipmi_control(zbx_ipmi_host_t * h,const ipmi_control_t * control)569 static void	zbx_delete_ipmi_control(zbx_ipmi_host_t *h, const ipmi_control_t *control)
570 {
571 	int	i;
572 	size_t	sz;
573 
574 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p pcontrol:%p", __func__, (void *)h, (const void *)control);
575 
576 	for (i = 0; i < h->control_count; i++)
577 	{
578 		if (h->controls[i].control != control)
579 			continue;
580 
581 		sz = sizeof(zbx_ipmi_control_t);
582 
583 		zabbix_log(LOG_LEVEL_DEBUG, "control '%s@[%s]:%d' deleted", h->controls[i].c_name, h->ip, h->port);
584 
585 		zbx_free(h->controls[i].c_name);
586 		zbx_free(h->controls[i].val);
587 		zbx_free(h->controls[i].full_name);
588 
589 		h->control_count--;
590 		if (h->control_count != i)
591 			memmove(&h->controls[i], &h->controls[i + 1], sz * (size_t)(h->control_count - i));
592 		h->controls = (zbx_ipmi_control_t *)zbx_realloc(h->controls, sz * (size_t)h->control_count);
593 
594 		break;
595 	}
596 
597 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
598 }
599 
600 /* callback function invoked from OpenIPMI */
zbx_got_thresholds_cb(ipmi_sensor_t * sensor,int err,ipmi_thresholds_t * th,void * cb_data)601 static void	zbx_got_thresholds_cb(ipmi_sensor_t *sensor, int err, ipmi_thresholds_t *th, void *cb_data)
602 {
603 	zbx_ipmi_host_t		*h = (zbx_ipmi_host_t *)cb_data;
604 	zbx_ipmi_sensor_t	*s;
605 	enum ipmi_thresh_e 	i;
606 	int			val, ret;
607 
608 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
609 
610 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' err:%d th:%p", __func__, h->ip, h->port, err, (void *)th);
611 
612 	if (0 != err)
613 	{
614 		zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
615 
616 		h->err = zbx_dsprintf(h->err, "error 0x%x while getting thresholds for sensor", (unsigned int)err);
617 		h->ret = NOTSUPPORTED;
618 		goto out;
619 	}
620 
621 	if (NULL == (s = zbx_get_ipmi_sensor(h, sensor)))
622 	{
623 		char			id[IPMI_SENSOR_ID_SZ];
624 		char			id_str[2 * IPMI_SENSOR_ID_SZ + 1];
625 		int			id_sz;
626 		enum ipmi_str_type_e	id_type;
627 
628 		THIS_SHOULD_NEVER_HAPPEN;
629 		h->err = zbx_dsprintf(h->err, "fatal error: host:'[%s]:%d' sensor %s", h->ip, h->port,
630 				zbx_get_sensor_id(sensor, id, sizeof(id), &id_sz, &id_type,  id_str, sizeof(id_str)));
631 
632 		h->ret = NOTSUPPORTED;
633 		goto out;
634 	}
635 
636 	for (i = IPMI_LOWER_NON_CRITICAL; i <= IPMI_UPPER_NON_RECOVERABLE; i++)
637 	{
638 		double	thr;
639 
640 		s->thresholds[i].status = ZBX_IPMI_THRESHOLD_STATUS_DISABLED;
641 		ret = ipmi_sensor_threshold_readable(sensor, i, &val);
642 		if (0 != ret || 0 == val)
643 			continue;
644 
645 		if (0 == ipmi_threshold_get(th, i, &thr))
646 		{
647 			s->thresholds[i].status = ZBX_IPMI_THRESHOLD_STATUS_ENABLED;
648 			s->thresholds[i].val = thr;
649 		}
650 		else
651 			zabbix_log(LOG_LEVEL_DEBUG, "Threshold %s could not be fetched", ipmi_get_threshold_string(i));
652 	}
653 out:
654 	h->done = 1;
655 
656 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
657 }
658 
659 /*get sensor units full string*/
zbx_get_ipmi_units(ipmi_sensor_t * sensor)660 static char *zbx_get_ipmi_units(ipmi_sensor_t *sensor)
661 {
662 	const char	*base, *mod_use = "", *modifier = "", *rate;
663 
664 	if (0 != ipmi_sensor_get_percentage(sensor))
665 		return zbx_dsprintf(NULL, "%%");
666 
667 	base = ipmi_sensor_get_base_unit_string(sensor);
668 
669 	switch (ipmi_sensor_get_modifier_unit_use(sensor))
670 	{
671 		case IPMI_MODIFIER_UNIT_NONE:
672 			break;
673 		case IPMI_MODIFIER_UNIT_BASE_DIV_MOD:
674 			mod_use = "/";
675 			modifier = ipmi_sensor_get_modifier_unit_string(sensor);
676 			break;
677 		case IPMI_MODIFIER_UNIT_BASE_MULT_MOD:
678 			mod_use = "*";
679 			modifier = ipmi_sensor_get_modifier_unit_string(sensor);
680 			break;
681 		default:
682 			THIS_SHOULD_NEVER_HAPPEN;
683 	}
684 	rate = ipmi_sensor_get_rate_unit_string(sensor);
685 
686 	return zbx_dsprintf(NULL, "%s%s%s%s", base, mod_use, modifier, rate);
687 }
688 
689 /* callback function invoked from OpenIPMI */
zbx_got_thresh_reading_cb(ipmi_sensor_t * sensor,int err,enum ipmi_value_present_e value_present,unsigned int raw_value,double val,ipmi_states_t * states,void * cb_data)690 static void	zbx_got_thresh_reading_cb(ipmi_sensor_t *sensor, int err, enum ipmi_value_present_e value_present,
691 		unsigned int raw_value, double val, ipmi_states_t *states, void *cb_data)
692 {
693 	char			id_str[2 * IPMI_SENSOR_ID_SZ + 1];
694 	zbx_ipmi_host_t		*h = (zbx_ipmi_host_t *)cb_data;
695 	zbx_ipmi_sensor_t	*s;
696 
697 	ZBX_UNUSED(raw_value);
698 
699 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
700 
701 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
702 
703 	if (0 != err)
704 	{
705 		zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
706 
707 		h->err = zbx_dsprintf(h->err, "error 0x%x while reading threshold sensor", (unsigned int)err);
708 		h->ret = NOTSUPPORTED;
709 		goto out;
710 	}
711 
712 	if (0 == ipmi_is_sensor_scanning_enabled(states) || 0 != ipmi_is_initial_update_in_progress(states))
713 	{
714 		h->err = zbx_strdup(h->err, "sensor data is not available");
715 		h->ret = NOTSUPPORTED;
716 		goto out;
717 	}
718 
719 	s = zbx_get_ipmi_sensor(h, sensor);
720 
721 	if (NULL == s)
722 	{
723 		THIS_SHOULD_NEVER_HAPPEN;
724 		h->err = zbx_strdup(h->err, "fatal error");
725 		h->ret = NOTSUPPORTED;
726 		goto out;
727 	}
728 
729 	switch (value_present)
730 	{
731 		case IPMI_NO_VALUES_PRESENT:
732 		case IPMI_RAW_VALUE_PRESENT:
733 			h->err = zbx_strdup(h->err, "no value present for threshold sensor");
734 			h->ret = NOTSUPPORTED;
735 			break;
736 		case IPMI_BOTH_VALUES_PRESENT:
737 			s->value.threshold = val;
738 
739 			if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
740 			{
741 				char		*units;
742 				const char	*e_string, *s_type_string, *s_reading_type_string;
743 
744 				e_string = ipmi_entity_get_entity_id_string(ipmi_sensor_get_entity(sensor));
745 				s_type_string = ipmi_sensor_get_sensor_type_string(sensor);
746 				s_reading_type_string = ipmi_sensor_get_event_reading_type_string(sensor);
747 
748 				units = zbx_get_ipmi_units(sensor);
749 
750 				zabbix_log(LOG_LEVEL_DEBUG, "Value [%s | %s | %s | %s | " ZBX_FS_DBL " %s]",
751 						zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type,
752 						s->id_sz), e_string, s_type_string, s_reading_type_string, val, units);
753 
754 				zbx_free(units);
755 			}
756 
757 			s->state = 0;
758 			if (IPMI_THRESHOLD_ACCESS_SUPPORT_NONE != ipmi_sensor_get_threshold_access(sensor))
759 			{
760 				int	value, ret;
761 				int	i;
762 
763 				for (i = IPMI_LOWER_NON_CRITICAL; i <= IPMI_UPPER_NON_RECOVERABLE; i++)
764 				{
765 					ret = ipmi_sensor_threshold_reading_supported(sensor, i, &value);
766 					if (0 != ret || 0 == value)
767 						continue;
768 					if (0 != ipmi_is_threshold_out_of_range(states, i))
769 						s->state |= 1 << i;
770 				}
771 			}
772 
773 			break;
774 		default:
775 			THIS_SHOULD_NEVER_HAPPEN;
776 	}
777 out:
778 	h->done = 1;
779 
780 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
781 }
782 
783 /* callback function invoked from OpenIPMI */
zbx_got_discrete_states_cb(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)784 static void	zbx_got_discrete_states_cb(ipmi_sensor_t *sensor, int err, ipmi_states_t *states, void *cb_data)
785 {
786 	char			id_str[2 * IPMI_SENSOR_ID_SZ + 1];
787 	int			id, i, val, ret, is_state_set;
788 	zbx_ipmi_host_t		*h = (zbx_ipmi_host_t *)cb_data;
789 	zbx_ipmi_sensor_t	*s;
790 
791 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
792 
793 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
794 
795 	if (0 == ipmi_is_sensor_scanning_enabled(states) || 0 != ipmi_is_initial_update_in_progress(states))
796 	{
797 		h->err = zbx_strdup(h->err, "sensor data is not available");
798 		h->ret = NOTSUPPORTED;
799 		goto out;
800 	}
801 
802 	s = zbx_get_ipmi_sensor(h, sensor);
803 
804 	if (NULL == s)
805 	{
806 		THIS_SHOULD_NEVER_HAPPEN;
807 		h->err = zbx_strdup(h->err, "fatal error");
808 		h->ret = NOTSUPPORTED;
809 		goto out;
810 	}
811 
812 	if (0 != err)
813 	{
814 		h->err = zbx_dsprintf(h->err, "error 0x%x while reading a discrete sensor %s@[%s]:%d",
815 				(unsigned int)err,
816 				zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz), h->ip,
817 				h->port);
818 		h->ret = NOTSUPPORTED;
819 		goto out;
820 	}
821 
822 	id = ipmi_entity_get_entity_id(ipmi_sensor_get_entity(sensor));
823 
824 	/* Discrete values are 16-bit. We're storing them into a 64-bit uint. */
825 
826 	s->value.discrete = 0;
827 	for (i = 0; i < MAX_DISCRETE_STATES; i++)
828 	{
829 		ret = ipmi_sensor_discrete_event_readable(sensor, i, &val);
830 		if (0 != ret || 0 == val)
831 			continue;
832 
833 		is_state_set = ipmi_is_state_set(states, i);
834 
835 		zabbix_log(LOG_LEVEL_DEBUG, "State [%s | %s | %s | %s | state %d value is %d]",
836 				zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz),
837 				ipmi_get_entity_id_string(id), ipmi_sensor_get_sensor_type_string(sensor),
838 				ipmi_sensor_get_event_reading_type_string(sensor), i, is_state_set);
839 
840 		if (0 != is_state_set)
841 			s->value.discrete |= 1 << i;
842 	}
843 out:
844 	h->done = 1;
845 
846 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
847 }
848 
849 /******************************************************************************
850  *                                                                            *
851  * Function: zbx_perform_openipmi_ops                                         *
852  *                                                                            *
853  * Purpose: Pass control to OpenIPMI library to process events                *
854  *                                                                            *
855  * Return value: SUCCEED - no errors                                          *
856  *               FAIL - an error occurred while processing events             *
857  *                                                                            *
858  ******************************************************************************/
zbx_perform_openipmi_ops(zbx_ipmi_host_t * h,const char * func_name)859 static int	zbx_perform_openipmi_ops(zbx_ipmi_host_t *h, const char *func_name)
860 {
861 	struct timeval	tv;
862 
863 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p from %s()", __func__, h->ip, h->port,
864 			(void *)h, func_name);
865 
866 	tv.tv_sec = 10;		/* set timeout for one operation */
867 	tv.tv_usec = 0;
868 
869 	while (0 == h->done)
870 	{
871 		int	res;
872 
873 		if (0 == (res = os_hnd->perform_one_op(os_hnd, &tv)))
874 			continue;
875 
876 		zabbix_log(LOG_LEVEL_DEBUG, "End %s() from %s(): error: %s", __func__, func_name, zbx_strerror(res));
877 
878 		return FAIL;
879 	}
880 
881 	zabbix_log(LOG_LEVEL_DEBUG, "End %s() from %s()", __func__, func_name);
882 
883 	return SUCCEED;
884 }
885 
886 /******************************************************************************
887  *                                                                            *
888  * Function: zbx_perform_all_openipmi_ops                                     *
889  *                                                                            *
890  * Purpose: Pass control to OpenIPMI library to process all internal events   *
891  *                                                                            *
892  * Parameters: timeout - [IN] timeout (in seconds) for processing single      *
893  *                            operation; processing multiple operations may   *
894  *                            take more time                                  *
895  *                                                                            *
896  *****************************************************************************/
zbx_perform_all_openipmi_ops(int timeout)897 void	zbx_perform_all_openipmi_ops(int timeout)
898 {
899 	/* Before OpenIPMI v2.0.26, perform_one_op() did not modify timeout argument.   */
900 	/* Starting with OpenIPMI v2.0.26, perform_one_op() updates timeout argument.   */
901 	/* To make sure that the loop works consistently with all versions of OpenIPMI, */
902 	/* initialize timeout argument for perform_one_op() inside the loop.            */
903 
904 	for (;;)
905 	{
906 		struct timeval	tv;
907 		double		start_time;
908 		int		res;
909 
910 		tv.tv_sec = timeout;
911 		tv.tv_usec = 0;
912 
913 		start_time = zbx_time();
914 
915 		/* perform_one_op() returns 0 on success, errno on failure (timeout means success) */
916 		if (0 != (res = os_hnd->perform_one_op(os_hnd, &tv)))
917 		{
918 			zabbix_log(LOG_LEVEL_DEBUG, "IPMI error: %s", zbx_strerror(res));
919 			break;
920 		}
921 
922 		/* If execution of perform_one_op() took more time than specified in timeout argument, assume that  */
923 		/* perform_one_op() timed out and break the loop.                                                   */
924 		/* If it took less than specified in timeout argument, assume that some operation was performed and */
925 		/* there may be more operations to be performed.                                                    */
926 		if (zbx_time() - start_time >= timeout)
927 		{
928 			break;
929 		}
930 	}
931 }
932 
zbx_read_ipmi_sensor(zbx_ipmi_host_t * h,const zbx_ipmi_sensor_t * s)933 static void	zbx_read_ipmi_sensor(zbx_ipmi_host_t *h, const zbx_ipmi_sensor_t *s)
934 {
935 	char		id_str[2 * IPMI_SENSOR_ID_SZ + 1];
936 	int		ret;
937 	const char	*s_reading_type_string;
938 
939 	/* copy sensor details at start - it can go away and we won't be able to make an error message */
940 	zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz);
941 
942 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id_str, h->ip, h->port);
943 
944 	h->ret = SUCCEED;
945 	h->done = 0;
946 
947 	switch (s->reading_type)
948 	{
949 		case IPMI_EVENT_READING_TYPE_THRESHOLD:
950 			if (0 != (ret = ipmi_sensor_get_reading(s->sensor, zbx_got_thresh_reading_cb, h)))
951 			{
952 				/* do not use pointer to sensor here - the sensor may have disappeared during */
953 				/* ipmi_sensor_get_reading(), as domain might be closed due to communication failure */
954 				h->err = zbx_dsprintf(h->err, "Cannot read sensor \"%s\"."
955 						" ipmi_sensor_get_reading() return error: 0x%x", id_str,
956 						(unsigned int)ret);
957 				h->ret = NOTSUPPORTED;
958 				goto out;
959 			}
960 			break;
961 		case IPMI_EVENT_READING_TYPE_DISCRETE_USAGE:
962 		case IPMI_EVENT_READING_TYPE_DISCRETE_STATE:
963 		case IPMI_EVENT_READING_TYPE_DISCRETE_PREDICTIVE_FAILURE:
964 		case IPMI_EVENT_READING_TYPE_DISCRETE_LIMIT_EXCEEDED:
965 		case IPMI_EVENT_READING_TYPE_DISCRETE_PERFORMANCE_MET:
966 		case IPMI_EVENT_READING_TYPE_DISCRETE_SEVERITY:
967 		case IPMI_EVENT_READING_TYPE_DISCRETE_DEVICE_PRESENCE:
968 		case IPMI_EVENT_READING_TYPE_DISCRETE_DEVICE_ENABLE:
969 		case IPMI_EVENT_READING_TYPE_DISCRETE_AVAILABILITY:
970 		case IPMI_EVENT_READING_TYPE_DISCRETE_REDUNDANCY:
971 		case IPMI_EVENT_READING_TYPE_DISCRETE_ACPI_POWER:
972 		case IPMI_EVENT_READING_TYPE_SENSOR_SPECIFIC:
973 		case 0x70:	/* reading types 70h-7Fh are for OEM discrete sensors */
974 		case 0x71:
975 		case 0x72:
976 		case 0x73:
977 		case 0x74:
978 		case 0x75:
979 		case 0x76:
980 		case 0x77:
981 		case 0x78:
982 		case 0x79:
983 		case 0x7a:
984 		case 0x7b:
985 		case 0x7c:
986 		case 0x7d:
987 		case 0x7e:
988 		case 0x7f:
989 			if (0 != (ret = ipmi_sensor_get_states(s->sensor, zbx_got_discrete_states_cb, h)))
990 			{
991 				/* do not use pointer to sensor here - the sensor may have disappeared during */
992 				/* ipmi_sensor_get_states(), as domain might be closed due to communication failure */
993 				h->err = zbx_dsprintf(h->err, "Cannot read sensor \"%s\"."
994 						" ipmi_sensor_get_states() return error: 0x%x", id_str,
995 						(unsigned int)ret);
996 				h->ret = NOTSUPPORTED;
997 				goto out;
998 			}
999 			break;
1000 		default:
1001 			s_reading_type_string = ipmi_sensor_get_event_reading_type_string(s->sensor);
1002 
1003 			h->err = zbx_dsprintf(h->err, "Cannot read sensor \"%s\"."
1004 					" IPMI reading type \"%s\" is not supported", id_str, s_reading_type_string);
1005 			h->ret = NOTSUPPORTED;
1006 			goto out;
1007 	}
1008 
1009 	zbx_perform_openipmi_ops(h, __func__);	/* ignore returned result */
1010 out:
1011 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1012 }
1013 
zbx_read_ipmi_thresholds(zbx_ipmi_host_t * h,const zbx_ipmi_sensor_t * s)1014 static void	zbx_read_ipmi_thresholds(zbx_ipmi_host_t *h, const zbx_ipmi_sensor_t *s)
1015 {
1016 	char	id_str[2 * IPMI_SENSOR_ID_SZ + 1];
1017 	int 	ret;
1018 	int	thr_access;
1019 
1020 	/* copy sensor details at start - it can go away and we won't be able to make an error message */
1021 	zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz);
1022 
1023 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id_str, h->ip, h->port);
1024 
1025 	h->done = 0;
1026 
1027 	thr_access = ipmi_sensor_get_threshold_access(s->sensor);
1028 	if (thr_access == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE || thr_access == IPMI_THRESHOLD_ACCESS_SUPPORT_FIXED)
1029 	{
1030 		zabbix_log(LOG_LEVEL_DEBUG, "Cannot access thresholds");
1031 		goto out;
1032 	}
1033 
1034 	if (0 != (ret = ipmi_sensor_get_thresholds(s->sensor, zbx_got_thresholds_cb, h)))
1035 	{
1036 		zabbix_log(LOG_LEVEL_DEBUG, "Cannot read thresholds for sensor \"%s\". ipmi_sensor_get_thresholds()"
1037 				" return error: 0x%x", id_str, (unsigned int)ret);
1038 		goto out;
1039 	}
1040 
1041 	zbx_perform_openipmi_ops(h, __func__);	/* ignore returned result */
1042 out:
1043 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1044 }
1045 /* callback function invoked from OpenIPMI */
zbx_got_control_reading_cb(ipmi_control_t * control,int err,int * val,void * cb_data)1046 static void	zbx_got_control_reading_cb(ipmi_control_t *control, int err, int *val, void *cb_data)
1047 {
1048 	zbx_ipmi_host_t		*h = (zbx_ipmi_host_t *)cb_data;
1049 	int			n;
1050 	zbx_ipmi_control_t	*c;
1051 	const char		*e_string;
1052 	size_t			sz;
1053 
1054 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1055 
1056 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1057 
1058 	if (0 != err)
1059 	{
1060 		zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
1061 
1062 		h->err = zbx_dsprintf(h->err, "error 0x%x while reading control", (unsigned int)err);
1063 		h->ret = NOTSUPPORTED;
1064 		goto out;
1065 	}
1066 
1067 	c = zbx_get_ipmi_control(h, control);
1068 
1069 	if (NULL == c)
1070 	{
1071 		THIS_SHOULD_NEVER_HAPPEN;
1072 		h->err = zbx_strdup(h->err, "fatal error");
1073 		h->ret = NOTSUPPORTED;
1074 		goto out;
1075 	}
1076 
1077 	if (c->num_values == 0)
1078 	{
1079 		THIS_SHOULD_NEVER_HAPPEN;
1080 		h->err = zbx_strdup(h->err, "no value present for control");
1081 		h->ret = NOTSUPPORTED;
1082 		goto out;
1083 	}
1084 
1085 	e_string = ipmi_entity_get_entity_id_string(ipmi_control_get_entity(control));
1086 
1087 	for (n = 0; n < c->num_values; n++)
1088 	{
1089 		zabbix_log(LOG_LEVEL_DEBUG, "control values [%s | %s | %d:%d]",
1090 				c->c_name, e_string, n + 1, val[n]);
1091 	}
1092 
1093 	sz = sizeof(int) * (size_t)c->num_values;
1094 	memcpy(c->val, val, sz);
1095 out:
1096 	h->done = 1;
1097 
1098 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1099 }
1100 
1101 /* callback function invoked from OpenIPMI */
zbx_got_control_setting_cb(ipmi_control_t * control,int err,void * cb_data)1102 static void	zbx_got_control_setting_cb(ipmi_control_t *control, int err, void *cb_data)
1103 {
1104 	zbx_ipmi_host_t		*h = (zbx_ipmi_host_t *)cb_data;
1105 	zbx_ipmi_control_t	*c;
1106 
1107 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1108 
1109 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1110 
1111 	if (0 != err)
1112 	{
1113 		zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
1114 
1115 		h->err = zbx_dsprintf(h->err, "error 0x%x while set control", (unsigned int)err);
1116 		h->ret = NOTSUPPORTED;
1117 		h->done = 1;
1118 		return;
1119 	}
1120 
1121 	c = zbx_get_ipmi_control(h, control);
1122 
1123 	if (NULL == c)
1124 	{
1125 		THIS_SHOULD_NEVER_HAPPEN;
1126 		h->err = zbx_strdup(h->err, "fatal error");
1127 		h->ret = NOTSUPPORTED;
1128 		h->done = 1;
1129 		return;
1130 	}
1131 
1132 	zabbix_log(LOG_LEVEL_DEBUG, "set value completed for control %s@[%s]:%d", c->c_name, h->ip, h->port);
1133 
1134 	h->done = 1;
1135 
1136 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1137 }
1138 
zbx_read_ipmi_control(zbx_ipmi_host_t * h,const zbx_ipmi_control_t * c)1139 static void	zbx_read_ipmi_control(zbx_ipmi_host_t *h, const zbx_ipmi_control_t *c)
1140 {
1141 	int	ret;
1142 	char	control_name[128];	/* internally defined CONTROL_ID_LEN is 32 in OpenIPMI 2.0.22 */
1143 
1144 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() control:'%s@[%s]:%d'", __func__, c->c_name, h->ip, h->port);
1145 
1146 	if (0 == ipmi_control_is_readable(c->control))
1147 	{
1148 		h->err = zbx_strdup(h->err, "control is not readable");
1149 		h->ret = NOTSUPPORTED;
1150 		goto out;
1151 	}
1152 
1153 	/* copy control name - it can go away and we won't be able to make an error message */
1154 	zbx_strlcpy(control_name, c->c_name, sizeof(control_name));
1155 
1156 	h->ret = SUCCEED;
1157 	h->done = 0;
1158 
1159 	if (0 != (ret = ipmi_control_get_val(c->control, zbx_got_control_reading_cb, h)))
1160 	{
1161 		/* do not use pointer to control here - the control may have disappeared during */
1162 		/* ipmi_control_get_val(), as domain might be closed due to communication failure */
1163 		h->err = zbx_dsprintf(h->err, "Cannot read control %s. ipmi_control_get_val() return error: 0x%x",
1164 				control_name, (unsigned int)ret);
1165 		h->ret = NOTSUPPORTED;
1166 		goto out;
1167 	}
1168 
1169 	zbx_perform_openipmi_ops(h, __func__);	/* ignore returned result */
1170 out:
1171 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1172 }
1173 
zbx_set_ipmi_control(zbx_ipmi_host_t * h,zbx_ipmi_control_t * c,int value)1174 static void	zbx_set_ipmi_control(zbx_ipmi_host_t *h, zbx_ipmi_control_t *c, int value)
1175 {
1176 	int	ret;
1177 	char	control_name[128];	/* internally defined CONTROL_ID_LEN is 32 in OpenIPMI 2.0.22 */
1178 
1179 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() control:'%s@[%s]:%d' value:%d",
1180 			__func__, c->c_name, h->ip, h->port, value);
1181 
1182 	if (c->num_values == 0)
1183 	{
1184 		THIS_SHOULD_NEVER_HAPPEN;
1185 		h->err = zbx_strdup(h->err, "no value present for control");
1186 		h->ret = NOTSUPPORTED;
1187 		h->done = 1;
1188 		goto out;
1189 	}
1190 
1191 	if (0 == ipmi_control_is_settable(c->control))
1192 	{
1193 		h->err = zbx_strdup(h->err, "control is not settable");
1194 		h->ret = NOTSUPPORTED;
1195 		goto out;
1196 	}
1197 
1198 	/* copy control name - it can go away and we won't be able to make an error message */
1199 	zbx_strlcpy(control_name, c->c_name, sizeof(control_name));
1200 
1201 	c->val[0] = value;
1202 	h->ret = SUCCEED;
1203 	h->done = 0;
1204 
1205 	if (0 != (ret = ipmi_control_set_val(c->control, c->val, zbx_got_control_setting_cb, h)))
1206 	{
1207 		/* do not use pointer to control here - the control may have disappeared during */
1208 		/* ipmi_control_set_val(), as domain might be closed due to communication failure */
1209 		h->err = zbx_dsprintf(h->err, "Cannot set control %s. ipmi_control_set_val() return error: 0x%x",
1210 				control_name, (unsigned int)ret);
1211 		h->ret = NOTSUPPORTED;
1212 		goto out;
1213 	}
1214 
1215 	zbx_perform_openipmi_ops(h, __func__);	/* ignore returned result */
1216 out:
1217 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1218 }
1219 
1220 /* callback function invoked from OpenIPMI */
zbx_sensor_change_cb(enum ipmi_update_e op,ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)1221 static void	zbx_sensor_change_cb(enum ipmi_update_e op, ipmi_entity_t *ent, ipmi_sensor_t *sensor, void *cb_data)
1222 {
1223 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1224 
1225 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1226 
1227 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p ent:%p sensor:%p op:%d",
1228 			__func__, h->ip, h->port, (void *)h, (void *)ent, (void *)sensor, (int)op);
1229 
1230 	/* ignore non-readable sensors (e.g. Event-only) */
1231 	if (0 != ipmi_sensor_get_is_readable(sensor))
1232 	{
1233 		switch (op)
1234 		{
1235 			case IPMI_ADDED:
1236 				if (NULL == zbx_get_ipmi_sensor(h, sensor))
1237 					zbx_allocate_ipmi_sensor(h, sensor);
1238 				break;
1239 			case IPMI_DELETED:
1240 				zbx_delete_ipmi_sensor(h, sensor);
1241 				break;
1242 			case IPMI_CHANGED:
1243 				break;
1244 			default:
1245 				THIS_SHOULD_NEVER_HAPPEN;
1246 		}
1247 	}
1248 
1249 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1250 }
1251 
1252 /* callback function invoked from OpenIPMI */
zbx_control_change_cb(enum ipmi_update_e op,ipmi_entity_t * ent,ipmi_control_t * control,void * cb_data)1253 static void	zbx_control_change_cb(enum ipmi_update_e op, ipmi_entity_t *ent, ipmi_control_t *control, void *cb_data)
1254 {
1255 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1256 
1257 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1258 
1259 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p ent:%p control:%p op:%d",
1260 			__func__, h->ip, h->port, (void *)h, (void *)ent, (void *)control, (int)op);
1261 
1262 	switch (op)
1263 	{
1264 		case IPMI_ADDED:
1265 			if (NULL == zbx_get_ipmi_control(h, control))
1266 				zbx_allocate_ipmi_control(h, control);
1267 			break;
1268 		case IPMI_DELETED:
1269 			zbx_delete_ipmi_control(h, control);
1270 			break;
1271 		case IPMI_CHANGED:
1272 			break;
1273 		default:
1274 			THIS_SHOULD_NEVER_HAPPEN;
1275 	}
1276 
1277 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1278 }
1279 
1280 /* callback function invoked from OpenIPMI */
zbx_entity_change_cb(enum ipmi_update_e op,ipmi_domain_t * domain,ipmi_entity_t * entity,void * cb_data)1281 static void	zbx_entity_change_cb(enum ipmi_update_e op, ipmi_domain_t *domain, ipmi_entity_t *entity, void *cb_data)
1282 {
1283 	int	ret;
1284 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1285 
1286 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1287 
1288 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
1289 	{
1290 		char	entity_name[IPMI_ENTITY_NAME_LEN];
1291 
1292 		ipmi_entity_get_name(entity, entity_name, sizeof(entity_name));
1293 
1294 		zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p domain:%p entity:%p:'%s' op:%d",
1295 				__func__, h->ip, h->port, (void *)h, (void *)domain, (void *)entity, entity_name,
1296 				(int)op);
1297 	}
1298 
1299 	if (op == IPMI_ADDED)
1300 	{
1301 		if (0 != (ret = ipmi_entity_add_sensor_update_handler(entity, zbx_sensor_change_cb, h)))
1302 		{
1303 			zabbix_log(LOG_LEVEL_DEBUG, "ipmi_entity_set_sensor_update_handler() return error: 0x%x",
1304 					(unsigned int)ret);
1305 		}
1306 
1307 		if (0 != (ret = ipmi_entity_add_control_update_handler(entity, zbx_control_change_cb, h)))
1308 		{
1309 			zabbix_log(LOG_LEVEL_DEBUG, "ipmi_entity_add_control_update_handler() return error: 0x%x",
1310 					(unsigned int)ret);
1311 		}
1312 	}
1313 
1314 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1315 }
1316 
1317 /* callback function invoked from OpenIPMI */
zbx_domain_closed_cb(void * cb_data)1318 static void	zbx_domain_closed_cb(void *cb_data)
1319 {
1320 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1321 
1322 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1323 
1324 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p host:'[%s]:%d'", __func__, (void *)h, h->ip, h->port);
1325 
1326 	h->domain_up = 0;
1327 	h->done = 1;
1328 
1329 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1330 }
1331 
1332 /* callback function invoked from OpenIPMI */
zbx_connection_change_cb(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected,void * cb_data)1333 static void	zbx_connection_change_cb(ipmi_domain_t *domain, int err, unsigned int conn_num, unsigned int port_num,
1334 		int still_connected, void *cb_data)
1335 {
1336 	/* this function is called when a connection comes up or goes down */
1337 
1338 	int		ret;
1339 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1340 
1341 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1342 
1343 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p domain:%p err:%d conn_num:%u port_num:%u"
1344 			" still_connected:%d cb_data:%p", __func__, h->ip, h->port, (void *)h, (void *)domain,
1345 			err, conn_num, port_num, still_connected, cb_data);
1346 
1347 	if (0 != err)
1348 	{
1349 		zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
1350 
1351 		h->err = zbx_dsprintf(h->err, "cannot connect to IPMI host: %s", zbx_strerror(err));
1352 		h->ret = NETWORK_ERROR;
1353 
1354 		if (0 != (ret = ipmi_domain_close(domain, zbx_domain_closed_cb, h)))
1355 			zabbix_log(LOG_LEVEL_DEBUG, "cannot close IPMI domain: [0x%x]", (unsigned int)ret);
1356 
1357 		goto out;
1358 	}
1359 
1360 	if (0 != (ret = ipmi_domain_add_entity_update_handler(domain, zbx_entity_change_cb, h)))
1361 	{
1362 		zabbix_log(LOG_LEVEL_DEBUG, "ipmi_domain_add_entity_update_handler() return error: [0x%x]",
1363 				(unsigned int)ret);
1364 	}
1365 out:
1366 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1367 }
1368 
1369 /* callback function invoked from OpenIPMI */
zbx_domain_up_cb(ipmi_domain_t * domain,void * cb_data)1370 static void	zbx_domain_up_cb(ipmi_domain_t *domain, void *cb_data)
1371 {
1372 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1373 
1374 	RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1375 
1376 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' domain:%p cb_data:%p", __func__, h->ip,
1377 			h->port, (void *)domain, cb_data);
1378 
1379 	h->domain_up = 1;
1380 	h->done = 1;
1381 
1382 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1383 }
1384 
zbx_vlog(os_handler_t * handler,const char * format,enum ipmi_log_type_e log_type,va_list ap)1385 static void	zbx_vlog(os_handler_t *handler, const char *format, enum ipmi_log_type_e log_type, va_list ap)
1386 {
1387 	char	type[8], str[MAX_STRING_LEN];
1388 
1389 	ZBX_UNUSED(handler);
1390 
1391 	switch (log_type)
1392 	{
1393 		case IPMI_LOG_INFO		: zbx_strlcpy(type, "INFO: ", sizeof(type)); break;
1394 		case IPMI_LOG_WARNING		: zbx_strlcpy(type, "WARN: ", sizeof(type)); break;
1395 		case IPMI_LOG_SEVERE		: zbx_strlcpy(type, "SEVR: ", sizeof(type)); break;
1396 		case IPMI_LOG_FATAL		: zbx_strlcpy(type, "FATL: ", sizeof(type)); break;
1397 		case IPMI_LOG_ERR_INFO		: zbx_strlcpy(type, "EINF: ", sizeof(type)); break;
1398 		case IPMI_LOG_DEBUG_START	:
1399 		case IPMI_LOG_DEBUG		: zbx_strlcpy(type, "DEBG: ", sizeof(type)); break;
1400 		case IPMI_LOG_DEBUG_CONT	:
1401 		case IPMI_LOG_DEBUG_END		: *type = '\0'; break;
1402 		default				: THIS_SHOULD_NEVER_HAPPEN;
1403 	}
1404 
1405 	zbx_vsnprintf(str, sizeof(str), format, ap);
1406 
1407 	zabbix_log(LOG_LEVEL_DEBUG, "%s%s", type, str);
1408 }
1409 
zbx_init_ipmi_handler(void)1410 int	zbx_init_ipmi_handler(void)
1411 {
1412 	int		res, ret = FAIL;
1413 
1414 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1415 
1416 	if (NULL == (os_hnd = ipmi_posix_setup_os_handler()))
1417 	{
1418 		zabbix_log(LOG_LEVEL_WARNING, "unable to allocate IPMI handler");
1419 		goto out;
1420 	}
1421 
1422 	os_hnd->set_log_handler(os_hnd, zbx_vlog);
1423 
1424 	if (0 != (res = ipmi_init(os_hnd)))
1425 	{
1426 		zabbix_log(LOG_LEVEL_WARNING, "unable to initialize the OpenIPMI library."
1427 				" ipmi_init() return error: 0x%x", (unsigned int)res);
1428 		goto out;
1429 	}
1430 
1431 	ret = SUCCEED;
1432 out:
1433 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1434 
1435 	return ret;
1436 }
1437 
zbx_free_ipmi_host(zbx_ipmi_host_t * h)1438 static void	zbx_free_ipmi_host(zbx_ipmi_host_t *h)
1439 {
1440 	int	i;
1441 
1442 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' h:%p", __func__, h->ip, h->port, (void *)h);
1443 
1444 	for (i = 0; i < h->control_count; i++)
1445 	{
1446 		zbx_free(h->controls[i].c_name);
1447 		zbx_free(h->controls[i].val);
1448 	}
1449 
1450 	zbx_free(h->sensors);
1451 	zbx_free(h->controls);
1452 	zbx_free(h->ip);
1453 	zbx_free(h->username);
1454 	zbx_free(h->password);
1455 	zbx_free(h->err);
1456 
1457 	zbx_free(h);
1458 
1459 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1460 }
1461 
zbx_free_ipmi_handler(void)1462 void	zbx_free_ipmi_handler(void)
1463 {
1464 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1465 
1466 	while (NULL != hosts)
1467 	{
1468 		zbx_ipmi_host_t	*h;
1469 
1470 		h = hosts;
1471 		hosts = hosts->next;
1472 
1473 		zbx_free_ipmi_host(h);
1474 	}
1475 
1476 	os_hnd->free_os_handler(os_hnd);
1477 
1478 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1479 }
1480 
zbx_init_ipmi_host(const char * ip,int port,int authtype,int privilege,const char * username,const char * password)1481 static zbx_ipmi_host_t	*zbx_init_ipmi_host(const char *ip, int port, int authtype, int privilege, const char *username,
1482 		const char *password)
1483 {
1484 	zbx_ipmi_host_t		*h;
1485 	ipmi_open_option_t	options[4];
1486 
1487 	/* Although we use only one address and port we pass them in 2-element arrays. The reason is */
1488 	/* OpenIPMI v.2.0.16 - 2.0.24 file lib/ipmi_lan.c, function ipmi_lanp_setup_con() ending with loop */
1489 	/* in OpenIPMI file lib/ipmi_lan.c, function ipmi_lanp_setup_con() ending with */
1490 	/*    for (i=0; i<MAX_IP_ADDR; i++) {           */
1491 	/*        if (!ports[i])                        */
1492 	/*            ports[i] = IPMI_LAN_STD_PORT_STR; */
1493 	/*    }                                         */
1494 	/* MAX_IP_ADDR is '#define MAX_IP_ADDR 2' in OpenIPMI and not available to library users. */
1495 	/* The loop is running two times regardless of number of addresses supplied by the caller, so we use */
1496 	/* 2-element arrays to match OpenIPMI internals. */
1497 	char			*addrs[2] = {NULL}, *ports[2] = {NULL};
1498 
1499 	char			domain_name[11];	/* max int length */
1500 	int			ret;
1501 
1502 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __func__, ip, port);
1503 
1504 	/* Host already in the list? */
1505 
1506 	if (NULL != (h = zbx_get_ipmi_host(ip, port, authtype, privilege, username, password)))
1507 	{
1508 		if (1 == h->domain_up)
1509 			goto out;
1510 	}
1511 	else
1512 		h = zbx_allocate_ipmi_host(ip, port, authtype, privilege, username, password);
1513 
1514 	h->ret = SUCCEED;
1515 	h->done = 0;
1516 
1517 	addrs[0] = strdup(h->ip);
1518 	ports[0] = zbx_dsprintf(NULL, "%d", h->port);
1519 
1520 	if (0 != (ret = ipmi_ip_setup_con(addrs, ports, 1,
1521 			h->authtype == -1 ? (unsigned int)IPMI_AUTHTYPE_DEFAULT : (unsigned int)h->authtype,
1522 			(unsigned int)h->privilege, h->username, strlen(h->username),
1523 			h->password, strlen(h->password), os_hnd, NULL, &h->con)))
1524 	{
1525 		h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d."
1526 				" ipmi_ip_setup_con() returned error 0x%x",
1527 				h->ip, h->port, (unsigned int)ret);
1528 		h->ret = NETWORK_ERROR;
1529 		goto out;
1530 	}
1531 
1532 	if (0 != (ret = h->con->start_con(h->con)))
1533 	{
1534 		h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d."
1535 				" start_con() returned error 0x%x",
1536 				h->ip, h->port, (unsigned int)ret);
1537 		h->ret = NETWORK_ERROR;
1538 		goto out;
1539 	}
1540 
1541 	options[0].option = IPMI_OPEN_OPTION_ALL;
1542 	options[0].ival = 0;
1543 	options[1].option = IPMI_OPEN_OPTION_SDRS;		/* scan SDRs */
1544 	options[1].ival = 1;
1545 	options[2].option = IPMI_OPEN_OPTION_IPMB_SCAN;		/* scan IPMB bus to find out as much as possible */
1546 	options[2].ival = 1;
1547 	options[3].option = IPMI_OPEN_OPTION_LOCAL_ONLY;	/* scan only local resources */
1548 	options[3].ival = 1;
1549 
1550 	zbx_snprintf(domain_name, sizeof(domain_name), "%u", h->domain_nr);
1551 
1552 	if (0 != (ret = ipmi_open_domain(domain_name, &h->con, 1, zbx_connection_change_cb, h, zbx_domain_up_cb, h,
1553 			options, ARRSIZE(options), NULL)))
1554 	{
1555 		h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d. ipmi_open_domain() failed: %s",
1556 				h->ip, h->port, zbx_strerror(ret));
1557 		h->ret = NETWORK_ERROR;
1558 		goto out;
1559 	}
1560 
1561 	zbx_perform_openipmi_ops(h, __func__);	/* ignore returned result */
1562 out:
1563 	zbx_free(addrs[0]);
1564 	zbx_free(ports[0]);
1565 
1566 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p domain_nr:%u", __func__, (void *)h, h->domain_nr);
1567 
1568 	return h;
1569 }
1570 
1571 static ipmi_domain_id_t	domain_id;		/* global variable for passing OpenIPMI domain ID between callbacks */
1572 static int		domain_id_found;	/* A flag to indicate whether the 'domain_id' carries a valid value. */
1573 						/* Values: 0 - not found, 1 - found. The flag is used because we */
1574 						/* cannot set 'domain_id' to NULL. */
1575 static int		domain_close_ok;
1576 
1577 /* callback function invoked from OpenIPMI */
zbx_get_domain_id_by_name_cb(ipmi_domain_t * domain,void * cb_data)1578 static void	zbx_get_domain_id_by_name_cb(ipmi_domain_t *domain, void *cb_data)
1579 {
1580 	char	name[IPMI_DOMAIN_NAME_LEN], *domain_name = (char *)cb_data;
1581 
1582 	RETURN_IF_CB_DATA_NULL(cb_data, "zbx_get_domain_id_by_name_cb");
1583 
1584 	/* from 'domain' pointer find the domain name */
1585 	ipmi_domain_get_name(domain, name, sizeof(name));
1586 
1587 	/* if the domain name matches the name we are searching for then store the domain ID into global variable */
1588 	if (0 == strcmp(domain_name, name))
1589 	{
1590 		domain_id = ipmi_domain_convert_to_id(domain);
1591 		domain_id_found = 1;
1592 	}
1593 }
1594 
1595 /* callback function invoked from OpenIPMI */
zbx_domain_close_cb(ipmi_domain_t * domain,void * cb_data)1596 static void	zbx_domain_close_cb(ipmi_domain_t *domain, void *cb_data)
1597 {
1598 	zbx_ipmi_host_t	*h = (zbx_ipmi_host_t *)cb_data;
1599 	int		ret;
1600 
1601 	RETURN_IF_CB_DATA_NULL(cb_data, "zbx_domain_close_cb");
1602 
1603 	if (0 != (ret = ipmi_domain_close(domain, zbx_domain_closed_cb, h)))
1604 		zabbix_log(LOG_LEVEL_DEBUG, "cannot close IPMI domain: [0x%x]", (unsigned int)ret);
1605 	else
1606 		domain_close_ok = 1;
1607 }
1608 
zbx_close_inactive_host(zbx_ipmi_host_t * h)1609 static int	zbx_close_inactive_host(zbx_ipmi_host_t *h)
1610 {
1611 	char	domain_name[11];	/* max int length */
1612 	int	ret = FAIL;
1613 
1614 	zabbix_log(LOG_LEVEL_DEBUG, "In %s(): %s", __func__, h->ip);
1615 
1616 	zbx_snprintf(domain_name, sizeof(domain_name), "%u", h->domain_nr);
1617 
1618 	/* Search the list of domains in OpenIPMI library and find which one to close. It could happen that */
1619 	/* the domain is not found (e.g. if Zabbix allocated an IPMI host during network problem and the domain was */
1620 	/* closed by OpenIPMI library but the host is still in our 'hosts' list). */
1621 
1622 	domain_id_found = 0;
1623 	ipmi_domain_iterate_domains(zbx_get_domain_id_by_name_cb, domain_name);
1624 
1625 	h->done = 0;
1626 	domain_close_ok = 0;
1627 
1628 	if (1 == domain_id_found)
1629 	{
1630 		int	res;
1631 
1632 		if (0 != (res = ipmi_domain_pointer_cb(domain_id, zbx_domain_close_cb, h)))
1633 		{
1634 			zabbix_log(LOG_LEVEL_DEBUG, "%s(): ipmi_domain_pointer_cb() return error: %s", __func__,
1635 					zbx_strerror(res));
1636 			goto out;
1637 		}
1638 
1639 		if (1 != domain_close_ok || SUCCEED != zbx_perform_openipmi_ops(h, __func__))
1640 			goto out;
1641 	}
1642 
1643 	/* The domain was either successfully closed or not found. */
1644 	zbx_free_ipmi_host(h);
1645 	ret = SUCCEED;
1646 out:
1647 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1648 
1649 	return ret;
1650 }
1651 
zbx_delete_inactive_ipmi_hosts(time_t last_check)1652 void	zbx_delete_inactive_ipmi_hosts(time_t last_check)
1653 {
1654 	zbx_ipmi_host_t	*h = hosts, *prev = NULL, *next;
1655 
1656 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1657 
1658 	while (NULL != h)
1659 	{
1660 		if (last_check - h->lastaccess > INACTIVE_HOST_LIMIT)
1661 		{
1662 			next = h->next;
1663 
1664 			if (SUCCEED == zbx_close_inactive_host(h))
1665 			{
1666 				if (NULL == prev)
1667 					hosts = next;
1668 				else
1669 					prev->next = next;
1670 
1671 				h = next;
1672 
1673 				continue;
1674 			}
1675 		}
1676 
1677 		prev = h;
1678 		h = h->next;
1679 	}
1680 
1681 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1682 }
1683 
1684 /******************************************************************************
1685  *                                                                            *
1686  * Function: has_name_prefix                                                  *
1687  *                                                                            *
1688  * Purpose: Check if a string starts with one of predefined prefixes and      *
1689  *          set prefix length                                                 *
1690  *                                                                            *
1691  * Parameters: str        - [IN] string to examine                            *
1692  *             prefix_len - [OUT] length of the prefix                        *
1693  *                                                                            *
1694  * Return value: 1 - the string starts with the name prefix,                  *
1695  *               0 - otherwise (no prefix or other prefix was found)          *
1696  *                                                                            *
1697  ******************************************************************************/
has_name_prefix(const char * str,size_t * prefix_len)1698 static int	has_name_prefix(const char *str, size_t *prefix_len)
1699 {
1700 #define ZBX_ID_PREFIX	"id:"
1701 #define ZBX_NAME_PREFIX	"name:"
1702 
1703 	const size_t	id_len = sizeof(ZBX_ID_PREFIX) - 1, name_len = sizeof(ZBX_NAME_PREFIX) - 1;
1704 
1705 	if (0 == strncmp(str, ZBX_NAME_PREFIX, name_len))
1706 	{
1707 		*prefix_len = name_len;
1708 		return 1;
1709 	}
1710 
1711 	if (0 == strncmp(str, ZBX_ID_PREFIX, id_len))
1712 		*prefix_len = id_len;
1713 	else
1714 		*prefix_len = 0;
1715 
1716 	return 0;
1717 
1718 #undef ZBX_ID_PREFIX
1719 #undef ZBX_NAME_PREFIX
1720 }
1721 
get_value_ipmi(zbx_uint64_t itemid,const char * addr,unsigned short port,signed char authtype,unsigned char privilege,const char * username,const char * password,const char * sensor,char ** value)1722 int	get_value_ipmi(zbx_uint64_t itemid, const char *addr, unsigned short port, signed char authtype,
1723 		unsigned char privilege, const char *username, const char *password, const char *sensor, char **value)
1724 {
1725 	zbx_ipmi_host_t		*h;
1726 	zbx_ipmi_sensor_t	*s;
1727 	zbx_ipmi_control_t	*c = NULL;
1728 	size_t			offset;
1729 
1730 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() itemid:" ZBX_FS_UI64, __func__, itemid);
1731 
1732 	if (NULL == os_hnd)
1733 	{
1734 		*value = zbx_strdup(*value, "IPMI handler is not initialised.");
1735 		return CONFIG_ERROR;
1736 	}
1737 
1738 	h = zbx_init_ipmi_host(addr, port, authtype, privilege, username, password);
1739 
1740 	h->lastaccess = time(NULL);
1741 
1742 	if (0 == h->domain_up)
1743 	{
1744 		if (NULL != h->err)
1745 			*value = zbx_strdup(*value, h->err);
1746 
1747 		return h->ret;
1748 	}
1749 
1750 	if (0 == has_name_prefix(sensor, &offset))
1751 	{
1752 		if (NULL == (s = zbx_get_ipmi_sensor_by_id(h, sensor + offset)))
1753 			c = zbx_get_ipmi_control_by_name(h, sensor + offset);
1754 	}
1755 	else
1756 	{
1757 		if (NULL == (s = zbx_get_ipmi_sensor_by_full_name(h, sensor + offset)))
1758 			c = zbx_get_ipmi_control_by_full_name(h, sensor + offset);
1759 	}
1760 
1761 	if (NULL == s && NULL == c)
1762 	{
1763 		*value = zbx_dsprintf(*value, "sensor or control %s@[%s]:%d does not exist", sensor, h->ip, h->port);
1764 		return NOTSUPPORTED;
1765 	}
1766 
1767 	if (NULL != s)
1768 		zbx_read_ipmi_sensor(h, s);
1769 	else
1770 		zbx_read_ipmi_control(h, c);
1771 
1772 	if (h->ret != SUCCEED)
1773 	{
1774 		if (NULL != h->err)
1775 			*value = zbx_strdup(*value, h->err);
1776 
1777 		return h->ret;
1778 	}
1779 
1780 	if (NULL != s)
1781 	{
1782 		if (IPMI_EVENT_READING_TYPE_THRESHOLD == s->reading_type)
1783 			*value = zbx_dsprintf(*value, ZBX_FS_DBL, s->value.threshold);
1784 		else
1785 			*value = zbx_dsprintf(*value, ZBX_FS_UI64, s->value.discrete);
1786 	}
1787 
1788 	if (NULL != c)
1789 		*value = zbx_dsprintf(*value, "%d", c->val[0]);
1790 
1791 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:%s", __func__, zbx_result_string(h->ret),
1792 			ZBX_NULL2EMPTY_STR(*value));
1793 
1794 	return h->ret;
1795 }
1796 
add_threshold_ipmi(struct zbx_json * json,const char * tag,zbx_ipmi_sensor_threshold_t * threshold)1797 static void add_threshold_ipmi(struct zbx_json *json, const char *tag, zbx_ipmi_sensor_threshold_t *threshold)
1798 {
1799 	if (ZBX_IPMI_THRESHOLD_STATUS_ENABLED == threshold->status)
1800 		zbx_json_addfloat(json, tag, threshold->val);
1801 }
1802 
get_discovery_ipmi(zbx_uint64_t itemid,const char * addr,unsigned short port,signed char authtype,unsigned char privilege,const char * username,const char * password,char ** value)1803 int	get_discovery_ipmi(zbx_uint64_t itemid, const char *addr, unsigned short port, signed char authtype,
1804 		unsigned char privilege, const char *username, const char *password, char **value)
1805 {
1806 	zbx_ipmi_host_t		*h;
1807 	int 			i, j;
1808 	struct zbx_json		json;
1809 
1810 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() itemid:" ZBX_FS_UI64, __func__, itemid);
1811 
1812 	if (NULL == os_hnd)
1813 	{
1814 		*value = zbx_strdup(*value, "IPMI handler is not initialised.");
1815 		return CONFIG_ERROR;
1816 	}
1817 
1818 	h = zbx_init_ipmi_host(addr, port, authtype, privilege, username, password);
1819 
1820 	h->lastaccess = time(NULL);
1821 
1822 	if (0 == h->domain_up)
1823 	{
1824 		if (NULL != h->err)
1825 			*value = zbx_strdup(*value, h->err);
1826 
1827 		return h->ret;
1828 	}
1829 
1830 	zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
1831 
1832 	for (i = 0; i < h->sensor_count; i++)
1833 	{
1834 		const char 	*p;
1835 		char 		state_name[MAX_STRING_LEN];
1836 		size_t		offset = 0;
1837 		zbx_uint64_t	state;
1838 
1839 		zbx_read_ipmi_sensor(h, &h->sensors[i]);
1840 		if (SUCCEED != h->ret)
1841 		{
1842 			zabbix_log(LOG_LEVEL_DEBUG,"Sensor '%s' cannot be discovered. Error: %s",h->sensors[i].id,
1843 					ZBX_NULL2EMPTY_STR(h->err));
1844 
1845 			continue;
1846 		}
1847 
1848 		if (IPMI_EVENT_READING_TYPE_THRESHOLD == h->sensors[i].reading_type)
1849 		{
1850 			zbx_read_ipmi_thresholds(h, &h->sensors[i]);
1851 			if (SUCCEED != h->ret)
1852 			{
1853 				zabbix_log(LOG_LEVEL_DEBUG,"Sensor '%s' cannot be discovered. Error: %s",
1854 						h->sensors[i].id, ZBX_NULL2EMPTY_STR(h->err));
1855 
1856 				continue;
1857 			}
1858 		}
1859 
1860 		zbx_json_addobject(&json, NULL);
1861 
1862 		zbx_json_addstring(&json, ZBX_IPMI_TAG_ID, h->sensors[i].id, ZBX_JSON_TYPE_STRING);
1863 		zbx_json_addstring(&json, ZBX_IPMI_TAG_NAME, h->sensors[i].full_name, ZBX_JSON_TYPE_STRING);
1864 
1865 		zbx_json_addobject(&json, ZBX_IPMI_TAG_SENSOR);
1866 		zbx_json_adduint64(&json, ZBX_IPMI_TAG_TYPE, (zbx_uint64_t)h->sensors[i].type);
1867 		p = ipmi_sensor_get_sensor_type_string(h->sensors[i].sensor);
1868 		zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, p,	ZBX_JSON_TYPE_STRING);
1869 		zbx_json_close(&json);
1870 
1871 		zbx_json_addobject(&json, ZBX_IPMI_TAG_READING);
1872 		zbx_json_adduint64(&json, ZBX_IPMI_TAG_TYPE, (zbx_uint64_t)h->sensors[i].reading_type);
1873 		p = ipmi_sensor_get_event_reading_type_string(h->sensors[i].sensor);
1874 		zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, p,	ZBX_JSON_TYPE_STRING);
1875 		zbx_json_close(&json);
1876 
1877 		if (IPMI_EVENT_READING_TYPE_THRESHOLD != h->sensors[i].reading_type)	/* discrete */
1878 		{
1879 			state = h->sensors[i].value.discrete;
1880 			zbx_json_addobject(&json, ZBX_IPMI_TAG_STATE);
1881 			zbx_json_adduint64(&json, ZBX_IPMI_TAG_STATE, state);
1882 
1883 			state_name[0] = '\0';
1884 			for (j = 0; j < MAX_DISCRETE_STATES; j++)
1885 			{
1886 				if (0 != (state & (1u << j)))
1887 				{
1888 					if (NULL != (p = ipmi_sensor_reading_name_string(h->sensors[i].sensor, j)))
1889 					{
1890 						if (0 < offset)
1891 							offset += zbx_snprintf(state_name + offset,
1892 									sizeof(state_name) - offset,", ");
1893 						offset += zbx_snprintf(state_name + offset, sizeof(state_name) - offset,
1894 								"%s", p);
1895 					}
1896 				}
1897 			}
1898 
1899 			zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, state_name, ZBX_JSON_TYPE_STRING);
1900 			zbx_json_close(&json);
1901 		}
1902 		else	/* threshold */
1903 		{
1904 			char	*units;
1905 
1906 			state = (zbx_uint64_t)h->sensors[i].state;
1907 			zbx_json_addobject(&json, ZBX_IPMI_TAG_STATE);
1908 			zbx_json_adduint64(&json, ZBX_IPMI_TAG_STATE, state);
1909 
1910 			state_name[0] = '\0';
1911 			for (j = IPMI_LOWER_NON_CRITICAL; j <= IPMI_UPPER_NON_RECOVERABLE; j++)
1912 			{
1913 				if (0 != (state & (1u << j)))
1914 				{
1915 					if (0 < offset)
1916 						offset += zbx_snprintf(state_name + offset,
1917 								sizeof(state_name) - offset,", ");
1918 					offset += zbx_snprintf(state_name + offset, sizeof(state_name) - offset,
1919 							"%s - out of range", ipmi_get_threshold_string(j));
1920 				}
1921 			}
1922 
1923 			zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, state_name, ZBX_JSON_TYPE_STRING);
1924 			zbx_json_close(&json);
1925 
1926 			zbx_json_addfloat(&json, ZBX_IPMI_TAG_VALUE, h->sensors[i].value.threshold);
1927 
1928 			units = zbx_get_ipmi_units(h->sensors[i].sensor);
1929 			zbx_json_addstring(&json, ZBX_IPMI_TAG_UNITS, units, ZBX_JSON_TYPE_STRING);
1930 			zbx_free(units);
1931 
1932 			zbx_read_ipmi_thresholds(h, &h->sensors[i]);
1933 
1934 			zbx_json_addobject(&json, ZBX_IPMI_TAG_THRESHOLD);
1935 			zbx_json_addobject(&json, ZBX_IPMI_TAG_LOWER);
1936 
1937 			add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_CRIT,
1938 					&h->sensors[i].thresholds[IPMI_LOWER_NON_CRITICAL]);
1939 			add_threshold_ipmi(&json,ZBX_IPMI_TAG_CRIT,
1940 					&h->sensors[i].thresholds[IPMI_LOWER_CRITICAL]);
1941 			add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_RECOVER,
1942 					&h->sensors[i].thresholds[IPMI_LOWER_NON_RECOVERABLE]);
1943 
1944 			zbx_json_close(&json);
1945 
1946 			zbx_json_addobject(&json, ZBX_IPMI_TAG_UPPER);
1947 
1948 			add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_CRIT,
1949 					&h->sensors[i].thresholds[IPMI_UPPER_NON_CRITICAL]);
1950 			add_threshold_ipmi(&json,ZBX_IPMI_TAG_CRIT,
1951 					&h->sensors[i].thresholds[IPMI_UPPER_CRITICAL]);
1952 			add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_RECOVER,
1953 					&h->sensors[i].thresholds[IPMI_UPPER_NON_RECOVERABLE]);
1954 
1955 			zbx_json_close(&json);
1956 			zbx_json_close(&json);
1957 		}
1958 		zbx_json_close(&json);
1959 
1960 	}
1961 	zbx_json_close(&json);
1962 
1963 	*value = zbx_strdup(*value, json.buffer);
1964 
1965 	zbx_json_free(&json);
1966 
1967 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:%s", __func__, ZBX_NULL2EMPTY_STR(*value));
1968 
1969 	return SUCCEED;
1970 }
1971 
1972 /* function 'zbx_parse_ipmi_command' requires 'c_name' with size 'ITEM_IPMI_SENSOR_LEN_MAX' */
zbx_parse_ipmi_command(const char * command,char * c_name,int * val,char * error,size_t max_error_len)1973 int	zbx_parse_ipmi_command(const char *command, char *c_name, int *val, char *error, size_t max_error_len)
1974 {
1975 	const char	*p;
1976 	size_t		sz_c_name;
1977 	int		ret = FAIL;
1978 
1979 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() command:'%s'", __func__, command);
1980 
1981 	while ('\0' != *command && NULL != strchr(" \t", *command))
1982 		command++;
1983 
1984 	for (p = command; '\0' != *p && NULL == strchr(" \t", *p); p++)
1985 		;
1986 
1987 	if (0 == (sz_c_name = p - command))
1988 	{
1989 		zbx_strlcpy(error, "IPMI command is empty", max_error_len);
1990 		goto fail;
1991 	}
1992 
1993 	if (ITEM_IPMI_SENSOR_LEN_MAX <= sz_c_name)
1994 	{
1995 		zbx_snprintf(error, max_error_len, "IPMI command is too long [%.*s]", (int)sz_c_name, command);
1996 		goto fail;
1997 	}
1998 
1999 	memcpy(c_name, command, sz_c_name);
2000 	c_name[sz_c_name] = '\0';
2001 
2002 	while ('\0' != *p && NULL != strchr(" \t", *p))
2003 		p++;
2004 
2005 	if ('\0' == *p || 0 == strcasecmp(p, "on"))
2006 		*val = 1;
2007 	else if (0 == strcasecmp(p, "off"))
2008 		*val = 0;
2009 	else if (SUCCEED != is_uint31(p, val))
2010 	{
2011 		zbx_snprintf(error, max_error_len, "IPMI command value is not supported [%s]", p);
2012 		goto fail;
2013 	}
2014 
2015 	ret = SUCCEED;
2016 fail:
2017 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2018 
2019 	return ret;
2020 }
2021 
zbx_set_ipmi_control_value(zbx_uint64_t hostid,const char * addr,unsigned short port,signed char authtype,unsigned char privilege,const char * username,const char * password,const char * sensor,int value,char ** error)2022 int	zbx_set_ipmi_control_value(zbx_uint64_t hostid, const char *addr, unsigned short port, signed char authtype,
2023 		unsigned char privilege, const char *username, const char *password, const char *sensor,
2024 		int value, char **error)
2025 {
2026 	zbx_ipmi_host_t		*h;
2027 	zbx_ipmi_control_t	*c;
2028 	size_t			offset;
2029 
2030 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostid:" ZBX_FS_UI64 "control:%s value:%d",
2031 			__func__, hostid, sensor, value);
2032 
2033 	if (NULL == os_hnd)
2034 	{
2035 		*error = zbx_strdup(*error, "IPMI handler is not initialized.");
2036 		zabbix_log(LOG_LEVEL_DEBUG, "%s", *error);
2037 		return NOTSUPPORTED;
2038 	}
2039 
2040 	h = zbx_init_ipmi_host(addr, port, authtype, privilege, username, password);
2041 
2042 	if (0 == h->domain_up)
2043 	{
2044 		if (NULL != h->err)
2045 		{
2046 			*error = zbx_strdup(*error, h->err);
2047 			zabbix_log(LOG_LEVEL_DEBUG, "%s", h->err);
2048 		}
2049 		return h->ret;
2050 	}
2051 
2052 	if (0 == has_name_prefix(sensor, &offset))
2053 		c = zbx_get_ipmi_control_by_name(h, sensor + offset);
2054 	else
2055 		c = zbx_get_ipmi_control_by_full_name(h, sensor + offset);
2056 
2057 	if (NULL == c)
2058 	{
2059 		*error = zbx_dsprintf(*error, "Control \"%s\" at address \"%s:%d\" does not exist.", sensor, h->ip, h->port);
2060 		zabbix_log(LOG_LEVEL_DEBUG, "%s", *error);
2061 		return NOTSUPPORTED;
2062 	}
2063 
2064 	zbx_set_ipmi_control(h, c, value);
2065 
2066 	if (h->ret != SUCCEED)
2067 	{
2068 		if (NULL != h->err)
2069 		{
2070 			*error = zbx_strdup(*error, h->err);
2071 			zabbix_log(LOG_LEVEL_DEBUG, "%s", h->err);
2072 		}
2073 	}
2074 
2075 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);\
2076 
2077 	return h->ret;
2078 }
2079 
2080 #endif	/* HAVE_OPENIPMI */
2081