Blame lib/ipmi_isol.c

Packit Service ed0f68
/*
Packit Service ed0f68
 * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Redistribution and use in source and binary forms, with or without
Packit Service ed0f68
 * modification, are permitted provided that the following conditions
Packit Service ed0f68
 * are met:
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Redistribution of source code must retain the above copyright
Packit Service ed0f68
 * notice, this list of conditions and the following disclaimer.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Redistribution in binary form must reproduce the above copyright
Packit Service ed0f68
 * notice, this list of conditions and the following disclaimer in the
Packit Service ed0f68
 * documentation and/or other materials provided with the distribution.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Neither the name of Sun Microsystems, Inc. or the names of
Packit Service ed0f68
 * contributors may be used to endorse or promote products derived
Packit Service ed0f68
 * from this software without specific prior written permission.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * This software is provided "AS IS," without a warranty of any kind.
Packit Service ed0f68
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
Packit Service ed0f68
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
Packit Service ed0f68
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
Packit Service ed0f68
 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
Packit Service ed0f68
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
Packit Service ed0f68
 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
Packit Service ed0f68
 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
Packit Service ed0f68
 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
Packit Service ed0f68
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
Packit Service ed0f68
 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
Packit Service ed0f68
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Packit Service ed0f68
 */
Packit Service ed0f68
#define _XOPEN_SOURCE
Packit Service ed0f68
Packit Service ed0f68
#include <stdlib.h>
Packit Service ed0f68
#include <string.h>
Packit Service ed0f68
#include <strings.h>
Packit Service ed0f68
#include <stdio.h>
Packit Service ed0f68
#include <sys/types.h>
Packit Service ed0f68
#include <sys/stat.h>
Packit Service ed0f68
#include <sys/select.h>
Packit Service ed0f68
#include <sys/time.h>
Packit Service ed0f68
#include <signal.h>
Packit Service ed0f68
#include <unistd.h>
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
#include <termios.h>
Packit Service ed0f68
Packit Service ed0f68
#include <ipmitool/helper.h>
Packit Service ed0f68
#include <ipmitool/log.h>
Packit Service ed0f68
#include <ipmitool/ipmi.h>
Packit Service ed0f68
#include <ipmitool/ipmi_strings.h>
Packit Service ed0f68
#include <ipmitool/ipmi_intf.h>
Packit Service ed0f68
#include <ipmitool/ipmi_isol.h>
Packit Service ed0f68
Packit Service ed0f68
static struct termios _saved_tio;
Packit Service ed0f68
static int            _in_raw_mode = 0;
Packit Service ed0f68
Packit Service ed0f68
extern int verbose;
Packit Service ed0f68
Packit Service ed0f68
#define ISOL_ESCAPE_CHARACTER                    '~'
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_get_isol_info
Packit Service ed0f68
 */
Packit Service ed0f68
static int ipmi_get_isol_info(struct ipmi_intf * intf,
Packit Service ed0f68
			      struct isol_config_parameters * params)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq req;
Packit Service ed0f68
	unsigned char data[6];
Packit Service ed0f68
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn = IPMI_NETFN_ISOL;
Packit Service ed0f68
	req.msg.cmd = GET_ISOL_CONFIG;
Packit Service ed0f68
	req.msg.data = data;
Packit Service ed0f68
	req.msg.data_len = 4;
Packit Service ed0f68
Packit Service ed0f68
	/* GET ISOL ENABLED CONFIG */
Packit Service ed0f68
	
Packit Service ed0f68
	memset(data, 0, 6);
Packit Service ed0f68
	data[0] = 0x00;
Packit Service ed0f68
	data[1] = ISOL_ENABLE_PARAM;
Packit Service ed0f68
	data[2] = 0x00;		/* block */
Packit Service ed0f68
	data[3] = 0x00;		/* selector */
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in Get ISOL Config Command");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode == 0xc1) {
Packit Service ed0f68
		lprintf(LOG_ERR, "IPMI v1.5 Serial Over Lan (ISOL) not supported!");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
