Incremental changes for SOL. Support for breaks (R. Sunshine). Much

refactoring and cleanup.  More coming soon.
This commit is contained in:
Jeremy Ellington 2004-07-23 20:56:17 +00:00
parent 9627ab3253
commit bf5e378272
2 changed files with 320 additions and 136 deletions

View File

@ -67,8 +67,7 @@
static struct termios _saved_tio;
static int _in_raw_mode = 0;
static int bShouldExit = 0;
extern int verbose;
@ -719,6 +718,28 @@ void enter_raw_mode(void)
}
static void sendBreak(struct ipmi_intf * intf)
{
struct ipmi_v2_payload v2_payload;
memset(&v2_payload, 0, sizeof(v2_payload));
v2_payload.payload_length = 0;
v2_payload.payload.sol_packet.generate_break = 1;
intf->send_sol(intf, &v2_payload);
}
/*
* suspendSelf
*
* Put ourself in the background
*
* param bRestoreTty specifies whether we will put our self back
* in raw mode when we resume
*/
static void suspendSelf(int bRestoreTty)
{
leave_raw_mode();
@ -730,21 +751,87 @@ static void suspendSelf(int bRestoreTty)
/*
* printSolEscapeSequences
*
* Send some useful documentation to the user
*/
void printSolEscapeSequences()
{
printf(
"~?\r\n\
"%c?\r\n\
Supported escape sequences:\r\n\
~. - terminate connection\r\n\
~^Z - suspend ipmitool\r\n\
~^X - suspend ipmitool, but don't restore tty on restart\r\n\
~? - this message\r\n\
~~ - send the escape character by typing it twice\r\n\
(Note that escapes are only recognized immediately after newline.)\r\n");
%c. - terminate connection\r\n\
%c^Z - suspend ipmitool\r\n\
%c^X - suspend ipmitool, but don't restore tty on restart\r\n\
%cb - send break\r\n\
%c? - this message\r\n\
%c%c - send the escape character by typing it twice\r\n\
(Note that escapes are only recognized immediately after newline.)\r\n",
SOL_ESCAPE_CHARACTER,
SOL_ESCAPE_CHARACTER,
SOL_ESCAPE_CHARACTER,
SOL_ESCAPE_CHARACTER,
SOL_ESCAPE_CHARACTER,
SOL_ESCAPE_CHARACTER,
SOL_ESCAPE_CHARACTER);
}
/*
* output
*
* Send the specified data to stdout
*/
static void output(char * data, int length)
{
int i;
for (i = 0; i < length; ++i)
putc(data[i], stdout);
fflush(stdout);
}
/*
* impi_sol_deactivate
*/
static int ipmi_sol_deactivate(struct ipmi_intf * intf)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char data[6];
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD;
req.msg.data_len = 6;
req.msg.data = data;
bzero(data, sizeof(data));
data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
data[1] = 1; /* payload instance. Guess! */
/* Lots of important data */
data[2] = 0;
data[3] = 0;
data[4] = 0;
data[5] = 0;
rsp = intf->sendrecv(intf, &req);
if (!rsp || rsp->ccode) {
printf("Error:%x Dectivating SOL payload\n",
rsp ? rsp->ccode : 0);
return -1;
}
return 0;
}
/*
* processSolUserInput
*
@ -767,11 +854,16 @@ static int processSolUserInput(struct ipmi_intf * intf,
char ch;
int i;
memset(&v2_payload, 0, sizeof(v2_payload));
/*
* Our first order of business is to check the input for escape
* sequences to act on.
*/
for (i = 0; i < buffer_length; ++i)
{
ch = input[i];
//if (escape_pending && (ch != SOL_ESCAPE_CHARACTER)) {
if (escape_pending){
escape_pending = 0;
@ -780,10 +872,9 @@ static int processSolUserInput(struct ipmi_intf * intf,
*/
switch (ch) {
case '.':
/* Terminate the connection. */
/* Should probably flush our buffer first */
return 1;
continue;
printf("%c. [terminated ipmitool]\r\n", SOL_ESCAPE_CHARACTER);
retval = 1;
break;
case 'Z' - 64:
printf("%c^Z [suspend ipmitool]\r\n", SOL_ESCAPE_CHARACTER);
suspendSelf(1); /* Restore tty back to raw */
@ -794,6 +885,11 @@ static int processSolUserInput(struct ipmi_intf * intf,
suspendSelf(0); /* Don't restore to raw mode */
continue;
case 'b':
printf("%cb [send break]\r\n", SOL_ESCAPE_CHARACTER);
sendBreak(intf);
continue;
case '?':
printSolEscapeSequences();
continue;
@ -823,19 +919,28 @@ static int processSolUserInput(struct ipmi_intf * intf,
}
/*
* If there is anything left to process we dispatch it to the BMC
*/
if (length)
{
struct ipmi_rs * rsp;
v2_payload.payload_length = length;
rsp = intf->send_sol(intf, &v2_payload);
//memcpy(v2_payload.payload.sol_packet.data,
// input,
// v2_payload.payload_length);
if (intf->send_sol(intf, &v2_payload))
/* This will always fail until we wait for our ACKs */
if (! rsp)
{
printf("Error sending SOL data\n");
retval = -1;
//printf("Error sending SOL data\n");
//retval = -1;
}
/* If the sequence number is set we know we have new data */
//else if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
// (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
// (rsp->payload.sol_packet.packet_sequence_number))
// output(rsp->data, rsp->data_len);
}
return retval;
@ -882,11 +987,12 @@ static int ipmi_sol_red_pill(struct ipmi_intf * intf)
return -1;
}
/*
* Process input from the user
*/
if (FD_ISSET(0, &read_fds))
{
/*
* Received input from the user
*/
{
bzero(buffer, sizeof(buffer));
numRead = read(fileno(stdin),
buffer, sizeof(buffer));
@ -894,10 +1000,14 @@ static int ipmi_sol_red_pill(struct ipmi_intf * intf)
if (numRead > 0)
{
int rc = processSolUserInput(intf, buffer, numRead);
if (rc)
bShouldExit = 1;
if (rc < 1)
bBmcClosedSession = 1;
{
if (rc < 0)
bShouldExit = bBmcClosedSession = 1;
else
bShouldExit = 1;
}
}
else
{
@ -905,11 +1015,12 @@ static int ipmi_sol_red_pill(struct ipmi_intf * intf)
}
}
/*
* Process input from the BMC
*/
else if (FD_ISSET(intf->fd, &read_fds))
{
/*
* Received input from the BMC.
*/
int i;
struct ipmi_rs * rs =intf->recv_sol(intf);
if (! rs)
@ -917,17 +1028,15 @@ static int ipmi_sol_red_pill(struct ipmi_intf * intf)
bShouldExit = bBmcClosedSession = 1;
}
else
{
for (i = 0; i < rs->data_len; ++i)
putc(rs->data[i], stdout);
}
fflush(stdout);
output(rs->data, rs->data_len);
}
else
/*
* ERROR in select
*/
else
{
/* ERROR */
printf("Error: Select returned with nothing to read\n");
bShouldExit = 1;
}
@ -941,46 +1050,14 @@ static int ipmi_sol_red_pill(struct ipmi_intf * intf)
printf("SOL session closed by BMC\n");
exit(1);
}
else
ipmi_sol_deactivate(intf);
return 0;
}
/*
* impi_sol_deactivate
*/
static int ipmi_sol_deactivate(struct ipmi_intf * intf)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char data[6];
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD;
req.msg.data_len = 6;
req.msg.data = data;
bzero(data, sizeof(data));
data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
data[1] = 1; /* payload instance. Guess! */
/* Lots of important data */
data[2] = 0;
data[3] = 0;
data[4] = 0;
data[5] = 0;
rsp = intf->sendrecv(intf, &req);
if (!rsp || rsp->ccode) {
printf("Error:%x Dectivating SOL payload\n",
rsp ? rsp->ccode : 0);
return -1;
}
return 0;
}
@ -1065,14 +1142,6 @@ static int ipmi_sol_activate(struct ipmi_intf * intf)
#endif
printf("max inbound payload size : %d\n",
intf->session->sol_data.max_inbound_payload_size);
printf("max outbound payload size : %d\n",
intf->session->sol_data.max_outbound_payload_size);
printf("SOL port : %d\n",
intf->session->sol_data.port);
if (intf->session->sol_data.port != intf->session->port)
{
printf("Error: BMC requests SOL session on different port\n");
@ -1080,6 +1149,10 @@ static int ipmi_sol_activate(struct ipmi_intf * intf)
}
printf("[SOL Session operational. Use %c? for help]\r\n",
SOL_ESCAPE_CHARACTER);
/*
* At this point we are good to go with our SOL session. We
* need to listen to
@ -1104,6 +1177,8 @@ void print_sol_usage()
{
printf("SOL Commands: info [<channel number>]\n");
printf(" set <parameter> <value> [channel]\n");
printf(" activate\n");
printf(" deactivate\n");
}
@ -1140,6 +1215,7 @@ int ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv)
retval = ipmi_print_sol_info(intf, channel);
}
/*
* Set a parameter value
*/

View File

@ -102,8 +102,12 @@ static void read_session_data_v2x(struct ipmi_rs * rsp, int * offset, struct ipm
static void read_ipmi_response(struct ipmi_rs * rsp, int * offset);
static void read_sol_packet(struct ipmi_rs * rsp, int * offset);
static struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf);
static int ipmi_lanplus_send_sol(struct ipmi_intf * intf,
struct ipmi_v2_payload * payload);
static struct ipmi_rs * ipmi_lanplus_send_sol(struct ipmi_intf * intf,
struct ipmi_v2_payload * payload);
static int check_sol_packet_for_data(struct ipmi_intf * intf,
struct ipmi_rs *rsp);
static void ack_sol_packet(struct ipmi_intf * intf,
struct ipmi_rs * rsp);
struct ipmi_intf ipmi_lanplus_intf = {
@ -605,7 +609,10 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
}
else if (rsp->session.payloadtype ==
/*
* Open Response
*/
else if (rsp->session.payloadtype ==
IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE)
{
if (session->v2_data.session_state !=
@ -621,7 +628,11 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
break;
}
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2)
/*
* RAKP 2
*/
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2)
{
if (session->v2_data.session_state != LANPLUS_STATE_RAKP_1_SENT)
{
@ -634,6 +645,10 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
break;
}
/*
* RAKP 4
*/
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_4)
{
if (session->v2_data.session_state != LANPLUS_STATE_RAKP_3_SENT)
@ -647,7 +662,11 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
break;
}
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)
/*
* SOL
*/
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)
{
int payload_start = offset;
int extra_data_length;
@ -1833,6 +1852,8 @@ struct ipmi_rs *
while (try < IPMI_LAN_RETRY) {
if (ipmi_lan_send_packet(intf, msg_data, msg_length) < 0) {
printf("ipmi_lan_send_cmd failed\n");
return NULL;
@ -1859,13 +1880,38 @@ struct ipmi_rs *
if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL)
{
// jme : todo. If the payload is not an ACK we need to wait
// for an ack. And if we don't receive an ACK, we need to
// resend.
break;
//if (! payload->payload.sol_packet.packet_sequence_number)
//{
/* This was just an ACK. We can leave now. No retry. */
break;
//}
//int try_count = 1;
// jme : todo. We need to wait for an ack. And if we
// don't receive an ACK, we need to resend.
/* We need an ACK */
//for (try_count = 1; try_count < 3; ++try_count)
//{
// rsp = ipmi_lan_poll_recv(intf);
/* Sets our last see */
// handleIncomingSolPacket(rsp);
// if (acksPacket(rsp, payload))
// break;
//}
//break;
}
/*
* This call is NOT made for SOL packets
*/
rsp = ipmi_lan_poll_recv(intf);
if (rsp)
break;
@ -1887,9 +1933,11 @@ struct ipmi_rs *
* return 0 on success
* -1 on error
*/
int ipmi_lanplus_send_sol(struct ipmi_intf * intf,
struct ipmi_v2_payload * v2_payload)
struct ipmi_rs * ipmi_lanplus_send_sol(struct ipmi_intf * intf,
struct ipmi_v2_payload * v2_payload)
{
struct ipmi_rs * rs;
v2_payload->payload_type = IPMI_PAYLOAD_TYPE_SOL;
/*
@ -1907,27 +1955,100 @@ int ipmi_lanplus_send_sol(struct ipmi_intf * intf,
v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */
ipmi_lanplus_send_payload(intf, v2_payload);
rs = ipmi_lanplus_send_payload(intf, v2_payload);
return 0;
return rs;
}
/*
* ipmi_lanplus_recv_sol
* check_sol_packet_for_new_data
*
* Receive a SOL packet and send an ACK in response.
* Determine whether the SOL packet has already been seen
* and whether the packet has new data for us.
*
* This function has the side effect of removing an previously
* seen data, and moving new data to the front.
*
* It also "Remembers" the data so we don't get repeats.
*
* returns the number of new bytes in the SOL packet
*/
struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf)
static int check_sol_packet_for_new_data(struct ipmi_intf * intf,
struct ipmi_rs *rsp)
{
struct ipmi_v2_payload ack;
struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf);
/* If the SOL packet looks good, ACK it */
if (rsp && rsp->data_len)
static unsigned char last_received_sequence_number = 0;
static unsigned char last_received_byte_count = 0;
int new_data_size = 0;
if (rsp &&
(rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
{
/* Store the data length before we mod it */
unsigned char unaltered_data_len = rsp->data_len;
if (rsp->payload.sol_packet.packet_sequence_number ==
last_received_sequence_number)
{
/*
* This is the same as the last packet, but may include
* extra data
*/
new_data_size =
rsp->data_len -
intf->session->sol_data.last_received_byte_count;
if (new_data_size > 0)
{
/* We have more data to process */
memmove(rsp->data,
rsp->data +
rsp->data_len - new_data_size,
new_data_size);
}
rsp->data_len = new_data_size;
}
/*
*Rember the data for next round
*/
if (rsp->payload.sol_packet.packet_sequence_number)
{
last_received_sequence_number =
rsp->payload.sol_packet.packet_sequence_number;
last_received_byte_count = unaltered_data_len;
}
}
return new_data_size;
}
/*
* ack_sol_packet
*
* Provided the specified packet looks reasonable, ACK it.
*/
static void ack_sol_packet(struct ipmi_intf * intf,
struct ipmi_rs * rsp)
{
if (rsp &&
(rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
(rsp->payload.sol_packet.packet_sequence_number))
{
struct ipmi_v2_payload ack;
bzero(&ack, sizeof(struct ipmi_v2_payload));
ack.payload_type = IPMI_PAYLOAD_TYPE_SOL;
@ -1948,45 +2069,33 @@ struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf)
ipmi_lanplus_send_payload(intf, &ack);
}
}
/* This may be an identical packet */
if (rsp &&
(rsp->payload.sol_packet.packet_sequence_number ==
intf->session->sol_data.last_received_sequence_number))
{
/* This is the same as the last packet, but may include
extra data */
int extra_data_size =
rsp->data_len -
intf->session->sol_data.last_received_byte_count;
if (extra_data_size > 0)
{
/* We have more data to process */
memmove(rsp->data,
rsp->data +
rsp->data_len - extra_data_size,
extra_data_size);
}
rsp->data_len = extra_data_size;
}
/* If it's not an ACK, remember that we saw it. */
if (rsp &&
rsp->payload.sol_packet.packet_sequence_number)
{
intf->session->sol_data.last_received_sequence_number =
rsp->payload.sol_packet.packet_sequence_number;
intf->session->sol_data.last_received_byte_count =
rsp->data_len;
}
/*
* ipmi_lanplus_recv_sol
*
* Receive a SOL packet and send an ACK in response.
*
*/
struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf)
{
struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf);
ack_sol_packet(intf, rsp);
/*
* Remembers the data sent, and alters the data to just
* include the new stuff.
*/
check_sol_packet_for_new_data(intf, rsp);
return rsp;
}
/**
* ipmi_lanplus_send_ipmi_cmd
*
@ -2005,7 +2114,6 @@ struct ipmi_rs *
/*
* ipmi_get_auth_capabilities_cmd
*
@ -2584,8 +2692,8 @@ int ipmi_lanplus_open(struct ipmi_intf * intf)
session->v2_data.console_id = 0x00;
session->v2_data.bmc_id = 0x00;
session->sol_data.sequence_number = 1;
session->sol_data.last_received_sequence_number = 0;
session->sol_data.last_received_byte_count = 0;
//session->sol_data.last_received_sequence_number = 0;
//session->sol_data.last_received_byte_count = 0;
memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE);
memset(session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE);