1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 #define _XOPEN_SOURCE 700
33 #define _GNU_SOURCE 1
34 #define _DARWIN_C_SOURCE 1
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #if defined(HAVE_CONFIG_H)
40 # include <config.h>
41 #endif
42 
43 #if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <ifaddrs.h>
49 #include <unistd.h>
50 #include <netdb.h>
51 #endif
52 
53 
54 #include <ipmitool/ipmi_intf.h>
55 #include <ipmitool/ipmi.h>
56 #include <ipmitool/ipmi_sdr.h>
57 #include <ipmitool/log.h>
58 
59 #define IPMI_DEFAULT_PAYLOAD_SIZE   25
60 
61 #ifdef IPMI_INTF_OPEN
62 extern struct ipmi_intf ipmi_open_intf;
63 #endif
64 #ifdef IPMI_INTF_IMB
65 extern struct ipmi_intf ipmi_imb_intf;
66 #endif
67 #ifdef IPMI_INTF_LIPMI
68 extern struct ipmi_intf ipmi_lipmi_intf;
69 #endif
70 #ifdef IPMI_INTF_BMC
71 extern struct ipmi_intf ipmi_bmc_intf;
72 #endif
73 #ifdef IPMI_INTF_LAN
74 extern struct ipmi_intf ipmi_lan_intf;
75 #endif
76 #ifdef IPMI_INTF_LANPLUS
77 extern struct ipmi_intf ipmi_lanplus_intf;
78 #endif
79 #ifdef IPMI_INTF_FREE
80 extern struct ipmi_intf ipmi_free_intf;
81 #endif
82 #ifdef IPMI_INTF_SERIAL
83 extern struct ipmi_intf ipmi_serial_term_intf;
84 extern struct ipmi_intf ipmi_serial_bm_intf;
85 #endif
86 #ifdef IPMI_INTF_DUMMY
87 extern struct ipmi_intf ipmi_dummy_intf;
88 #endif
89 #ifdef IPMI_INTF_USB
90 extern struct ipmi_intf ipmi_usb_intf;
91 #endif
92 
93 struct ipmi_intf * ipmi_intf_table[] = {
94 #ifdef IPMI_INTF_OPEN
95 	&ipmi_open_intf,
96 #endif
97 #ifdef IPMI_INTF_IMB
98 	&ipmi_imb_intf,
99 #endif
100 #ifdef IPMI_INTF_LIPMI
101 	&ipmi_lipmi_intf,
102 #endif
103 #ifdef IPMI_INTF_BMC
104 	&ipmi_bmc_intf,
105 #endif
106 #ifdef IPMI_INTF_LAN
107 	&ipmi_lan_intf,
108 #endif
109 #ifdef IPMI_INTF_LANPLUS
110 	&ipmi_lanplus_intf,
111 #endif
112 #ifdef IPMI_INTF_FREE
113 	&ipmi_free_intf,
114 #endif
115 #ifdef IPMI_INTF_SERIAL
116 	&ipmi_serial_term_intf,
117 	&ipmi_serial_bm_intf,
118 #endif
119 #ifdef IPMI_INTF_DUMMY
120 	&ipmi_dummy_intf,
121 #endif
122 #ifdef IPMI_INTF_USB
123 	&ipmi_usb_intf,
124 #endif
125 	NULL
126 };
127 
128 /* ipmi_intf_print  -  Print list of interfaces
129  *
130  * no meaningful return code
131  */
ipmi_intf_print(struct ipmi_intf_support * intflist)132 void ipmi_intf_print(struct ipmi_intf_support * intflist)
133 {
134 	struct ipmi_intf ** intf;
135 	struct ipmi_intf_support * sup;
136 	int def = 1;
137 	int found;
138 
139 	lprintf(LOG_NOTICE, "Interfaces:");
140 
141 	for (intf = ipmi_intf_table; intf && *intf; intf++) {
142 
143 		if (intflist != NULL) {
144 			found = 0;
145 			for (sup=intflist; sup->name != NULL; sup++) {
146 				if (strncmp(sup->name, (*intf)->name, strlen(sup->name)) == 0 &&
147 				    strncmp(sup->name, (*intf)->name, strlen((*intf)->name)) == 0 &&
148 				    sup->supported == 1)
149 					found = 1;
150 			}
151 			if (found == 0)
152 				continue;
153 		}
154 
155 		lprintf(LOG_NOTICE, "\t%-12s  %s %s",
156 			(*intf)->name, (*intf)->desc,
157 			def ? "[default]" : "");
158 		def = 0;
159 	}
160 	lprintf(LOG_NOTICE, "");
161 }
162 
163 /* ipmi_intf_load  -  Load an interface from the interface table above
164  *                    If no interface name is given return first entry
165  *
166  * @name:	interface name to try and load
167  *
168  * returns pointer to inteface structure if found
169  * returns NULL on error
170  */
ipmi_intf_load(char * name)171 struct ipmi_intf * ipmi_intf_load(char * name)
172 {
173 	struct ipmi_intf ** intf;
174 	struct ipmi_intf * i;
175 
176 	if (name == NULL) {
177 		i = ipmi_intf_table[0];
178 		if (i->setup != NULL && (i->setup(i) < 0)) {
179 			lprintf(LOG_ERR, "Unable to setup "
180 				"interface %s", name);
181 			return NULL;
182 		}
183 		return i;
184 	}
185 
186 	for (intf = ipmi_intf_table;
187 	     ((intf != NULL) && (*intf != NULL));
188 	     intf++) {
189 		i = *intf;
190 		if (strncmp(name, i->name, strlen(name)) == 0) {
191 			if (i->setup != NULL && (i->setup(i) < 0)) {
192 				lprintf(LOG_ERR, "Unable to setup "
193 					"interface %s", name);
194 				return NULL;
195 			}
196 			return i;
197 		}
198 	}
199 
200 	return NULL;
201 }
202 
203 void
ipmi_intf_session_set_hostname(struct ipmi_intf * intf,char * hostname)204 ipmi_intf_session_set_hostname(struct ipmi_intf * intf, char * hostname)
205 {
206 	if (intf->ssn_params.hostname != NULL) {
207 		free(intf->ssn_params.hostname);
208 		intf->ssn_params.hostname = NULL;
209 	}
210 	if (hostname == NULL) {
211 		return;
212 	}
213 	intf->ssn_params.hostname = strdup(hostname);
214 }
215 
216 void
ipmi_intf_session_set_username(struct ipmi_intf * intf,char * username)217 ipmi_intf_session_set_username(struct ipmi_intf * intf, char * username)
218 {
219 	memset(intf->ssn_params.username, 0, 17);
220 
221 	if (username == NULL)
222 		return;
223 
224 	memcpy(intf->ssn_params.username, username, __min(strlen(username), 16));
225 }
226 
227 void
ipmi_intf_session_set_password(struct ipmi_intf * intf,char * password)228 ipmi_intf_session_set_password(struct ipmi_intf * intf, char * password)
229 {
230 	memset(intf->ssn_params.authcode_set, 0, IPMI_AUTHCODE_BUFFER_SIZE);
231 
232 	if (password == NULL) {
233 		intf->ssn_params.password = 0;
234 		return;
235 	}
236 
237 	intf->ssn_params.password = 1;
238 	memcpy(intf->ssn_params.authcode_set, password,
239 	       __min(strlen(password), IPMI_AUTHCODE_BUFFER_SIZE));
240 }
241 
242 void
ipmi_intf_session_set_privlvl(struct ipmi_intf * intf,uint8_t level)243 ipmi_intf_session_set_privlvl(struct ipmi_intf * intf, uint8_t level)
244 {
245 	intf->ssn_params.privlvl = level;
246 }
247 
248 void
ipmi_intf_session_set_lookupbit(struct ipmi_intf * intf,uint8_t lookupbit)249 ipmi_intf_session_set_lookupbit(struct ipmi_intf * intf, uint8_t lookupbit)
250 {
251 	intf->ssn_params.lookupbit = lookupbit;
252 }
253 
254 void
ipmi_intf_session_set_cipher_suite_id(struct ipmi_intf * intf,uint8_t cipher_suite_id)255 ipmi_intf_session_set_cipher_suite_id(struct ipmi_intf * intf, uint8_t cipher_suite_id)
256 {
257 	intf->ssn_params.cipher_suite_id = cipher_suite_id;
258 }
259 
260 void
ipmi_intf_session_set_sol_escape_char(struct ipmi_intf * intf,char sol_escape_char)261 ipmi_intf_session_set_sol_escape_char(struct ipmi_intf * intf, char sol_escape_char)
262 {
263 	intf->ssn_params.sol_escape_char = sol_escape_char;
264 }
265 
266 void
ipmi_intf_session_set_kgkey(struct ipmi_intf * intf,const uint8_t * kgkey)267 ipmi_intf_session_set_kgkey(struct ipmi_intf *intf, const uint8_t *kgkey)
268 {
269 	memcpy(intf->ssn_params.kg, kgkey, IPMI_KG_BUFFER_SIZE);
270 }
271 
272 void
ipmi_intf_session_set_port(struct ipmi_intf * intf,int port)273 ipmi_intf_session_set_port(struct ipmi_intf * intf, int port)
274 {
275 	intf->ssn_params.port = port;
276 }
277 
278 void
ipmi_intf_session_set_authtype(struct ipmi_intf * intf,uint8_t authtype)279 ipmi_intf_session_set_authtype(struct ipmi_intf * intf, uint8_t authtype)
280 {
281 	/* clear password field if authtype NONE specified */
282 	if (authtype == IPMI_SESSION_AUTHTYPE_NONE) {
283 		memset(intf->ssn_params.authcode_set, 0, IPMI_AUTHCODE_BUFFER_SIZE);
284 		intf->ssn_params.password = 0;
285 	}
286 
287 	intf->ssn_params.authtype_set = authtype;
288 }
289 
290 void
ipmi_intf_session_set_timeout(struct ipmi_intf * intf,uint32_t timeout)291 ipmi_intf_session_set_timeout(struct ipmi_intf * intf, uint32_t timeout)
292 {
293 	intf->ssn_params.timeout = timeout;
294 }
295 
296 void
ipmi_intf_session_set_retry(struct ipmi_intf * intf,int retry)297 ipmi_intf_session_set_retry(struct ipmi_intf * intf, int retry)
298 {
299 	intf->ssn_params.retry = retry;
300 }
301 
302 void
ipmi_intf_session_cleanup(struct ipmi_intf * intf)303 ipmi_intf_session_cleanup(struct ipmi_intf *intf)
304 {
305 	if (intf->session == NULL) {
306 		return;
307 	}
308 
309 	free(intf->session);
310 	intf->session = NULL;
311 }
312 
313 void
ipmi_cleanup(struct ipmi_intf * intf)314 ipmi_cleanup(struct ipmi_intf * intf)
315 {
316 	ipmi_sdr_list_empty(intf);
317 	ipmi_intf_session_set_hostname(intf, NULL);
318 }
319 
320 #if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
321 int
ipmi_intf_socket_connect(struct ipmi_intf * intf)322 ipmi_intf_socket_connect(struct ipmi_intf * intf)
323 {
324 	struct ipmi_session_params *params;
325 
326 	struct sockaddr_storage addr;
327 	struct addrinfo hints;
328 	struct addrinfo *rp0 = NULL, *rp;
329 	char service[NI_MAXSERV];
330 
331 	if (!intf) {
332 		return -1;
333 	}
334 
335 	params = &intf->ssn_params;
336 
337 	if (params->hostname == NULL || strlen((const char *)params->hostname) == 0) {
338 		lprintf(LOG_ERR, "No hostname specified!");
339 		return -1;
340 	}
341 
342 	/* open port to BMC */
343 	memset(&addr, 0, sizeof(addr));
344 
345 	sprintf(service, "%d", params->port);
346 	/* Obtain address(es) matching host/port */
347 	memset(&hints, 0, sizeof(hints));
348 	hints.ai_family   = intf->ai_family;    /* Allow IPv4 or IPv6 */
349 	hints.ai_socktype = SOCK_DGRAM;   /* Datagram socket */
350 	hints.ai_flags    = 0;            /* use AI_NUMERICSERV for no name resolution */
351 	hints.ai_protocol = IPPROTO_UDP; /*  */
352 
353 	if (getaddrinfo(params->hostname, service, &hints, &rp0) != 0) {
354 		lprintf(LOG_ERR, "Address lookup for %s failed",
355 				params->hostname);
356 		return -1;
357 	}
358 
359 	/* getaddrinfo() returns a list of address structures.
360 	 * Try each address until we successfully connect(2).
361 	 * If socket(2) (or connect(2)) fails, we (close the socket
362 	 * and) try the next address.
363 	 */
364 
365 	for (rp = rp0; rp != NULL; rp = rp->ai_next) {
366 		/* We are only interested in IPv4 and IPv6 */
367 		if ((rp->ai_family != AF_INET6) && (rp->ai_family != AF_INET)) {
368 			continue;
369 		}
370 
371 		intf->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
372 		if (intf->fd == -1) {
373 			continue;
374 		}
375 
376 		if (rp->ai_family == AF_INET) {
377 			if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
378 				hints.ai_family = rp->ai_family;
379 				break;  /* Success */
380 			}
381 		}  else if (rp->ai_family == AF_INET6) {
382 			struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)rp->ai_addr;
383 			char hbuf[NI_MAXHOST];
384 			socklen_t len;
385 
386 			/* The scope was specified on the command line e.g. with -H FE80::219:99FF:FEA0:BD95%eth0 */
387 			if (addr6->sin6_scope_id != 0) {
388 				len = sizeof(struct sockaddr_in6);
389 				if (getnameinfo((struct sockaddr *)addr6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) {
390 					lprintf(LOG_DEBUG, "Trying address: %s scope=%d",
391 						hbuf,
392 						addr6->sin6_scope_id);
393 				}
394 				if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
395 					hints.ai_family = rp->ai_family;
396 					break;  /* Success */
397 				}
398 			} else {
399 				/* No scope specified, try to get this from the list of interfaces */
400 				struct ifaddrs *ifaddrs = NULL;
401 				struct ifaddrs *ifa = NULL;
402 
403 				if (getifaddrs(&ifaddrs) < 0) {
404 					lprintf(LOG_ERR, "Interface address lookup for %s failed",
405 						params->hostname);
406 					break;
407 				}
408 
409 				for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
410 					if (ifa->ifa_addr == NULL) {
411 						continue;
412 					}
413 
414 					if (ifa->ifa_addr->sa_family == AF_INET6) {
415 						struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)ifa->ifa_addr;
416 
417 						/* Skip unwanted addresses */
418 						if (IN6_IS_ADDR_MULTICAST(&tmp6->sin6_addr)) {
419 							continue;
420 						}
421 						if (IN6_IS_ADDR_LOOPBACK(&tmp6->sin6_addr)) {
422 							continue;
423 						}
424 						len = sizeof(struct sockaddr_in6);
425 						if ( getnameinfo((struct sockaddr *)tmp6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) {
426 							lprintf(LOG_DEBUG, "Testing %s interface address: %s scope=%d",
427 								ifa->ifa_name != NULL ? ifa->ifa_name : "???",
428 								hbuf,
429 								tmp6->sin6_scope_id);
430 						}
431 
432 						if (tmp6->sin6_scope_id != 0) {
433 							addr6->sin6_scope_id = tmp6->sin6_scope_id;
434 						} else {
435 							/*
436 							 * No scope information in interface address information
437 							 * On some OS'es, getifaddrs() is returning out the 'kernel' representation
438 							 * of scoped addresses which stores the scope in the 3rd and 4th
439 							 * byte. See also this page:
440 							 * http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html
441 							 */
442 							if (IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr)
443 									&& (tmp6->sin6_addr.s6_addr[1] != 0)) {
444 								addr6->sin6_scope_id = ntohs(tmp6->sin6_addr.s6_addr[1]);
445 							}
446 						}
447 
448 						/* OK, now try to connect with the scope id from this interface address */
449 						if (addr6->sin6_scope_id != 0 || !IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr)) {
450 							if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
451 								hints.ai_family = rp->ai_family;
452 								lprintf(LOG_DEBUG, "Successful connected on %s interface with scope id %d", ifa->ifa_name, tmp6->sin6_scope_id);
453 								break;  /* Success */
454 							}
455 						}
456 					}
457 				}
458 				freeifaddrs(ifaddrs);
459 			}
460 		}
461 		if (hints.ai_family != AF_UNSPEC) {
462 			break;
463 		}
464 		close(intf->fd);
465 		intf->fd = -1;
466 	}
467 
468 	/* No longer needed */
469 	freeaddrinfo(rp0);
470 
471 	return ((intf->fd != -1) ? 0 : -1);
472 }
473 #endif
474 
475 uint16_t
ipmi_intf_get_max_request_data_size(struct ipmi_intf * intf)476 ipmi_intf_get_max_request_data_size(struct ipmi_intf * intf)
477 {
478 	int16_t size;
479 
480 	size = intf->max_request_data_size;
481 
482 	/* check if request size is not specified */
483 	if (!size) {
484 		/*
485 		 * The IPMB standard overall message length for �non -bridging�
486 		 * messages is specified as 32 bytes, maximum, including slave
487 		 * address. This sets the upper limit for typical IPMI messages.
488 		 * With the exception of messages used for bridging messages to
489 		 * other busses or interfaces (e.g. Master Write-Read and Send Message)
490 		 * IPMI messages should be designed to fit within this 32-byte maximum.
491 		 * In order to support bridging, the Master Write -Read and Send Message
492 		 * commands are allowed to exceed the 32-byte maximum transaction on IPMB
493 		 */
494 
495 		size = IPMI_DEFAULT_PAYLOAD_SIZE;
496 
497 		/* check if message is forwarded */
498 		if (intf->target_addr && intf->target_addr != intf->my_addr) {
499 			/* add Send Message request size */
500 			size += 8;
501 		}
502 	}
503 
504 	/* check if message is forwarded */
505 	if (intf->target_addr && intf->target_addr != intf->my_addr) {
506 		/* subtract send message request size */
507 		size -= 8;
508 
509 		/*
510 		 * Check that forwarded request size is not greater
511 		 * than the default payload size.
512 		 */
513 		if (size > IPMI_DEFAULT_PAYLOAD_SIZE) {
514 			size = IPMI_DEFAULT_PAYLOAD_SIZE;
515 		}
516 
517 		/* check for double bridging */
518 		if (intf->transit_addr && intf->transit_addr != intf->target_addr) {
519 			/* subtract inner send message request size */
520 			size -= 8;
521 		}
522 	}
523 
524 	/* check for underflow */
525 	if (size < 0) {
526 		return 0;
527 	}
528 
529 	return size;
530 }
531 
532 uint16_t
ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf)533 ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf)
534 {
535 	int16_t size;
536 
537 	size = intf->max_response_data_size;
538 
539 	/* check if response size is not specified */
540 	if (!size) {
541 		/*
542 		 * The IPMB standard overall message length for �non -bridging�
543 		 * messages is specified as 32 bytes, maximum, including slave
544 		 * address. This sets the upper limit for typical IPMI messages.
545 		 * With the exception of messages used for bridging messages to
546 		 * other busses or interfaces (e.g. Master Write-Read and Send Message)
547 		 * IPMI messages should be designed to fit within this 32-byte maximum.
548 		 * In order to support bridging, the Master Write -Read and Send Message
549 		 * commands are allowed to exceed the 32-byte maximum transaction on IPMB
550 		 */
551 
552 		size = IPMI_DEFAULT_PAYLOAD_SIZE; /* response length with subtracted header and checksum byte */
553 
554 		/* check if message is forwarded */
555 		if (intf->target_addr && intf->target_addr != intf->my_addr) {
556 			/* add Send Message header size */
557 			size += 7;
558 		}
559 	}
560 
561 	/* check if message is forwarded */
562 	if (intf->target_addr && intf->target_addr != intf->my_addr) {
563 		/*
564 		 * Some IPMI controllers like PICMG AMC Carriers embed responses
565 		 * to the forwarded messages into the Send Message response.
566 		 * In order to be sure that the response is not truncated,
567 		 * subtract the internal message header size.
568 		 */
569 		size -= 8;
570 
571 		/*
572 		 * Check that forwarded response is not greater
573 		 * than the default payload size.
574 		 */
575 		if (size > IPMI_DEFAULT_PAYLOAD_SIZE) {
576 			size = IPMI_DEFAULT_PAYLOAD_SIZE;
577 		}
578 
579 		/* check for double bridging */
580 		if (intf->transit_addr && intf->transit_addr != intf->target_addr) {
581 			/* subtract inner send message header size */
582 			size -= 8;
583 		}
584 	}
585 
586 	/* check for underflow */
587 	if (size < 0) {
588 		return 0;
589 	}
590 
591 	return size;
592 }
593 
594 void
ipmi_intf_set_max_request_data_size(struct ipmi_intf * intf,uint16_t size)595 ipmi_intf_set_max_request_data_size(struct ipmi_intf * intf, uint16_t size)
596 {
597 	if (size < IPMI_DEFAULT_PAYLOAD_SIZE) {
598 		lprintf(LOG_ERR, "Request size is too small (%d), leave default size",
599 				size);
600 		return;
601 	}
602 
603 	if (intf->set_max_request_data_size) {
604 		intf->set_max_request_data_size(intf, size);
605 	} else {
606 		intf->max_request_data_size = size;
607 	}
608 }
609 
610 void
ipmi_intf_set_max_response_data_size(struct ipmi_intf * intf,uint16_t size)611 ipmi_intf_set_max_response_data_size(struct ipmi_intf * intf, uint16_t size)
612 {
613 	if (size < IPMI_DEFAULT_PAYLOAD_SIZE - 1) {
614 		lprintf(LOG_ERR, "Response size is too small (%d), leave default size",
615 				size);
616 		return;
617 	}
618 
619 	if (intf->set_max_response_data_size) {
620 		intf->set_max_response_data_size(intf, size);
621 	} else {
622 		intf->max_response_data_size = size;
623 	}
624 }
625