xref: /openbmc/ipmitool/lib/ipmi_sol.c (revision 2d79e69f)
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 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/select.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <signal.h>
43 #include <unistd.h>
44 
45 #if defined(HAVE_CONFIG_H)
46 # include <config.h>
47 #endif
48 
49 #if defined(HAVE_TERMIOS_H)
50 # include <termios.h>
51 #elif defined (HAVE_SYS_TERMIOS_H)
52 # include <sys/termios.h>
53 #endif
54 
55 #include <ipmitool/helper.h>
56 #include <ipmitool/log.h>
57 #include <ipmitool/ipmi.h>
58 #include <ipmitool/ipmi_intf.h>
59 #include <ipmitool/ipmi_sol.h>
60 #include <ipmitool/ipmi_strings.h>
61 #include <ipmitool/bswap.h>
62 
63 
64 #define SOL_PARAMETER_SET_IN_PROGRESS           0x00
65 #define SOL_PARAMETER_SOL_ENABLE                0x01
66 #define SOL_PARAMETER_SOL_AUTHENTICATION        0x02
67 #define SOL_PARAMETER_CHARACTER_INTERVAL        0x03
68 #define SOL_PARAMETER_SOL_RETRY                 0x04
69 #define SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE 0x05
70 #define SOL_PARAMETER_SOL_VOLATILE_BIT_RATE     0x06
71 #define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL       0x07
72 #define SOL_PARAMETER_SOL_PAYLOAD_PORT          0x08
73 
74 #define MAX_SOL_RETRY 6
75 
76 const struct valstr sol_parameter_vals[] = {
77 	{ SOL_PARAMETER_SET_IN_PROGRESS,           "Set In Progress (0)" },
78 	{ SOL_PARAMETER_SOL_ENABLE,                "Enable (1)" },
79 	{ SOL_PARAMETER_SOL_AUTHENTICATION,        "Authentication (2)" },
80 	{ SOL_PARAMETER_CHARACTER_INTERVAL,        "Character Interval (3)" },
81 	{ SOL_PARAMETER_SOL_RETRY,                 "Retry (4)" },
82 	{ SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE, "Nonvolatile Bitrate (5)" },
83 	{ SOL_PARAMETER_SOL_VOLATILE_BIT_RATE,     "Volatile Bitrate (6)" },
84 	{ SOL_PARAMETER_SOL_PAYLOAD_CHANNEL,       "Payload Channel (7)" },
85 	{ SOL_PARAMETER_SOL_PAYLOAD_PORT,          "Payload Port (8)" },
86 	{ 0x00, NULL },
87 };
88 
89 
90 static struct timeval _start_keepalive;
91 static struct termios _saved_tio;
92 static int            _in_raw_mode = 0;
93 static int            _disable_keepalive = 0;
94 static int            _use_sol_for_keepalive = 0;
95 static int            _keepalive_retries = 0;
96 
97 extern int verbose;
98 
99 /*
100  * ipmi_sol_payload_access
101  */
102 int
ipmi_sol_payload_access(struct ipmi_intf * intf,uint8_t channel,uint8_t userid,int enable)103 ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel,
104 		uint8_t userid, int enable)
105 {
106 	struct ipmi_rq req;
107 	struct ipmi_rs *rsp;
108 	int rc = (-1);
109 	uint8_t data[6];
110 
111 	memset(&req, 0, sizeof(req));
112 	req.msg.netfn = IPMI_NETFN_APP;
113 	req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS;
114 	req.msg.data = data;
115 	req.msg.data_len = 6;
116 
117 	memset(data, 0, 6);
118 	/* channel */
119 	data[0] = channel & 0xf;
120 	/* user id */
121 	data[1] = userid & 0x3f;
122 	if (!enable) {
123 		/* disable */
124 		data[1] |= 0x40;
125 	}
126 	/* payload 1 is SOL */
127 	data[2] = 0x02;
128 	rsp = intf->sendrecv(intf, &req);
129 	if (rsp == NULL) {
130 		lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d",
131 				enable ? "en" : "dis", userid, channel);
132 		rc = (-1);
133 	} else if (rsp->ccode != 0) {
134 		lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s",
135 				enable ? "en" : "dis", userid, channel,
136 				val2str(rsp->ccode, completion_code_vals));
137 		rc = (-1);
138 	} else {
139 		rc = 0;
140 	}
141 	return rc;
142 }
143 
144 int
ipmi_sol_payload_access_status(struct ipmi_intf * intf,uint8_t channel,uint8_t userid)145 ipmi_sol_payload_access_status(struct ipmi_intf * intf,
146 				uint8_t channel,
147 				uint8_t userid)
148 {
149 	struct ipmi_rq req;
150 	struct ipmi_rs *rsp;
151 	uint8_t data[2];
152 
153 	memset(&req, 0, sizeof(req));
154 	req.msg.netfn    = IPMI_NETFN_APP;
155 	req.msg.cmd      = IPMI_GET_USER_PAYLOAD_ACCESS;
156 	req.msg.data     = data;
157 	req.msg.data_len = sizeof(data);
158 
159 	data[0] = channel & 0xf;	/* channel */
160 	data[1] = userid & 0x3f;	/* user id */
161 	rsp = intf->sendrecv(intf, &req);
162 
163 	if (rsp == NULL) {
164 		lprintf(LOG_ERR, "Error. No valid response received.");
165 		return -1;
166 	}
167 
168 	switch(rsp->ccode) {
169 		case 0x00:
170 			if (rsp->data_len != 4) {
171 				lprintf(LOG_ERR, "Error parsing SOL payload status for user %d on channel %d",
172 					userid, channel);
173 				return -1;
174 			}
175 
176 			printf("User %d on channel %d is %sabled\n",
177 				userid, channel, (rsp->data[0] & 0x02) ? "en":"dis");
178 			return 0;
179 
180 		default:
181 			lprintf(LOG_ERR, "Error getting SOL payload status for user %d on channel %d: %s",
182 				userid, channel,
183 				val2str(rsp->ccode, completion_code_vals));
184 			return -1;
185 	}
186 }
187 
188 
189 /*
190  * ipmi_get_sol_info
191  */
192 int
ipmi_get_sol_info(struct ipmi_intf * intf,uint8_t channel,struct sol_config_parameters * params)193 ipmi_get_sol_info(
194 				  struct ipmi_intf * intf,
195 				  uint8_t channel,
196 				  struct sol_config_parameters * params)
197 {
198 	struct ipmi_rs * rsp;
199 	struct ipmi_rq req;
200 	uint8_t data[4];
201 
202 	memset(&req, 0, sizeof(req));
203 	req.msg.netfn    = IPMI_NETFN_TRANSPORT;
204 	req.msg.cmd      = IPMI_GET_SOL_CONFIG_PARAMETERS;
205 	req.msg.data_len = 4;
206 	req.msg.data     = data;
207 
208 	/*
209 	 * set in progress
210 	 */
211 	memset(data, 0, sizeof(data));
212 	data[0] = channel;                       /* channel number     */
213 	data[1] = SOL_PARAMETER_SET_IN_PROGRESS; /* parameter selector */
214 	data[2] = 0x00;                          /* set selector       */
215 	data[3] = 0x00;                          /* block selector     */
216 
217 	rsp = intf->sendrecv(intf, &req);
218 	if (rsp == NULL) {
219 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
220 				val2str(data[1], sol_parameter_vals));
221 		return (-1);
222 	}
223 
224 	switch (rsp->ccode) {
225 		case 0x00:
226 			if (rsp->data_len == 2) {
227 				params->set_in_progress = rsp->data[1];
228 			} else {
229 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
230 						"for SOL parameter '%s'",
231 						rsp->data_len,
232 						val2str(data[1], sol_parameter_vals));
233 			}
234 			break;
235 		case 0x80:
236 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
237 					val2str(data[1], sol_parameter_vals));
238 			break;
239 		default:
240 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
241 				val2str(data[1], sol_parameter_vals),
242 				val2str(rsp->ccode, completion_code_vals));
243 			return (-1);
244 	}
245 
246 	/*
247 	 * SOL enable
248 	 */
249 	memset(data, 0, sizeof(data));
250 	data[0] = channel;                  /* channel number     */
251 	data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */
252 	data[2] = 0x00;                     /* set selector       */
253 	data[3] = 0x00;                     /* block selector     */
254 
255 	rsp = intf->sendrecv(intf, &req);
256 	if (rsp == NULL) {
257 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
258 				val2str(data[1], sol_parameter_vals));
259 		return (-1);
260 	}
261 
262 	switch (rsp->ccode) {
263 		case 0x00:
264 			if (rsp->data_len == 2) {
265 				params->enabled = rsp->data[1];
266 			} else {
267 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
268 						"for SOL parameter '%s'",
269 						rsp->data_len,
270 						val2str(data[1], sol_parameter_vals));
271 			}
272 			break;
273 		case 0x80:
274 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
275 					val2str(data[1], sol_parameter_vals));
276 			break;
277 		default:
278 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
279 				val2str(data[1], sol_parameter_vals),
280 				val2str(rsp->ccode, completion_code_vals));
281 			return (-1);
282 	}
283 
284 	/*
285 	 * SOL authentication
286 	 */
287 	memset(data, 0, sizeof(data));
288 	data[0] = channel;                          /* channel number     */
289 	data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */
290 	data[2] = 0x00;                             /* set selector       */
291 	data[3] = 0x00;                             /* block selector     */
292 
293 	rsp = intf->sendrecv(intf, &req);
294 	if (rsp == NULL) {
295 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
296 				val2str(data[1], sol_parameter_vals));
297 		return (-1);
298 	}
299 
300 	switch (rsp->ccode) {
301 		case 0x00:
302 			if (rsp->data_len == 2) {
303 				params->force_encryption     = ((rsp->data[1] & 0x80)? 1 : 0);
304 				params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0);
305 				params->privilege_level      = rsp->data[1] & 0x0F;
306 			} else {
307 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
308 						"for SOL parameter '%s'",
309 						rsp->data_len,
310 						val2str(data[1], sol_parameter_vals));
311 			}
312 			break;
313 		case 0x80:
314 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
315 					val2str(data[1], sol_parameter_vals));
316 			break;
317 		default:
318 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
319 				val2str(data[1], sol_parameter_vals),
320 				val2str(rsp->ccode, completion_code_vals));
321 			return (-1);
322 	}
323 
324 	/*
325 	 * Character accumulate interval and character send interval
326 	 */
327 	memset(data, 0, sizeof(data));
328 	data[0] = channel;                          /* channel number     */
329 	data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */
330 	data[2] = 0x00;                             /* set selector       */
331 	data[3] = 0x00;                             /* block selector     */
332 
333 	rsp = intf->sendrecv(intf, &req);
334 	if (rsp == NULL) {
335 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
336 				val2str(data[1], sol_parameter_vals));
337 		return (-1);
338 	}
339 
340 	switch (rsp->ccode) {
341 		case 0x00:
342 			if (rsp->data_len == 3) {
343 				params->character_accumulate_level = rsp->data[1];
344 				params->character_send_threshold   = rsp->data[2];
345 			} else {
346 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
347 						"for SOL parameter '%s'",
348 						rsp->data_len,
349 						val2str(data[1], sol_parameter_vals));
350 			}
351 			break;
352 		case 0x80:
353 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
354 					val2str(data[1], sol_parameter_vals));
355 			break;
356 		default:
357 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
358 				val2str(data[1], sol_parameter_vals),
359 				val2str(rsp->ccode, completion_code_vals));
360 			return (-1);
361 	}
362 
363 	/*
364 	 * SOL retry
365 	 */
366 	memset(data, 0, sizeof(data));
367 	data[0] = channel;                 /* channel number     */
368 	data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */
369 	data[2] = 0x00;                    /* set selector       */
370 	data[3] = 0x00;                    /* block selector     */
371 
372 	rsp = intf->sendrecv(intf, &req);
373 	if (rsp == NULL) {
374 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
375 				val2str(data[1], sol_parameter_vals));
376 		return (-1);
377 	}
378 
379 	switch (rsp->ccode) {
380 		case 0x00:
381 			if (rsp->data_len == 3) {
382 				params->retry_count    = rsp->data[1];
383 				params->retry_interval = rsp->data[2];
384 			} else {
385 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
386 						"for SOL parameter '%s'",
387 						rsp->data_len,
388 						val2str(data[1], sol_parameter_vals));
389 			}
390 			break;
391 		case 0x80:
392 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
393 					val2str(data[1], sol_parameter_vals));
394 			break;
395 		default:
396 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
397 				val2str(data[1], sol_parameter_vals),
398 				val2str(rsp->ccode, completion_code_vals));
399 			return (-1);
400 	}
401 
402 	/*
403 	 * SOL non-volatile bit rate
404 	 */
405 	memset(data, 0, sizeof(data));
406 	data[0] = channel;                                 /* channel number     */
407 	data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */
408 	data[2] = 0x00;                                    /* set selector       */
409 	data[3] = 0x00;                                    /* block selector     */
410 
411 	rsp = intf->sendrecv(intf, &req);
412 	if (rsp == NULL) {
413 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
414 				val2str(data[1], sol_parameter_vals));
415 		return (-1);
416 	}
417 
418 	switch (rsp->ccode) {
419 		case 0x00:
420 			if (rsp->data_len == 2) {
421 				params->non_volatile_bit_rate = rsp->data[1] & 0x0F;
422 			} else {
423 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
424 						"for SOL parameter '%s'",
425 						rsp->data_len,
426 						val2str(data[1], sol_parameter_vals));
427 			}
428 			break;
429 		case 0x80:
430 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
431 					val2str(data[1], sol_parameter_vals));
432 			break;
433 		default:
434 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
435 				val2str(data[1], sol_parameter_vals),
436 				val2str(rsp->ccode, completion_code_vals));
437 			return (-1);
438 	}
439 
440 	/*
441 	 * SOL volatile bit rate
442 	 */
443 	memset(data, 0, sizeof(data));
444 	data[0] = channel;                             /* channel number     */
445 	data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */
446 	data[2] = 0x00;                                /* set selector       */
447 	data[3] = 0x00;                                /* block selector     */
448 
449 	rsp = intf->sendrecv(intf, &req);
450 	if (rsp == NULL) {
451 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
452 				val2str(data[1], sol_parameter_vals));
453 		return (-1);
454 	}
455 
456 	switch (rsp->ccode) {
457 		case 0x00:
458 			if (rsp->data_len == 2) {
459 				params->volatile_bit_rate = rsp->data[1] & 0x0F;
460 			} else {
461 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
462 						"for SOL parameter '%s'",
463 						rsp->data_len,
464 						val2str(data[1], sol_parameter_vals));
465 			}
466 			break;
467 		case 0x80:
468 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
469 					val2str(data[1], sol_parameter_vals));
470 			break;
471 		default:
472 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
473 				val2str(data[1], sol_parameter_vals),
474 				val2str(rsp->ccode, completion_code_vals));
475 			return (-1);
476 	}
477 
478 	/*
479 	 * SOL payload channel
480 	 */
481 	memset(data, 0, sizeof(data));
482 	data[0] = channel;                           /* channel number     */
483 	data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */
484 	data[2] = 0x00;                              /* set selector       */
485 	data[3] = 0x00;                              /* block selector     */
486 
487 	rsp = intf->sendrecv(intf, &req);
488 	if (rsp == NULL) {
489 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
490 				val2str(data[1], sol_parameter_vals));
491 		return (-1);
492 	}
493 
494 	switch (rsp->ccode) {
495 		case 0x00:
496 			if (rsp->data_len == 2) {
497 				params->payload_channel = rsp->data[1];
498 			} else {
499 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
500 						"for SOL parameter '%s'",
501 						rsp->data_len,
502 						val2str(data[1], sol_parameter_vals));
503 			}
504 			break;
505 		case 0x80:
506 			lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x",
507 					val2str(data[1], sol_parameter_vals), channel);
508 			params->payload_channel = channel;
509 			break;
510 		default:
511 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
512 					val2str(data[1], sol_parameter_vals),
513 					val2str(rsp->ccode, completion_code_vals));
514 			return (-1);
515 	}
516 
517 	/*
518 	 * SOL payload port
519 	 */
520 	memset(data, 0, sizeof(data));
521 	data[0] = channel;                        /* channel number     */
522 	data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */
523 	data[2] = 0x00;                           /* set selector       */
524 	data[3] = 0x00;                           /* block selector     */
525 
526 	rsp = intf->sendrecv(intf, &req);
527 	if (rsp == NULL) {
528 		lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
529 				val2str(data[1], sol_parameter_vals));
530 		return (-1);
531 	}
532 
533 	switch (rsp->ccode) {
534 		case 0x00:
535 			if (rsp->data_len == 3) {
536 				params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8);
537 			} else {
538 				lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
539 						"for SOL parameter '%s'",
540 						rsp->data_len,
541 						val2str(data[1], sol_parameter_vals));
542 			}
543 			break;
544 		case 0x80:
545 			if( intf->session != NULL ) {
546 				lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d",
547 						val2str(data[1], sol_parameter_vals), intf->ssn_params.port);
548 				params->payload_port = intf->ssn_params.port;
549 			} else {
550 				lprintf(LOG_ERR,
551 						"Info: SOL parameter '%s' not supported - can't determine which "
552 						"payload port to use on NULL session",
553 						val2str(data[1], sol_parameter_vals));
554 						return (-1);
555 			}
556 			break;
557 		default:
558 			lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
559 				val2str(data[1], sol_parameter_vals),
560 				val2str(rsp->ccode, completion_code_vals));
561 			return (-1);
562 	}
563 
564 	return 0;
565 }
566 
567 
568 
569 /*
570  * ipmi_print_sol_info
571  */
572 static int
ipmi_print_sol_info(struct ipmi_intf * intf,uint8_t channel)573 ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel)
574 {
575 	struct sol_config_parameters params = {0};
576 	if (ipmi_get_sol_info(intf, channel, &params))
577 		return -1;
578 
579 	if (csv_output)
580 	{
581 		printf("%s,",
582 			   val2str(params.set_in_progress & 0x03,
583 					   ipmi_set_in_progress_vals));
584 		printf("%s,", params.enabled?"true": "false");
585 		printf("%s,", params.force_encryption?"true":"false");
586 		printf("%s,", params.force_encryption?"true":"false");
587 		printf("%s,",
588 			   val2str(params.privilege_level, ipmi_privlvl_vals));
589 		printf("%d,", params.character_accumulate_level * 5);
590 		printf("%d,", params.character_send_threshold);
591 		printf("%d,", params.retry_count);
592 		printf("%d,", params.retry_interval * 10);
593 
594 		printf("%s,",
595 			   val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
596 
597 		printf("%s,",
598 			   val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
599 
600 		printf("%d,", params.payload_channel);
601 		printf("%d\n", params.payload_port);
602 	}
603 	else
604 	{
605 		printf("Set in progress                 : %s\n",
606 			   val2str(params.set_in_progress & 0x03,
607 					   ipmi_set_in_progress_vals));
608 		printf("Enabled                         : %s\n",
609 			   params.enabled?"true": "false");
610 		printf("Force Encryption                : %s\n",
611 			   params.force_encryption?"true":"false");
612 		printf("Force Authentication            : %s\n",
613 			   params.force_authentication?"true":"false");
614 		printf("Privilege Level                 : %s\n",
615 			   val2str(params.privilege_level, ipmi_privlvl_vals));
616 		printf("Character Accumulate Level (ms) : %d\n",
617 			   params.character_accumulate_level * 5);
618 		printf("Character Send Threshold        : %d\n",
619 			   params.character_send_threshold);
620 		printf("Retry Count                     : %d\n",
621 			   params.retry_count);
622 		printf("Retry Interval (ms)             : %d\n",
623 			   params.retry_interval * 10);
624 
625 		printf("Volatile Bit Rate (kbps)        : %s\n",
626 			   val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
627 
628 		printf("Non-Volatile Bit Rate (kbps)    : %s\n",
629 			   val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
630 
631 		printf("Payload Channel                 : %d (0x%02x)\n",
632 			   params.payload_channel, params.payload_channel);
633 		printf("Payload Port                    : %d\n",
634 			   params.payload_port);
635 	}
636 
637 	return 0;
638 }
639 
640 
641 
642 /*
643  * Small function to validate that user-supplied SOL
644  * configuration parameter values we store in uint8_t
645  * data type falls within valid range.  With minval
646  * and maxval parameters we can use the same function
647  * to validate parameters that have different ranges
648  * of values.
649  *
650  * function will return -1 if value is not valid, or
651  * will return 0 if valid.
652  */
ipmi_sol_set_param_isvalid_uint8_t(const char * strval,const char * name,int base,uint8_t minval,uint8_t maxval,uint8_t * out_value)653 int ipmi_sol_set_param_isvalid_uint8_t( const char *strval,
654 					const char *name,
655 					int base,
656 					uint8_t minval,
657 					uint8_t maxval,
658 					uint8_t *out_value)
659 {
660 	if (str2uchar(strval, out_value) != 0 || (*out_value < minval)
661 			|| (*out_value > maxval)) {
662 		lprintf(LOG_ERR, "Invalid value %s for parameter %s",
663 			strval, name);
664 		lprintf(LOG_ERR, "Valid values are %d-%d", minval, maxval);
665 		return -1;
666 	}
667 	return 0;
668 }
669 
670 
671 /*
672  * ipmi_sol_set_param
673  *
674  * Set the specified Serial Over LAN value to the specified
675  * value
676  *
677  * return 0 on success,
678  *        -1 on failure
679  */
680 static int
ipmi_sol_set_param(struct ipmi_intf * intf,uint8_t channel,const char * param,const char * value,uint8_t guarded)681 ipmi_sol_set_param(struct ipmi_intf * intf,
682 		   uint8_t            channel,
683 		   const char       * param,
684 		   const char       * value,
685 		   uint8_t            guarded)
686 {
687 	struct ipmi_rs * rsp;
688 	struct ipmi_rq   req;
689 	uint8_t          data[4];
690 	int              bGuarded = guarded; /* Use set-in-progress indicator? */
691 
692 	memset(&req, 0, sizeof(req));
693 	req.msg.netfn    = IPMI_NETFN_TRANSPORT;           /* 0x0c */
694 	req.msg.cmd      = IPMI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */
695 	req.msg.data     = data;
696 
697 	data[0] = channel;
698 
699 	/*
700 	 * set-in-progress
701 	 */
702 	if (! strcmp(param, "set-in-progress"))
703 	{
704 		bGuarded = 0; /* We _ARE_ the set-in-progress indicator */
705 		req.msg.data_len = 3;
706 		data[1] = SOL_PARAMETER_SET_IN_PROGRESS;
707 
708 		if (! strcmp(value, "set-complete"))
709 			data[2] = 0x00;
710 		else if (! strcmp(value, "set-in-progress"))
711 			data[2] = 0x01;
712 		else if (! strcmp(value, "commit-write"))
713 			data[2] = 0x02;
714 		else
715 		{
716 			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
717 				   value, param);
718 			lprintf(LOG_ERR, "Valid values are set-complete, set-in-progress "
719 				   "and commit-write");
720 			return -1;
721 		}
722 	}
723 
724 
725 	/*
726 	 * enabled
727 	 */
728 	else if (! strcmp(param, "enabled"))
729 	{
730 		req.msg.data_len = 3;
731 		data[1] = SOL_PARAMETER_SOL_ENABLE;
732 
733 		if (! strcmp(value, "true"))
734 			data[2] = 0x01;
735 		else if (! strcmp(value, "false"))
736 			data[2] = 0x00;
737 		else
738 		{
739 			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
740 				   value, param);
741 			lprintf(LOG_ERR, "Valid values are true and false");
742 			return -1;
743 		}
744 	}
745 
746 
747 	/*
748 	 * force-payload-encryption
749 	 */
750 	else if (! strcmp(param, "force-encryption"))
751 	{
752 		struct sol_config_parameters params;
753 
754 		req.msg.data_len = 3;
755 		data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
756 
757 		if (! strcmp(value, "true"))
758 			data[2] = 0x80;
759 		else if (! strcmp(value, "false"))
760 			data[2] = 0x00;
761 		else
762 		{
763 			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
764 				   value, param);
765 			lprintf(LOG_ERR, "Valid values are true and false");
766 			return -1;
767 		}
768 
769 
770 		/* We need other values to complete the request */
771 		if (ipmi_get_sol_info(intf, channel, &params))
772 		{
773 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
774 				   param);
775 			return -1;
776 		}
777 
778 		data[2] |= params.force_authentication? 0x40 : 0x00;
779 		data[2] |= params.privilege_level;
780 	}
781 
782 
783 	/*
784 	 * force-payload-authentication
785 	 */
786 	else if (! strcmp(param, "force-authentication"))
787 	{
788 		struct sol_config_parameters params;
789 
790 		req.msg.data_len = 3;
791 		data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
792 
793 		if (! strcmp(value, "true"))
794 			data[2] = 0x40;
795 		else if (! strcmp(value, "false"))
796 			data[2] = 0x00;
797 		else
798 		{
799 			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
800 				   value, param);
801 			lprintf(LOG_ERR, "Valid values are true and false");
802 			return -1;
803 		}
804 
805 
806 		/* We need other values to complete the request */
807 		if (ipmi_get_sol_info(intf, channel, &params))
808 		{
809 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
810 				   param);
811 			return -1;
812 		}
813 
814 		data[2] |= params.force_encryption? 0x80 : 0x00;
815 		data[2] |= params.privilege_level;
816 	}
817 
818 
819 	/*
820 	 * privilege-level
821 	 */
822 	else if (! strcmp(param, "privilege-level"))
823 	{
824 		struct sol_config_parameters params;
825 
826 		req.msg.data_len = 3;
827 		data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
828 
829 		if (! strcmp(value, "user"))
830 			data[2] = 0x02;
831 		else if (! strcmp(value, "operator"))
832 			data[2] = 0x03;
833 		else if (! strcmp(value, "admin"))
834 			data[2] = 0x04;
835 		else if (! strcmp(value, "oem"))
836 			data[2] = 0x05;
837 		else
838 		{
839 			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
840 				   value, param);
841 			lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
842 			return -1;
843 		}
844 
845 
846 		/* We need other values to complete the request */
847 		if (ipmi_get_sol_info(intf, channel, &params))
848 		{
849 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
850 				   param);
851 			return -1;
852 		}
853 
854 		data[2] |= params.force_encryption?     0x80 : 0x00;
855 		data[2] |= params.force_authentication? 0x40 : 0x00;
856 	}
857 
858 
859 	/*
860 	 * character-accumulate-level
861 	 */
862 	else if (! strcmp(param, "character-accumulate-level"))
863 	{
864 		struct sol_config_parameters params;
865 
866 		req.msg.data_len = 4;
867 		data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
868 
869 		/* validate user-supplied input */
870 		if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 1, 255, &data[2]))
871 			return -1;
872 
873 		/* We need other values to complete the request */
874 		if (ipmi_get_sol_info(intf, channel, &params))
875 		{
876 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
877 				   param);
878 			return -1;
879 		}
880 
881 		data[3] = params.character_send_threshold;
882 	}
883 
884 
885 	/*
886 	 * character-send-threshold
887 	 */
888 	else if (! strcmp(param, "character-send-threshold"))
889 	{
890 		struct sol_config_parameters params;
891 
892 		req.msg.data_len = 4;
893 		data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
894 
895 		/* validate user-supplied input */
896 		if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
897 			return -1;
898 
899 		/* We need other values to complete the request */
900 		if (ipmi_get_sol_info(intf, channel, &params))
901 		{
902 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
903 				   param);
904 			return -1;
905 		}
906 
907 		data[2] = params.character_accumulate_level;
908 	}
909 
910 
911 	/*
912 	 * retry-count
913 	 */
914 	else if (! strcmp(param, "retry-count"))
915 	{
916 		struct sol_config_parameters params;
917 
918 		req.msg.data_len = 4;
919 		data[1] = SOL_PARAMETER_SOL_RETRY;
920 
921 		/* validate user input, 7 is max value */
922 		if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 7, &data[2]))
923 			return -1;
924 
925 		/* We need other values to complete the request */
926 		if (ipmi_get_sol_info(intf, channel, &params))
927 		{
928 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
929 				   param);
930 			return -1;
931 		}
932 
933 		data[3] = params.retry_interval;
934 	}
935 
936 
937 	/*
938 	 * retry-interval
939 	 */
940 	else if (! strcmp(param, "retry-interval"))
941 	{
942 		struct sol_config_parameters params;
943 
944 		req.msg.data_len = 4;
945 		data[1] = SOL_PARAMETER_SOL_RETRY;
946 
947 		/* validate user-supplied input */
948 		if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
949 			return -1;
950 
951 		/* We need other values to complete the request */
952 		if (ipmi_get_sol_info(intf, channel, &params))
953 		{
954 			lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
955 				   param);
956 			return -1;
957 		}
958 
959 		data[2] = params.retry_count;
960 	}
961 
962 
963 	/*
964 	 * non-volatile-bit-rate
965 	 */
966 	else if (! strcmp(param, "non-volatile-bit-rate"))
967 	{
968 		req.msg.data_len = 3;
969 		data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE;
970 
971 		if (!strcmp(value, "serial"))
972 		{
973 			data[2] = 0x00;
974 		}
975 		else if (!strcmp(value, "9.6"))
976 		{
977 			data[2] = 0x06;
978 		}
979 		else if (!strcmp(value, "19.2"))
980 		{
981 			data[2] = 0x07;
982 		}
983 		else if (!strcmp(value, "38.4"))
984 		{
985 			data[2] = 0x08;
986 		}
987 		else if (!strcmp(value, "57.6"))
988 		{
989 			data[2] = 0x09;
990 		}
991 		else if (!strcmp(value, "115.2"))
992 		{
993 			data[2] = 0x0A;
994 		}
995 		else
996 		{
997 			lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
998 				   value,
999 				   param);
1000 			lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
1001 			return -1;
1002 		}
1003 	}
1004 
1005 
1006 	/*
1007 	 * volatile-bit-rate
1008 	 */
1009 	else if (! strcmp(param, "volatile-bit-rate"))
1010 	{
1011 		req.msg.data_len = 3;
1012 		data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE;
1013 
1014 		if (!strcmp(value, "serial"))
1015 		{
1016 			data[2] = 0x00;
1017 		}
1018 		else if (!strcmp(value, "9.6"))
1019 		{
1020 			data[2] = 0x06;
1021 		}
1022 		else if (!strcmp(value, "19.2"))
1023 		{
1024 			data[2] = 0x07;
1025 		}
1026 		else if (!strcmp(value, "38.4"))
1027 		{
1028 			data[2] = 0x08;
1029 		}
1030 		else if (!strcmp(value, "57.6"))
1031 		{
1032 			data[2] = 0x09;
1033 		}
1034 		else if (!strcmp(value, "115.2"))
1035 		{
1036 			data[2] = 0x0A;
1037 		}
1038 		else
1039 		{
1040 			lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
1041 				   value,
1042 				   param);
1043 			lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
1044 			return -1;
1045 		}
1046 	}
1047 	else
1048 	{
1049 		lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param);
1050 		return -1;
1051 	}
1052 
1053 
1054 	/*
1055 	 * Execute the request
1056 	 */
1057 	if (bGuarded &&
1058 		(ipmi_sol_set_param(intf,
1059 				    channel,
1060 				    "set-in-progress",
1061 				    "set-in-progress",
1062 				    bGuarded)))
1063 	{
1064 		lprintf(LOG_ERR, "Error: set of parameter \"%s\" failed", param);
1065 		return -1;
1066 	}
1067 
1068 
1069 	/* The command proper */
1070 	rsp = intf->sendrecv(intf, &req);
1071 
1072 	if (rsp == NULL) {
1073 		lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param);
1074 		return -1;
1075 	}
1076 
1077 	if (!(!strncmp(param, "set-in-progress", 15) && !strncmp(value, "commit-write", 12)) &&
1078 	    rsp->ccode > 0) {
1079 		switch (rsp->ccode) {
1080 		case 0x80:
1081 			lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1082 				"Parameter not supported", param);
1083 			break;
1084 		case 0x81:
1085 			lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1086 				"Attempt to set set-in-progress when not in set-complete state",
1087 				param);
1088 			break;
1089 		case 0x82:
1090 			lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1091 				"Attempt to write read-only parameter", param);
1092 			break;
1093 		case 0x83:
1094 			lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1095 				"Attempt to read write-only parameter", param);
1096 			break;
1097 		default:
1098 			lprintf(LOG_ERR, "Error setting SOL parameter '%s' to '%s': %s",
1099 				param, value, val2str(rsp->ccode, completion_code_vals));
1100 			break;
1101 		}
1102 
1103 		if (bGuarded &&
1104 			(ipmi_sol_set_param(intf,
1105 					    channel,
1106 					    "set-in-progress",
1107 					    "set-complete",
1108 					    bGuarded)))
1109 		{
1110 			lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
1111 				   "to \"set-complete\"");
1112 		}
1113 
1114 		return -1;
1115 	}
1116 
1117 
1118 	/*
1119 	 * The commit write could very well fail, but that's ok.
1120 	 * It may not be implemented.
1121 	 */
1122 	if (bGuarded)
1123 		ipmi_sol_set_param(intf,
1124 				   channel,
1125 				   "set-in-progress",
1126 				   "commit-write",
1127 				   bGuarded);
1128 
1129 
1130 	if (bGuarded &&
1131  		ipmi_sol_set_param(intf,
1132 				   channel,
1133 				   "set-in-progress",
1134 				   "set-complete",
1135 				   bGuarded))
1136 	{
1137 		lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
1138 			   "to \"set-complete\"");
1139 		return -1;
1140 	}
1141 
1142 	return 0;
1143 }
1144 
1145 
1146 
1147 void
leave_raw_mode(void)1148 leave_raw_mode(void)
1149 {
1150 	if (!_in_raw_mode)
1151 		return;
1152 	if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
1153 		perror("tcsetattr");
1154 	else
1155 		_in_raw_mode = 0;
1156 }
1157 
1158 
1159 
1160 void
enter_raw_mode(void)1161 enter_raw_mode(void)
1162 {
1163 	struct termios tio;
1164 	if (tcgetattr(fileno(stdin), &tio) == -1) {
1165 		perror("tcgetattr");
1166 		return;
1167 	}
1168 	_saved_tio = tio;
1169 	tio.c_iflag |= IGNPAR;
1170 	tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
1171 	tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
1172 	//	#ifdef IEXTEN
1173 	tio.c_lflag &= ~IEXTEN;
1174 	//	#endif
1175 	tio.c_oflag &= ~OPOST;
1176 	tio.c_cc[VMIN] = 1;
1177 	tio.c_cc[VTIME] = 0;
1178 	if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
1179 		perror("tcsetattr");
1180 	else
1181 		_in_raw_mode = 1;
1182 }
1183 
1184 
1185 static void
sendBreak(struct ipmi_intf * intf)1186 sendBreak(struct ipmi_intf * intf)
1187 {
1188 	struct ipmi_v2_payload  v2_payload;
1189 
1190 	memset(&v2_payload, 0, sizeof(v2_payload));
1191 
1192 	v2_payload.payload.sol_packet.character_count = 0;
1193 	v2_payload.payload.sol_packet.generate_break  = 1;
1194 
1195 	intf->send_sol(intf, &v2_payload);
1196 }
1197 
1198 
1199 
1200 /*
1201  * suspendSelf
1202  *
1203  * Put ourself in the background
1204  *
1205  * param bRestoreTty specifies whether we will put our self back
1206  *       in raw mode when we resume
1207  */
1208 static void
suspendSelf(int bRestoreTty)1209 suspendSelf(int bRestoreTty)
1210 {
1211 	leave_raw_mode();
1212 	kill(getpid(), SIGTSTP);
1213 
1214 	if (bRestoreTty)
1215 		enter_raw_mode();
1216 }
1217 
1218 
1219 
1220 /*
1221  * printSolEscapeSequences
1222  *
1223  * Send some useful documentation to the user
1224  */
1225 static void
printSolEscapeSequences(struct ipmi_intf * intf)1226 printSolEscapeSequences(struct ipmi_intf * intf)
1227 {
1228 	printf(
1229 		   "%c?\n\
1230 	Supported escape sequences:\n\
1231 	%c.  - terminate connection\n\
1232 	%c^Z - suspend ipmitool\n\
1233 	%c^X - suspend ipmitool, but don't restore tty on restart\n\
1234 	%cB  - send break\n\
1235 	%c?  - this message\n\
1236 	%c%c  - send the escape character by typing it twice\n\
1237 	(Note that escapes are only recognized immediately after newline.)\n",
1238 		   intf->ssn_params.sol_escape_char,
1239 		   intf->ssn_params.sol_escape_char,
1240 		   intf->ssn_params.sol_escape_char,
1241 		   intf->ssn_params.sol_escape_char,
1242 		   intf->ssn_params.sol_escape_char,
1243 		   intf->ssn_params.sol_escape_char,
1244 		   intf->ssn_params.sol_escape_char,
1245 		   intf->ssn_params.sol_escape_char);
1246 }
1247 
1248 
1249 
1250 /*
1251  * output
1252  *
1253  * Send the specified data to stdout
1254  */
1255 static void
output(struct ipmi_rs * rsp)1256 output(struct ipmi_rs * rsp)
1257 {
1258 	/* Add checks to make sure it is actually SOL data, in general I see
1259 	 * outside code mostly trying to guard against this happening, but
1260 	 * some places fail to do so, so I do so here to make sure nothing gets
1261 	 * through.  If non-sol data comes through here, there is probably
1262 	 * a packet that won't get processed somewhere else, but the alternative
1263 	 * of outputting corrupt data is worse.  Generally I see the get device
1264 	 * id response make it here somehow.  I assume it is a heartbeat and the
1265 	 * other code will retry if it cares about the response and misses it.
1266 	 */
1267 	if (rsp &&
1268 	    (rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
1269 	    (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
1270 	{
1271 		int i;
1272 
1273 		for (i = 0; i < rsp->data_len; ++i)
1274 			putc(rsp->data[i], stdout);
1275 
1276 		fflush(stdout);
1277 	}
1278 }
1279 
1280 
1281 
1282 /*
1283  * ipmi_sol_deactivate
1284  */
1285 static int
ipmi_sol_deactivate(struct ipmi_intf * intf,int instance)1286 ipmi_sol_deactivate(struct ipmi_intf * intf, int instance)
1287 {
1288 	struct ipmi_rs * rsp;
1289 	struct ipmi_rq   req;
1290 	uint8_t          data[6];
1291 
1292 	if ((instance <= 0) || (instance > 15)) {
1293 		lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
1294 		return -1;
1295 	}
1296 
1297 	memset(&req, 0, sizeof(req));
1298 	req.msg.netfn    = IPMI_NETFN_APP;
1299 	req.msg.cmd      = IPMI_DEACTIVATE_PAYLOAD;
1300 	req.msg.data_len = 6;
1301 	req.msg.data     = data;
1302 
1303 	memset(data, 0, sizeof(data));
1304 	data[0] = IPMI_PAYLOAD_TYPE_SOL;  /* payload type      */
1305 	data[1] = instance;               /* payload instance. */
1306 
1307 	/* Lots of important data */
1308 	data[2] = 0;
1309 	data[3] = 0;
1310 	data[4] = 0;
1311 	data[5] = 0;
1312 
1313 	rsp = intf->sendrecv(intf, &req);
1314 
1315 	if (NULL != rsp) {
1316 		switch (rsp->ccode) {
1317 			case 0x00:
1318 				return 0;
1319 			case 0x80:
1320 				lprintf(LOG_ERR, "Info: SOL payload already de-activated");
1321 				break;
1322 			case 0x81:
1323 				lprintf(LOG_ERR, "Info: SOL payload type disabled");
1324 				break;
1325 			default:
1326 				lprintf(LOG_ERR, "Error de-activating SOL payload: %s",
1327 					val2str(rsp->ccode, completion_code_vals));
1328 				break;
1329 		}
1330 	} else {
1331 		lprintf(LOG_ERR, "Error: No response de-activating SOL payload");
1332 	}
1333 
1334 	return -1;
1335 }
1336 
1337 
1338 
1339 /*
1340  * processSolUserInput
1341  *
1342  * Act on user input into the SOL session.  The only reason this
1343  * is complicated is that we have to process escape sequences.
1344  *
1345  * return   0 on success
1346  *          1 if we should exit
1347  *        < 0 on error (BMC probably closed the session)
1348  */
1349 static int
processSolUserInput(struct ipmi_intf * intf,uint8_t * input,uint16_t buffer_length)1350 processSolUserInput(
1351 					struct ipmi_intf * intf,
1352 					uint8_t    * input,
1353 					uint16_t   buffer_length)
1354 {
1355 	static int escape_pending = 0;
1356 	static int last_was_cr    = 1;
1357 	struct ipmi_v2_payload v2_payload;
1358 	int  length               = 0;
1359 	int  retval               = 0;
1360 	char ch;
1361 	int  i;
1362 
1363 	memset(&v2_payload, 0, sizeof(v2_payload));
1364 
1365 	/*
1366 	 * Our first order of business is to check the input for escape
1367 	 * sequences to act on.
1368 	 */
1369 	for (i = 0; i < buffer_length; ++i)
1370 	{
1371 		ch = input[i];
1372 
1373 		if (escape_pending){
1374 			escape_pending = 0;
1375 
1376 			/*
1377 			 * Process a possible escape sequence.
1378 			 */
1379 			switch (ch) {
1380 			case '.':
1381 				printf("%c. [terminated ipmitool]\n",
1382 				       intf->ssn_params.sol_escape_char);
1383 				retval = 1;
1384 				break;
1385 
1386 			case 'Z' - 64:
1387 				printf("%c^Z [suspend ipmitool]\n",
1388 				       intf->ssn_params.sol_escape_char);
1389 				suspendSelf(1); /* Restore tty back to raw */
1390 				continue;
1391 
1392 			case 'X' - 64:
1393 				printf("%c^Z [suspend ipmitool]\n",
1394 				       intf->ssn_params.sol_escape_char);
1395 				suspendSelf(0); /* Don't restore to raw mode */
1396 				continue;
1397 
1398 			case 'B':
1399 				printf("%cB [send break]\n",
1400 				       intf->ssn_params.sol_escape_char);
1401 				sendBreak(intf);
1402 				continue;
1403 
1404 			case '?':
1405 				printSolEscapeSequences(intf);
1406 				continue;
1407 
1408 			default:
1409 				if (ch != intf->ssn_params.sol_escape_char)
1410 					v2_payload.payload.sol_packet.data[length++] =
1411 						intf->ssn_params.sol_escape_char;
1412 				v2_payload.payload.sol_packet.data[length++] = ch;
1413 			}
1414 		}
1415 
1416 		else
1417 		{
1418 			if (last_was_cr && (ch == intf->ssn_params.sol_escape_char)) {
1419 				escape_pending = 1;
1420 				continue;
1421 			}
1422 
1423 			v2_payload.payload.sol_packet.data[length++] =	ch;
1424 		}
1425 
1426 
1427 		/*
1428 		 * Normal character.  Record whether it was a newline.
1429 		 */
1430 		last_was_cr = (ch == '\r' || ch == '\n');
1431 	}
1432 
1433 
1434 	/*
1435 	 * If there is anything left to process we dispatch it to the BMC,
1436 	 * send intf->session->sol_data.max_outbound_payload_size bytes
1437 	 * at a time.
1438 	 */
1439 	if (length)
1440 	{
1441 		struct ipmi_rs * rsp = NULL;
1442 		int try = 0;
1443 
1444 		while (try < intf->ssn_params.retry) {
1445 
1446 			v2_payload.payload.sol_packet.character_count = length;
1447 
1448 			rsp = intf->send_sol(intf, &v2_payload);
1449 
1450 			if (rsp)
1451 			{
1452 				break;
1453 			}
1454 
1455 			usleep(5000);
1456 			try++;
1457 		}
1458 
1459 		if (! rsp)
1460 		{
1461 			lprintf(LOG_ERR, "Error sending SOL data: FAIL");
1462 			retval = -1;
1463 		}
1464 
1465 		/* If the sequence number is set we know we have new data */
1466 		if (retval == 0)
1467 			if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
1468 			    (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)        &&
1469 			    (rsp->payload.sol_packet.packet_sequence_number))
1470 				output(rsp);
1471 	}
1472 
1473 	return retval;
1474 }
1475 
1476 static int
ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf)1477 ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf)
1478 {
1479 	struct ipmi_v2_payload v2_payload;
1480 	struct timeval end;
1481 
1482 	if (_disable_keepalive)
1483 		return 0;
1484 
1485 	gettimeofday(&end, 0);
1486 
1487 	if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
1488 		memset(&v2_payload, 0, sizeof(v2_payload));
1489 		v2_payload.payload.sol_packet.character_count = 0;
1490 		if (intf->send_sol(intf, &v2_payload) == NULL)
1491 			return -1;
1492 		/* good return, reset start time */
1493 		gettimeofday(&_start_keepalive, 0);
1494 	}
1495 	return 0;
1496 }
1497 
1498 static int
ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf)1499 ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf)
1500 {
1501 	struct timeval  end;
1502 
1503 	if (_disable_keepalive)
1504 		return 0;
1505 
1506 	gettimeofday(&end, 0);
1507 
1508 	if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
1509 		if (intf->keepalive(intf) != 0)
1510          		return -1;
1511 		/* good return, reset start time */
1512 		gettimeofday(&_start_keepalive, 0);
1513    	}
1514 	return 0;
1515 }
1516 
1517 
1518 
1519 /*
1520  * ipmi_sol_red_pill
1521  */
1522 static int
ipmi_sol_red_pill(struct ipmi_intf * intf,int instance)1523 ipmi_sol_red_pill(struct ipmi_intf * intf, int instance)
1524 {
1525 	char   * buffer;
1526 	int    numRead;
1527 	int    bShouldExit       = 0;
1528 	int    bBmcClosedSession = 0;
1529 	fd_set read_fds;
1530 	struct timeval tv;
1531 	int    retval;
1532 	int    buffer_size = intf->session->sol_data.max_inbound_payload_size;
1533 	int    keepAliveRet = 0;
1534 	int    retrySol = 0;
1535 
1536 	/* Subtract SOL header from max_inbound_payload_size */
1537 	if (buffer_size > 4)
1538 		buffer_size -= 4;
1539 
1540 	buffer = (char*)malloc(buffer_size);
1541 	if (buffer == NULL) {
1542 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1543 		return -1;
1544 	}
1545 
1546 	/* Initialize keepalive start time */
1547 	gettimeofday(&_start_keepalive, 0);
1548 
1549 	enter_raw_mode();
1550 
1551 	while (! bShouldExit)
1552 	{
1553 		FD_ZERO(&read_fds);
1554 		FD_SET(0, &read_fds);
1555 		FD_SET(intf->fd, &read_fds);
1556 
1557 		if (!ipmi_oem_active(intf,"i82571spt"))
1558 		{
1559 			/* Send periodic keepalive packet */
1560 			if(_use_sol_for_keepalive == 0)
1561 			{
1562 				keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf);
1563 			}
1564 			else
1565 			{
1566 				keepAliveRet = ipmi_sol_keepalive_using_sol(intf);
1567 			}
1568 
1569 			if (keepAliveRet != 0)
1570 			{
1571 				/*
1572 				 * Retrying the keep Alive before declaring a communication
1573 				 * lost state with the IPMC. Helpful when the payload is
1574 				 * reset and brings down the connection temporarily. Otherwise,
1575 				 * if we send getDevice Id to check the status of IPMC during
1576 				 * this down time when the connection is restarting, SOL will
1577 				 * exit even though the IPMC is available and the session is open.
1578 				 */
1579 				if (retrySol == MAX_SOL_RETRY)
1580 				{
1581 					/* no response to Get Device ID keepalive message */
1582 					bShouldExit = 1;
1583 					continue;
1584 				}
1585 				else
1586 				{
1587 					retrySol++;
1588 				}
1589 			}
1590 			else
1591 			{
1592 				/* if the keep Alive is successful reset retries to zero */
1593 				retrySol = 0;
1594 			}
1595 		} /* !oem="i82571spt" */
1596 		/* Wait up to half a second */
1597 		tv.tv_sec =  0;
1598 		tv.tv_usec = 500000;
1599 
1600 		retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv);
1601 
1602 		if (retval)
1603 		{
1604 			if (retval == -1)
1605 			{
1606 				/* ERROR */
1607 				perror("select");
1608 				return -1;
1609 			}
1610 
1611 
1612 			/*
1613 			 * Process input from the user
1614 			 */
1615 			if (FD_ISSET(0, &read_fds))
1616 	 		{
1617 				memset(buffer, 0, buffer_size);
1618 				numRead = read(fileno(stdin),
1619 							   buffer,
1620 							   buffer_size);
1621 
1622 				if (numRead > 0)
1623 				{
1624 					int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead);
1625 
1626 					if (rc)
1627 					{
1628 						if (rc < 0)
1629 							bShouldExit = bBmcClosedSession = 1;
1630 						else
1631 							bShouldExit = 1;
1632 					}
1633 				}
1634 				else
1635 				{
1636 					bShouldExit = 1;
1637 				}
1638 			}
1639 
1640 
1641 			/*
1642 			 * Process input from the BMC
1643 			 */
1644 			else if (FD_ISSET(intf->fd, &read_fds))
1645 			{
1646 				struct ipmi_rs * rs =intf->recv_sol(intf);
1647 				if ( rs)
1648 				{
1649 					output(rs);
1650 				}
1651 				/*
1652 				 * Should recv_sol come back null, the incoming packet was not ours.
1653 				 * Just fall through, the keepalive logic will determine if
1654 				 * the BMC has dropped the session.
1655 				 */
1656  			}
1657 
1658 
1659 			/*
1660 			 * ERROR in select
1661 			 */
1662  			else
1663 			{
1664 				lprintf(LOG_ERR, "Error: Select returned with nothing to read");
1665 				bShouldExit = 1;
1666 			}
1667 		}
1668 	}
1669 
1670 	leave_raw_mode();
1671 
1672 	if (keepAliveRet != 0)
1673 	{
1674 		lprintf(LOG_ERR, "Error: No response to keepalive - Terminating session");
1675 		/* attempt to clean up anyway */
1676 		ipmi_sol_deactivate(intf, instance);
1677 		exit(1);
1678 	}
1679 
1680 	if (bBmcClosedSession)
1681 	{
1682 		lprintf(LOG_ERR, "SOL session closed by BMC");
1683 		exit(1);
1684 	}
1685 	else
1686 		ipmi_sol_deactivate(intf, instance);
1687 
1688 	return 0;
1689 }
1690 
1691 
1692 
1693 
1694 /*
1695  * ipmi_sol_activate
1696  */
1697 static int
ipmi_sol_activate(struct ipmi_intf * intf,int looptest,int interval,int instance)1698 ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval,
1699 		int instance)
1700 {
1701 	struct ipmi_rs * rsp;
1702 	struct ipmi_rq   req;
1703 	struct activate_payload_rsp ap_rsp;
1704 	uint8_t    data[6];
1705 	uint8_t    bSolEncryption     = 1;
1706 	uint8_t    bSolAuthentication = 1;
1707 
1708 	/*
1709 	 * This command is only available over RMCP+ (the lanplus
1710 	 * interface).
1711 	 */
1712 	if (strncmp(intf->name, "lanplus", 7) != 0)
1713 	{
1714 		lprintf(LOG_ERR, "Error: This command is only available over the "
1715 			   "lanplus interface");
1716 		return -1;
1717 	}
1718 
1719 	if ((instance <= 0) || (instance > 15)) {
1720 		lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
1721 		return -1;
1722 	}
1723 
1724 
1725 	/*
1726 	 * Setup a callback so that the lanplus processing knows what
1727 	 * to do with packets that come unexpectedly (while waiting for
1728 	 * an ACK, perhaps.
1729 	 */
1730 	intf->session->sol_data.sol_input_handler = output;
1731 
1732 
1733 	memset(&req, 0, sizeof(req));
1734 	req.msg.netfn    = IPMI_NETFN_APP;
1735 	req.msg.cmd      = IPMI_ACTIVATE_PAYLOAD;
1736 	req.msg.data_len = 6;
1737 	req.msg.data     = data;
1738 
1739 	data[0] = IPMI_PAYLOAD_TYPE_SOL;  /* payload type     */
1740 	data[1] = instance;               /* payload instance */
1741 
1742 	/* Lots of important data.  Most is default */
1743 	data[2]  = bSolEncryption?     0x80 : 0;
1744 	data[2] |= bSolAuthentication? 0x40 : 0;
1745 	data[2] |= IPMI_SOL_SERIAL_ALERT_MASK_DEFERRED;
1746 
1747 	if (ipmi_oem_active(intf, "intelplus")) {
1748 		data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE;
1749 	} else if (ipmi_oem_active(intf, "i82571spt")) {
1750 		/*
1751 		 * A quote from Intel: "Engineering believes the problem
1752 		 * lies within the Auxiliary data being sent with the
1753 		 * 'Activate Payload' command from IPMITool.  IPMITool
1754 		 * sends a C6h which sets some bits having to do with
1755 		 * encryption and some behavior dealing with CTS DCD/DSR.
1756 		 * I recommend that the customer modify this request
1757 		 * to send 08h instead. This is what our internal utility
1758 		 * sends and it works without issue. I will work with
1759 		 * engineering to ensure the settings that IPMITool uses
1760 		 * (C6h) are supported in the future.
1761 		 */
1762 		data[2] = 0x08;
1763 	} else {
1764 		data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE;
1765 	}
1766 
1767 	data[3] = 0x00; /* reserved */
1768 	data[4] = 0x00; /* reserved */
1769 	data[5] = 0x00; /* reserved */
1770 
1771 	rsp = intf->sendrecv(intf, &req);
1772 
1773 	if (NULL != rsp) {
1774 		switch (rsp->ccode) {
1775 			case 0x00:
1776 				if (rsp->data_len == 12) {
1777 					break;
1778 				} else {
1779 					lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
1780 						   "in payload activation response",
1781 						   rsp->data_len);
1782 					return -1;
1783 				}
1784 				break;
1785 			case 0x80:
1786 				lprintf(LOG_ERR, "Info: SOL payload already active on another session");
1787 				return -1;
1788 			case 0x81:
1789 				lprintf(LOG_ERR, "Info: SOL payload disabled");
1790 				return -1;
1791 			case 0x82:
1792 				lprintf(LOG_ERR, "Info: SOL payload activation limit reached");
1793 				return -1;
1794 			case 0x83:
1795 				lprintf(LOG_ERR, "Info: cannot activate SOL payload with encryption");
1796 				return -1;
1797 			case 0x84:
1798 				lprintf(LOG_ERR, "Info: cannot activate SOL payload without encryption");
1799 				return -1;
1800 			default:
1801 				lprintf(LOG_ERR, "Error activating SOL payload: %s",
1802 					val2str(rsp->ccode, completion_code_vals));
1803 				return -1;
1804 		}
1805 	} else {
1806 		lprintf(LOG_ERR, "Error: No response activating SOL payload");
1807 		return -1;
1808 	}
1809 
1810 
1811 	memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp));
1812 
1813 	intf->session->sol_data.max_inbound_payload_size =
1814 		(ap_rsp.inbound_payload_size[1] << 8) |
1815 		ap_rsp.inbound_payload_size[0];
1816 
1817 	intf->session->sol_data.max_outbound_payload_size =
1818 		(ap_rsp.outbound_payload_size[1] << 8) |
1819 		ap_rsp.outbound_payload_size[0];
1820 
1821 	intf->session->sol_data.port =
1822 		(ap_rsp.payload_udp_port[1] << 8) |
1823 		ap_rsp.payload_udp_port[0];
1824 
1825 	intf->session->timeout = 1;
1826 
1827 
1828 	/* NOTE: the spec does allow for SOL traffic to be sent on
1829 	 * a different port.  we do not yet support that feature. */
1830 	if (intf->session->sol_data.port != intf->ssn_params.port)
1831 	{
1832 		/* try byteswapping port in case BMC sent it incorrectly */
1833 		uint16_t portswap = BSWAP_16(intf->session->sol_data.port);
1834 
1835 		if (portswap == intf->ssn_params.port) {
1836 			intf->session->sol_data.port = portswap;
1837 		}
1838 		else {
1839 			lprintf(LOG_ERR, "Error: BMC requests SOL session on different port");
1840 			return -1;
1841 		}
1842 	}
1843 
1844 	printf("[SOL Session operational.  Use %c? for help]\n",
1845 	       intf->ssn_params.sol_escape_char);
1846 
1847 	if(looptest == 1)
1848 	{
1849 		ipmi_sol_deactivate(intf, instance);
1850 		usleep(interval*1000);
1851 		return 0;
1852 	}
1853 
1854 	/*
1855 	 * At this point we are good to go with our SOL session.  We
1856 	 * need to listen to
1857 	 * 1) STDIN for user input
1858 	 * 2) The FD for incoming SOL packets
1859 	 */
1860 	if (ipmi_sol_red_pill(intf, instance))
1861 	{
1862 		lprintf(LOG_ERR, "Error in SOL session");
1863 		return -1;
1864 	}
1865 
1866 	return 0;
1867 }
1868 
1869 
1870 
1871 /*
1872  * print_sol_usage
1873  */
1874 static void
print_sol_usage(void)1875 print_sol_usage(void)
1876 {
1877 	lprintf(LOG_NOTICE, "SOL Commands: info [<channel number>]");
1878 	lprintf(LOG_NOTICE, "              set <parameter> <value> [channel]");
1879 	lprintf(LOG_NOTICE, "              payload <enable|disable|status> [channel] [userid]");
1880 	lprintf(LOG_NOTICE, "              activate [<usesolkeepalive|nokeepalive>] [instance=<number>]");
1881 	lprintf(LOG_NOTICE, "              deactivate [instance=<number>]");
1882 	lprintf(LOG_NOTICE, "              looptest [<loop times> [<loop interval(in ms)> [<instance>]]]");
1883 }
1884 
1885 
1886 
1887 /*
1888  * print_sol_set_usage
1889  */
1890 static void
print_sol_set_usage(void)1891 print_sol_set_usage(void)
1892 {
1893 	lprintf(LOG_NOTICE, "\nSOL set parameters and values: \n");
1894   	lprintf(LOG_NOTICE, "  set-in-progress             set-complete | "
1895 		"set-in-progress | commit-write");
1896 	lprintf(LOG_NOTICE, "  enabled                     true | false");
1897 	lprintf(LOG_NOTICE, "  force-encryption            true | false");
1898 	lprintf(LOG_NOTICE, "  force-authentication        true | false");
1899 	lprintf(LOG_NOTICE, "  privilege-level             user | operator | admin | oem");
1900 	lprintf(LOG_NOTICE, "  character-accumulate-level  <in 5 ms increments>");
1901 	lprintf(LOG_NOTICE, "  character-send-threshold    N");
1902 	lprintf(LOG_NOTICE, "  retry-count                 N");
1903 	lprintf(LOG_NOTICE, "  retry-interval              <in 10 ms increments>");
1904 	lprintf(LOG_NOTICE, "  non-volatile-bit-rate       "
1905 		"serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
1906 	lprintf(LOG_NOTICE, "  volatile-bit-rate           "
1907 		"serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
1908 	lprintf(LOG_NOTICE, "");
1909 }
1910 
1911 
1912 
1913 /* ipmi_sol_main */
1914 int
ipmi_sol_main(struct ipmi_intf * intf,int argc,char ** argv)1915 ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv)
1916 {
1917 	int retval = 0;
1918 	if (!argc || !strncmp(argv[0], "help", 4)) {
1919 		/* Help */
1920 		print_sol_usage();
1921 	} else if (!strncmp(argv[0], "info", 4)) {
1922 		/* Info */
1923 		uint8_t channel;
1924 		if (argc == 1) {
1925 			/* Ask about the current channel */
1926 			channel = 0x0E;
1927 		} else if (argc == 2) {
1928 			if (is_ipmi_channel_num(argv[1], &channel) != 0) {
1929 				return (-1);
1930 			}
1931 		} else {
1932 			print_sol_usage();
1933 			return -1;
1934 		}
1935 		retval = ipmi_print_sol_info(intf, channel);
1936 	} else if (!strncmp(argv[0], "payload", 7)) {
1937 		/* Payload enable or disable */
1938 		uint8_t channel = 0xe;
1939 		uint8_t userid = 1;
1940 		int enable = -1;
1941 		if (argc == 1 || argc > 4) {
1942 			print_sol_usage();
1943 			return -1;
1944 		}
1945 		if (argc >= 3) {
1946 			if (is_ipmi_channel_num(argv[2], &channel) != 0) {
1947 				return (-1);
1948 			}
1949 		}
1950 		if (argc == 4) {
1951 			if (is_ipmi_user_id(argv[3], &userid) != 0) {
1952 				return (-1);
1953 			}
1954 		}
1955 		if (!strncmp(argv[1], "enable", 6)) {
1956 			enable = 1;
1957 		} else if (!strncmp(argv[1], "disable", 7)) {
1958 			enable = 0;
1959 		} else if (!strncmp(argv[1], "status", 6)) {
1960 			return ipmi_sol_payload_access_status(intf, channel, userid);
1961 		} else {
1962 			print_sol_usage();
1963 			return -1;
1964 		}
1965 		retval = ipmi_sol_payload_access(intf, channel, userid, enable);
1966 	} else if (!strncmp(argv[0], "set", 3)) {
1967 		/* Set a parameter value */
1968 		uint8_t channel = 0xe;
1969 		uint8_t guard = 1;
1970 		if (argc == 3) {
1971 			channel = 0xe;
1972 		} else if (argc == 4) {
1973 			if (!strncmp(argv[3], "noguard", 7)) {
1974 				guard = 0;
1975 			} else {
1976 				if (is_ipmi_channel_num(argv[3], &channel) != 0) {
1977 					return (-1);
1978 				}
1979 			}
1980 		} else if (argc == 5) {
1981 			if (is_ipmi_channel_num(argv[3], &channel) != 0) {
1982 				return (-1);
1983 			}
1984 			if (!strncmp(argv[4], "noguard", 7)) {
1985 				guard = 0;
1986 			}
1987 		} else {
1988 			print_sol_set_usage();
1989 			return -1;
1990 		}
1991 		retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard);
1992 	} else if (!strncmp(argv[0], "activate", 8)) {
1993 		/* Activate */
1994 		int i;
1995 		uint8_t instance = 1;
1996 		for (i = 1; i < argc; i++) {
1997 			if (!strncmp(argv[i], "usesolkeepalive", 15)) {
1998 				_use_sol_for_keepalive = 1;
1999 			} else if (!strncmp(argv[i], "nokeepalive", 11)) {
2000 				_disable_keepalive = 1;
2001 			} else if (!strncmp(argv[i], "instance=", 9)) {
2002 				if (str2uchar(argv[i] + 9, &instance) != 0) {
2003 					lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9);
2004 					print_sol_usage();
2005 					return -1;
2006 				}
2007 			} else {
2008 				print_sol_usage();
2009 				return -1;
2010 			}
2011 		}
2012 		retval = ipmi_sol_activate(intf, 0, 0, instance);
2013 	} else if (!strncmp(argv[0], "deactivate", 10)) {
2014 		/* Dectivate */
2015 		int i;
2016 		uint8_t instance = 1;
2017 		for (i = 1; i < argc; i++) {
2018 			if (!strncmp(argv[i], "instance=", 9)) {
2019 				if (str2uchar(argv[i] + 9, &instance) != 0) {
2020 					lprintf(LOG_ERR,
2021 							"Given instance '%s' is invalid.",
2022 							argv[i] + 9);
2023 					print_sol_usage();
2024 					return -1;
2025 				}
2026 			} else {
2027 				print_sol_usage();
2028 				return -1;
2029 			}
2030 		}
2031 		retval = ipmi_sol_deactivate(intf, instance);
2032 	} else if (!strncmp(argv[0], "looptest", 8)) {
2033 		/* SOL loop test: Activate and then Dectivate */
2034 		int cnt = 200;
2035 		int interval = 100; /* Unit is: ms */
2036 		uint8_t instance = 1;
2037 		if (argc > 4) {
2038 			print_sol_usage();
2039 			return -1;
2040 		}
2041 		if (argc != 1) {
2042 			/* at least 2 */
2043 			if (str2int(argv[1], &cnt) != 0) {
2044 				lprintf(LOG_ERR, "Given cnt '%s' is invalid.",
2045 						argv[1]);
2046 				return (-1);
2047 			}
2048 			if (cnt <= 0) {
2049 				cnt = 200;
2050 			}
2051 		}
2052 		if (argc >= 3) {
2053 			if (str2int(argv[2], &interval) != 0) {
2054 				lprintf(LOG_ERR, "Given interval '%s' is invalid.",
2055 						argv[2]);
2056 				return (-1);
2057 			}
2058 			if (interval < 0) {
2059 				interval = 0;
2060 			}
2061 		}
2062 		if (argc >= 4) {
2063 			if (str2uchar(argv[3], &instance) != 0) {
2064 				lprintf(LOG_ERR, "Given instance '%s' is invalid.",
2065 						argv[3]);
2066 				print_sol_usage();
2067 				return -1;
2068 			}
2069 		}
2070 
2071 		while (cnt > 0) {
2072 			printf("remain loop test counter: %d\n", cnt);
2073 			retval = ipmi_sol_activate(intf, 1, interval, instance);
2074 			if (retval) {
2075 				printf("SOL looptest failed: %d\n",
2076 						retval);
2077 				break;
2078 			}
2079 			cnt -= 1;
2080 		}
2081 	} else {
2082 		print_sol_usage();
2083 		retval = -1;
2084 	}
2085 	return retval;
2086 }
2087