Packit Service ed0f68
			val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	params->enabled = rsp->data[1];
Packit Service ed0f68
Packit Service ed0f68
	/* GET ISOL AUTHENTICATON CONFIG */
Packit Service ed0f68
	
Packit Service ed0f68
	memset(data, 0, 6);
Packit Service ed0f68
	data[0] = 0x00;
Packit Service ed0f68
	data[1] = ISOL_AUTHENTICATION_PARAM;
Packit Service ed0f68
	data[2] = 0x00;		/* block */
Packit Service ed0f68
	data[3] = 0x00;		/* selector */
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in Get ISOL Config Command");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
Packit Service ed0f68
			val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	params->privilege_level = rsp->data[1];
Packit Service ed0f68
	
Packit Service ed0f68
	/* GET ISOL BAUD RATE CONFIG */
Packit Service ed0f68
	
Packit Service ed0f68
	memset(data, 0, 6);
Packit Service ed0f68
	data[0] = 0x00;
Packit Service ed0f68
	data[1] = ISOL_BAUD_RATE_PARAM;
Packit Service ed0f68
	data[2] = 0x00;		/* block */
Packit Service ed0f68
	data[3] = 0x00;		/* selector */
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in Get ISOL Config Command");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
Packit Service ed0f68
			val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	params->bit_rate = rsp->data[1];
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static int ipmi_print_isol_info(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct isol_config_parameters params = {0};
Packit Service ed0f68
	if (ipmi_get_isol_info(intf, &params))
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	if (csv_output)
Packit Service ed0f68
	{
Packit Service ed0f68
		printf("%s,", (params.enabled & 0x1)?"true": "false");
Packit Service ed0f68
		printf("%s,",
Packit Service ed0f68
			   val2str((params.privilege_level & 0xf), ipmi_privlvl_vals));
Packit Service ed0f68
		printf("%s,",
Packit Service ed0f68
			   val2str((params.bit_rate & 0xf), ipmi_bit_rate_vals));
Packit Service ed0f68
	}
Packit Service ed0f68
	else
Packit Service ed0f68
	{
Packit Service ed0f68
		printf("Enabled                         : %s\n",
Packit Service ed0f68
		       (params.enabled & 0x1)?"true": "false");
Packit Service ed0f68
		printf("Privilege Level                 : %s\n",
Packit Service ed0f68
		       val2str((params.privilege_level & 0xf), ipmi_privlvl_vals));
Packit Service ed0f68
		printf("Bit Rate (kbps)                 : %s\n",
Packit Service ed0f68
		       val2str((params.bit_rate & 0xf), ipmi_bit_rate_vals));
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static int ipmi_isol_set_param(struct ipmi_intf * intf,
Packit Service ed0f68
			       const char *param,
Packit Service ed0f68
			       const char *value)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq req;
Packit Service ed0f68
	unsigned char data[6];	
Packit Service ed0f68
	struct isol_config_parameters params = {0};
Packit Service ed0f68
Packit Service ed0f68
	/* We need other values to complete the request */
Packit Service ed0f68
	if (ipmi_get_isol_info(intf, &params))
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn = IPMI_NETFN_ISOL;
Packit Service ed0f68
	req.msg.cmd = SET_ISOL_CONFIG;
Packit Service ed0f68
	req.msg.data = data;
Packit Service ed0f68
	req.msg.data_len = 3;
Packit Service ed0f68
Packit Service ed0f68
	memset(data, 0, 6);
Packit Service ed0f68
	
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * enabled
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (strcmp(param, "enabled") == 0)
Packit Service ed0f68
	{
Packit Service ed0f68
		data[1] = ISOL_ENABLE_PARAM;
Packit Service ed0f68
		if (strcmp(value, "true") == 0)
Packit Service ed0f68
			data[2] = 0x01;
Packit Service ed0f68
		else if (strcmp(value, "false") == 0)
Packit Service ed0f68
			data[2] = 0x00;
Packit Service ed0f68
		else {
Packit Service ed0f68
			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
Packit Service ed0f68
				   value, param);
Packit Service ed0f68
			lprintf(LOG_ERR, "Valid values are true and false");
Packit Service ed0f68
			return -1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * privilege-level
Packit Service ed0f68
	 */
Packit Service ed0f68
	else if (strcmp(param, "privilege-level") == 0)
Packit Service ed0f68
	{
Packit Service ed0f68
		data[1] = ISOL_AUTHENTICATION_PARAM;
Packit Service ed0f68
		if (! strcmp(value, "user"))
Packit Service ed0f68
			data[2] = 0x02;
Packit Service ed0f68
		else if (! strcmp(value, "operator"))
Packit Service ed0f68
			data[2] = 0x03;
Packit Service ed0f68
		else if (! strcmp(value, "admin"))
Packit Service ed0f68
			data[2] = 0x04;
Packit Service ed0f68
		else if (! strcmp(value, "oem"))
Packit Service ed0f68
			data[2] = 0x05;
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
Packit Service ed0f68
				   value, param);
Packit Service ed0f68
			lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
Packit Service ed0f68
			return -1;
Packit Service ed0f68
		}
Packit Service ed0f68
		/* We need to mask bit7 from the fetched value */
Packit Service ed0f68
		data[2] |= (params.privilege_level & 0x80) ? 0x80 : 0x00;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * bit-rate
Packit Service ed0f68
	 */
Packit Service ed0f68
	else if (strcmp(param, "bit-rate") == 0)
Packit Service ed0f68
	{
Packit Service ed0f68
		data[1] = ISOL_BAUD_RATE_PARAM;
Packit Service ed0f68
		if (strncmp(value, "9.6", 3) == 0) {
Packit Service ed0f68
			data[2] = 0x06;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (strncmp(value, "19.2", 4) == 0) {
Packit Service ed0f68
			data[2] = 0x07;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (strncmp(value, "38.4", 4) == 0) {
Packit Service ed0f68
			data[2] = 0x08;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (strncmp(value, "57.6", 4) == 0) {
Packit Service ed0f68
			data[2] = 0x09;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (strncmp(value, "115.2", 5) == 0) {
Packit Service ed0f68
			data[2] = 0x0A;
Packit Service ed0f68
		}
Packit Service ed0f68
		else {
Packit Service ed0f68
			lprintf(LOG_ERR, "ISOL - Unsupported baud rate: %s", value);
Packit Service ed0f68
			lprintf(LOG_ERR, "Valid values are 9.6, 19.2, 38.4, 57.6 and 115.2");
Packit Service ed0f68
			return -1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
	else
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_ERR, "Error: invalid ISOL parameter %s", param);
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	
Packit Service ed0f68
	
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Execute the request
Packit Service ed0f68
	 */
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error setting ISOL parameter '%s'", param);
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error setting ISOL parameter '%s': %s",
Packit Service ed0f68
			   param, val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void
Packit Service ed0f68
leave_raw_mode(void)
Packit Service ed0f68
{
Packit Service ed0f68
	if (!_in_raw_mode)
Packit Service ed0f68
		return;
Packit Service ed0f68
	if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
Packit Service ed0f68
		perror("tcsetattr");
Packit Service ed0f68
	else
Packit Service ed0f68
		_in_raw_mode = 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static void
Packit Service ed0f68
enter_raw_mode(void)
Packit Service ed0f68
{
Packit Service ed0f68
	struct termios tio;
Packit Service ed0f68
	if (tcgetattr(fileno(stdin), &tio) == -1) {
Packit Service ed0f68
		perror("tcgetattr");
Packit Service ed0f68
		return;
Packit Service ed0f68
	}
Packit Service ed0f68
	_saved_tio = tio;
Packit Service ed0f68
	tio.c_iflag |= IGNPAR;
Packit Service ed0f68
	tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF)\
Packit Service ed0f68
		;
Packit Service ed0f68
	tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
Packit Service ed0f68
	//	#ifdef IEXTEN
Packit Service ed0f68
	tio.c_lflag &= ~IEXTEN;
Packit Service ed0f68
	//	#endif
Packit Service ed0f68
	tio.c_oflag &= ~OPOST;
Packit Service ed0f68
	tio.c_cc[VMIN] = 1;
Packit Service ed0f68
	tio.c_cc[VTIME] = 0;
Packit Service ed0f68
	if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
Packit Service ed0f68
		perror("tcsetattr");
Packit Service ed0f68
	else
Packit Service ed0f68
		_in_raw_mode = 1;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static void
Packit Service ed0f68
sendBreak(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_v2_payload  v2_payload;
Packit Service ed0f68
Packit Service ed0f68
	memset(&v2_payload, 0, sizeof(v2_payload));
Packit Service ed0f68
Packit Service ed0f68
	v2_payload.payload.sol_packet.character_count = 0;
Packit Service ed0f68
	v2_payload.payload.sol_packet.generate_break  = 1;
Packit Service ed0f68
Packit Service ed0f68
	intf->send_sol(intf, &v2_payload);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * suspendSelf
Packit Service ed0f68
 *
Packit Service ed0f68
 * Put ourself in the background
Packit Service ed0f68
 *
Packit Service ed0f68
 * param bRestoreTty specifies whether we will put our self back
Packit Service ed0f68
 *       in raw mode when we resume
Packit Service ed0f68
 */
Packit Service ed0f68
static void
Packit Service ed0f68
suspendSelf(int bRestoreTty)
Packit Service ed0f68
{
Packit Service ed0f68
	leave_raw_mode();
Packit Service ed0f68
	kill(getpid(), SIGTSTP);
Packit Service ed0f68
Packit Service ed0f68
	if (bRestoreTty)
Packit Service ed0f68
		enter_raw_mode();
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * printiSolEscapeSequences
Packit Service ed0f68
 *
Packit Service ed0f68
 * Send some useful documentation to the user
Packit Service ed0f68
 */
Packit Service ed0f68
static void
Packit Service ed0f68
printiSolEscapeSequences(void)
Packit Service ed0f68
{
Packit Service ed0f68
	printf(
Packit Service ed0f68
		   "%c?\n\
Packit Service ed0f68
	Supported escape sequences:\n\
Packit Service ed0f68
	%c.  - terminate connection\n\
Packit Service ed0f68
	%c^Z - suspend ipmitool\n\
Packit Service ed0f68
	%c^X - suspend ipmitool, but don't restore tty on restart\n\
Packit Service ed0f68
	%cB  - send break\n\
Packit Service ed0f68
	%c?  - this message\n\
Packit Service ed0f68
	%c%c  - send the escape character by typing it twice\n\
Packit Service ed0f68
	(Note that escapes are only recognized immediately after newline.)\n",
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER,
Packit Service ed0f68
		   ISOL_ESCAPE_CHARACTER);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * output
Packit Service ed0f68
 *
Packit Service ed0f68
 * Send the specified data to stdout
Packit Service ed0f68
 */
Packit Service ed0f68
static void
Packit Service ed0f68
output(struct ipmi_rs * rsp)
Packit Service ed0f68
{
Packit Service ed0f68
	if (rsp)
Packit Service ed0f68
	{
Packit Service ed0f68
		int i;
Packit Service ed0f68
		for (i = 0; i < rsp->data_len; ++i)
Packit Service ed0f68
			putc(rsp->data[i], stdout);
Packit Service ed0f68
Packit Service ed0f68
		fflush(stdout);
Packit Service ed0f68
	}
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_isol_deactivate
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_isol_deactivate(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq   req;
Packit Service ed0f68
	uint8_t    data[6];	 
Packit Service ed0f68
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn = IPMI_NETFN_ISOL;
Packit Service ed0f68
	req.msg.cmd = ACTIVATE_ISOL;
Packit Service ed0f68
	req.msg.data = data;
Packit Service ed0f68
	req.msg.data_len = 5;
Packit Service ed0f68
Packit Service ed0f68
	memset(data, 0, 6);
Packit Service ed0f68
	data[0] = 0x00; /* Deactivate */
Packit Service ed0f68
	data[1] = 0x00;
Packit Service ed0f68
	data[2] = 0x00;
Packit Service ed0f68
	data[3] = 0x00;
Packit Service ed0f68
	data[5] = 0x00;
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error deactivating ISOL");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error deactivating ISOL: %s",
Packit Service ed0f68
			val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	/* response contain 4 additional bytes : 80 00 32 ff
Packit Service ed0f68
	   Don't know what to use them for yet... */
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * processiSolUserInput
Packit Service ed0f68
 *
Packit Service ed0f68
 * Act on user input into the ISOL session.  The only reason this
Packit Service ed0f68
 * is complicated is that we have to process escape sequences.
Packit Service ed0f68
 *
Packit Service ed0f68
 * return   0 on success
Packit Service ed0f68
 *          1 if we should exit
Packit Service ed0f68
 *        < 0 on error (BMC probably closed the session)
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
processiSolUserInput(struct ipmi_intf * intf,
Packit Service ed0f68
		    uint8_t * input,
Packit Service ed0f68
		    uint16_t  buffer_length)
Packit Service ed0f68
{
Packit Service ed0f68
	static int escape_pending = 0;
Packit Service ed0f68
	static int last_was_cr    = 1;
Packit Service ed0f68
	struct ipmi_v2_payload v2_payload;
Packit Service ed0f68
	int  length               = 0;
Packit Service ed0f68
	int  retval               = 0;
Packit Service ed0f68
	char ch;
Packit Service ed0f68
	int  i;
Packit Service ed0f68
Packit Service ed0f68
	memset(&v2_payload, 0, sizeof(v2_payload));
Packit Service ed0f68
	
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Our first order of business is to check the input for escape
Packit Service ed0f68
	 * sequences to act on.
Packit Service ed0f68
	 */
Packit Service ed0f68
	for (i = 0; i < buffer_length; ++i)
Packit Service ed0f68
	{
Packit Service ed0f68
		ch = input[i];
Packit Service ed0f68
Packit Service ed0f68
		if (escape_pending){
Packit Service ed0f68
			escape_pending = 0;
Packit Service ed0f68
			
Packit Service ed0f68
			/*
Packit Service ed0f68
			 * Process a possible escape sequence.
Packit Service ed0f68
			 */
Packit Service ed0f68
			switch (ch) {
Packit Service ed0f68
			case '.':
Packit Service ed0f68
				printf("%c. [terminated ipmitool]\n", ISOL_ESCAPE_CHARACTER);
Packit Service ed0f68
				retval = 1;
Packit Service ed0f68
				break;
Packit Service ed0f68
			case 'Z' - 64:
Packit Service ed0f68
				printf("%c^Z [suspend ipmitool]\n", ISOL_ESCAPE_CHARACTER);
Packit Service ed0f68
				suspendSelf(1); /* Restore tty back to raw */
Packit Service ed0f68
				continue;
Packit Service ed0f68
Packit Service ed0f68
			case 'X' - 64:
Packit Service ed0f68
				printf("%c^X [suspend ipmitool]\n", ISOL_ESCAPE_CHARACTER);
Packit Service ed0f68
				suspendSelf(0); /* Don't restore to raw mode */
Packit Service ed0f68
				continue;
Packit Service ed0f68
Packit Service ed0f68
			case 'B':
Packit Service ed0f68
				printf("%cb [send break]\n", ISOL_ESCAPE_CHARACTER);
Packit Service ed0f68
				sendBreak(intf);
Packit Service ed0f68
				continue;
Packit Service ed0f68
Packit Service ed0f68
			case '?':
Packit Service ed0f68
				printiSolEscapeSequences();
Packit Service ed0f68
				continue;
Packit Service ed0f68
			default:
Packit Service ed0f68
				if (ch != ISOL_ESCAPE_CHARACTER)
Packit Service ed0f68
					v2_payload.payload.sol_packet.data[length++] =
Packit Service ed0f68
						ISOL_ESCAPE_CHARACTER;
Packit Service ed0f68
				v2_payload.payload.sol_packet.data[length++] = ch;
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			if (last_was_cr && (ch == ISOL_ESCAPE_CHARACTER)) {
Packit Service ed0f68
				escape_pending = 1;
Packit Service ed0f68
				continue;
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			v2_payload.payload.sol_packet.data[length++] =	ch;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Normal character.  Record whether it was a newline.
Packit Service ed0f68
		 */
Packit Service ed0f68
		last_was_cr = (ch == '\r' || ch == '\n');
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * If there is anything left to process we dispatch it to the BMC,
Packit Service ed0f68
	 * send intf->session->sol_data.max_outbound_payload_size bytes
Packit Service ed0f68
	 * at a time.
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (length)
Packit Service ed0f68
	{
Packit Service ed0f68
		struct ipmi_rs * rsp;
Packit Service ed0f68
Packit Service ed0f68
		v2_payload.payload.sol_packet.flush_outbound = 1; /* Not sure if necessary ? */
Packit Service ed0f68
		v2_payload.payload.sol_packet.character_count = length;
Packit Service ed0f68
		rsp = intf->send_sol(intf, &v2_payload);
Packit Service ed0f68
Packit Service ed0f68
		if (! rsp) {
Packit Service ed0f68
			lprintf(LOG_ERR, "Error sending SOL data");
Packit Service ed0f68
			retval = -1;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		/* If the sequence number is set we know we have new data */
Packit Service ed0f68
		else if ((rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)        &&
Packit Service ed0f68
			 (rsp->payload.sol_packet.packet_sequence_number))
Packit Service ed0f68
			output(rsp);
Packit Service ed0f68
	}
Packit Service ed0f68
	return retval;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_isol_red_pill
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_isol_red_pill(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	char   * buffer;
Packit Service ed0f68
	int    numRead;
Packit Service ed0f68
	int    bShouldExit       = 0;
Packit Service ed0f68
	int    bBmcClosedSession = 0;
Packit Service ed0f68
	fd_set read_fds;
Packit Service ed0f68
	struct timeval tv;
Packit Service ed0f68
	int    retval;
Packit Service ed0f68
	int    buffer_size = 255;
Packit Service ed0f68
	int    timedout = 0;
Packit Service ed0f68
Packit Service ed0f68
	buffer = (char*)malloc(buffer_size);
Packit Service ed0f68
	if (buffer == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	enter_raw_mode();
Packit Service ed0f68
Packit Service ed0f68
	while (! bShouldExit)
Packit Service ed0f68
	{
Packit Service ed0f68
		FD_ZERO(&read_fds);
Packit Service ed0f68
		FD_SET(0, &read_fds);
Packit Service ed0f68
		FD_SET(intf->fd, &read_fds);
Packit Service ed0f68
Packit Service ed0f68
		/* Wait up to half a second */
Packit Service ed0f68
		tv.tv_sec =  0;
Packit Service ed0f68
		tv.tv_usec = 500000;
Packit Service ed0f68
Packit Service ed0f68
		retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv;;
Packit Service ed0f68
Packit Service ed0f68
		if (retval)
Packit Service ed0f68
		{
Packit Service ed0f68
			if (retval == -1)
Packit Service ed0f68
			{
Packit Service ed0f68
				/* ERROR */
Packit Service ed0f68
				perror("select");
Packit Service ed0f68
				return -1;
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			timedout = 0;
Packit Service ed0f68
Packit Service ed0f68
			/*
Packit Service ed0f68
			 * Process input from the user
Packit Service ed0f68
			 */
Packit Service ed0f68
			if (FD_ISSET(0, &read_fds))
Packit Service ed0f68
	 		{
Packit Service ed0f68
				memset(buffer, 0, buffer_size);
Packit Service ed0f68
				numRead = read(fileno(stdin),
Packit Service ed0f68
							   buffer,
Packit Service ed0f68
							   buffer_size);
Packit Service ed0f68
				
Packit Service ed0f68
				if (numRead > 0)
Packit Service ed0f68
				{
Packit Service ed0f68
					int rc = processiSolUserInput(intf, buffer, numRead);
Packit Service ed0f68
					
Packit Service ed0f68
					if (rc)
Packit Service ed0f68
					{
Packit Service ed0f68
						if (rc < 0)
Packit Service ed0f68
							bShouldExit = bBmcClosedSession = 1;
Packit Service ed0f68
						else
Packit Service ed0f68
							bShouldExit = 1;
Packit Service ed0f68
					}
Packit Service ed0f68
				}
Packit Service ed0f68
				else
Packit Service ed0f68
				{
Packit Service ed0f68
					bShouldExit = 1;
Packit Service ed0f68
				}
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
			/*
Packit Service ed0f68
			 * Process input from the BMC
Packit Service ed0f68
			 */
Packit Service ed0f68
			else if (FD_ISSET(intf->fd, &read_fds))
Packit Service ed0f68
			{
Packit Service ed0f68
				struct ipmi_rs * rs = intf->recv_sol(intf);
Packit Service ed0f68
				if (! rs)
Packit Service ed0f68
				{
Packit Service ed0f68
					bShouldExit = bBmcClosedSession = 1;
Packit Service ed0f68
				}
Packit Service ed0f68
				else
Packit Service ed0f68
					output(rs);
Packit Service ed0f68
 			}
Packit Service ed0f68
Packit Service ed0f68
			
Packit Service ed0f68
			/*
Packit Service ed0f68
			 * ERROR in select
Packit Service ed0f68
			 */
Packit Service ed0f68
 			else
Packit Service ed0f68
			{
Packit Service ed0f68
				lprintf(LOG_ERR, "Error: Select returned with nothing to read");
Packit Service ed0f68
				bShouldExit = 1;
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			if ((++timedout) == 20) /* Every 10 seconds we send a keepalive */
Packit Service ed0f68
			{
Packit Service ed0f68
				intf->keepalive(intf);
Packit Service ed0f68
				timedout = 0;
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
	}		
Packit Service ed0f68
Packit Service ed0f68
	leave_raw_mode();
Packit Service ed0f68
Packit Service ed0f68
	if (bBmcClosedSession)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_ERR, "SOL session closed by BMC");
Packit Service ed0f68
	}
Packit Service ed0f68
	else
Packit Service ed0f68
		ipmi_isol_deactivate(intf);
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_isol_activate
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_isol_activate(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq   req;
Packit Service ed0f68
	uint8_t    data[6];	 
Packit Service ed0f68
	struct isol_config_parameters params;
Packit Service ed0f68
Packit Service ed0f68
	if (ipmi_get_isol_info(intf, &params))
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	if (!(params.enabled & 0x1)) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ISOL is not enabled!");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Setup a callback so that the lanplus processing knows what
Packit Service ed0f68
	 * to do with packets that come unexpectedly (while waiting for
Packit Service ed0f68
	 * an ACK, perhaps.
Packit Service ed0f68
	 */
Packit Service ed0f68
	intf->session->sol_data.sol_input_handler = output;
Packit Service ed0f68
	
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn = IPMI_NETFN_ISOL;
Packit Service ed0f68
	req.msg.cmd = ACTIVATE_ISOL;
Packit Service ed0f68
	req.msg.data = data;
Packit Service ed0f68
	req.msg.data_len = 5;
Packit Service ed0f68
Packit Service ed0f68
	memset(data, 0, 6);
Packit Service ed0f68
	data[0] = 0x01;
Packit Service ed0f68
	data[1] = 0x00;
Packit Service ed0f68
	data[2] = 0x00;
Packit Service ed0f68
	data[3] = 0x00;
Packit Service ed0f68
	data[5] = 0x00;
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (NULL != rsp) {
Packit Service ed0f68
		switch (rsp->ccode) {
Packit Service ed0f68
			case 0x00: 
Packit Service ed0f68
				if (rsp->data_len == 4) {
Packit Service ed0f68
					break;
Packit Service ed0f68
				} else {
Packit Service ed0f68
					lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
Packit Service ed0f68
						   "in ISOL activation response",
Packit Service ed0f68
						   rsp->data_len);
Packit Service ed0f68
					return -1;
Packit Service ed0f68
				}
Packit Service ed0f68
				break;
Packit Service ed0f68
			case 0x80:
Packit Service ed0f68
				lprintf(LOG_ERR, "Info: ISOL already active on another session");
Packit Service ed0f68
				return -1;
Packit Service ed0f68
			case 0x81:
Packit Service ed0f68
				lprintf(LOG_ERR, "Info: ISOL disabled");
Packit Service ed0f68
				return -1;
Packit Service ed0f68
			case 0x82:
Packit Service ed0f68
				lprintf(LOG_ERR, "Info: ISOL activation limit reached");
Packit Service ed0f68
				return -1;
Packit Service ed0f68
			default:
Packit Service ed0f68
				lprintf(LOG_ERR, "Error activating ISOL: %s",
Packit Service ed0f68
					val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
				return -1;
Packit Service ed0f68
		}				
Packit Service ed0f68
	} else {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error: No response activating ISOL");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* response contain 4 additional bytes : 80 01 32 ff
Packit Service ed0f68
	   Don't know what to use them for yet... */
Packit Service ed0f68
Packit Service ed0f68
	printf("[SOL Session operational.  Use %c? for help]\n",
Packit Service ed0f68
	       ISOL_ESCAPE_CHARACTER);
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * At this point we are good to go with our SOL session.  We
Packit Service ed0f68
	 * need to listen to
Packit Service ed0f68
	 * 1) STDIN for user input
Packit Service ed0f68
	 * 2) The FD for incoming SOL packets
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (ipmi_isol_red_pill(intf)) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in SOL session");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void print_isol_set_usage(void) {
Packit Service ed0f68
	lprintf(LOG_NOTICE, "\nISOL set parameters and values: \n");
Packit Service ed0f68
	lprintf(LOG_NOTICE, "  enabled                     true | false");
Packit Service ed0f68
	lprintf(LOG_NOTICE, "  privilege-level             user | operator | admin | oem");
Packit Service ed0f68
	lprintf(LOG_NOTICE, "  bit-rate                    "
Packit Service ed0f68
		"9.6 | 19.2 | 38.4 | 57.6 | 115.2");
Packit Service ed0f68
	lprintf(LOG_NOTICE, "");
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void print_isol_usage(void) {
Packit Service ed0f68
	lprintf(LOG_NOTICE, "ISOL Commands: info");
Packit Service ed0f68
	lprintf(LOG_NOTICE, "               set <parameter> <setting>");
Packit Service ed0f68
	lprintf(LOG_NOTICE, "               activate");
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int ipmi_isol_main(struct ipmi_intf * intf, int argc, char ** argv)
Packit Service ed0f68
{
Packit Service ed0f68
	int ret = 0;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Help
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (!argc || !strncmp(argv[0], "help", 4))
Packit Service ed0f68
		print_isol_usage();
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Info
Packit Service ed0f68
	 */
Packit Service ed0f68
	else if (!strncmp(argv[0], "info", 4)) {
Packit Service ed0f68
		ret = ipmi_print_isol_info(intf);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Set a parameter value
Packit Service ed0f68
	 */
Packit Service ed0f68
	else if (!strncmp(argv[0], "set", 3)) {
Packit Service ed0f68
		if (argc < 3) {
Packit Service ed0f68
			print_isol_set_usage();
Packit Service ed0f68
			return -1;
Packit Service ed0f68
		}
Packit Service ed0f68
		ret = ipmi_isol_set_param(intf, argv[1], argv[2]);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Activate
Packit Service ed0f68
	 */
Packit Service ed0f68
 	else if (!strncmp(argv[0], "activate", 8)) {
Packit Service ed0f68
		ret = ipmi_isol_activate(intf);
Packit Service ed0f68
	}
Packit Service ed0f68
	
Packit Service ed0f68
	else {
Packit Service ed0f68
		print_isol_usage();
Packit Service ed0f68
		ret = -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	
Packit Service ed0f68
	return ret;
Packit Service ed0f68
}