Move all files one level up in the file hierarcy, to avoid the useless ipmitool directory.

This commit is contained in:
Petter Reinholdtsen
2014-02-05 17:30:32 +01:00
parent b0aad15d67
commit c18ec02f33
171 changed files with 0 additions and 0 deletions

43
src/plugins/Makefile.am Normal file
View File

@@ -0,0 +1,43 @@
# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@
DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy
noinst_LTLIBRARIES = libintf.la
libintf_la_SOURCES = ipmi_intf.c
libintf_la_LDFLAGS = -export-dynamic
libintf_la_LIBADD = @IPMITOOL_INTF_LIB@
libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@

View File

@@ -0,0 +1,41 @@
# Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_bmc.la
noinst_LTLIBRARIES = @INTF_BMC_LIB@
libintf_bmc_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_bmc_la_SOURCES = \
bmc.c bmc.h \
bmc_intf.h

351
src/plugins/bmc/bmc.c Normal file
View File

@@ -0,0 +1,351 @@
/*
* Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/*
* interface routines between ipmitool and the bmc kernel driver
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stropts.h>
#include <stddef.h>
#include <stropts.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include "bmc_intf.h"
#include "bmc.h"
static int curr_seq;
static int bmc_method(int fd, int *if_type);
struct ipmi_rs *(*sendrecv_fn)(struct ipmi_intf *, struct ipmi_rq *) = NULL;
extern int verbose;
static void dump_request(bmc_req_t *request);
static void dump_response(bmc_rsp_t *response);
static struct ipmi_rs *ipmi_bmc_send_cmd_ioctl(struct ipmi_intf *intf,
struct ipmi_rq *req);
static struct ipmi_rs *ipmi_bmc_send_cmd_putmsg(struct ipmi_intf *intf,
struct ipmi_rq *req);
#define MESSAGE_BUFSIZE 1024
struct ipmi_intf ipmi_bmc_intf = {
name: "bmc",
desc: "IPMI v2.0 BMC interface",
open: ipmi_bmc_open,
close: ipmi_bmc_close,
sendrecv: ipmi_bmc_send_cmd};
void
ipmi_bmc_close(struct ipmi_intf *intf)
{
if (intf && intf->fd >= 0)
close(intf->fd);
intf->opened = 0;
intf->manufacturer_id = IPMI_OEM_UNKNOWN;
intf->fd = -1;
}
int
ipmi_bmc_open(struct ipmi_intf *intf)
{
int method;
if (!intf)
return -1;
/* Open local device */
intf->fd = open(BMC_DEV, O_RDWR);
if (intf->fd <= 0) {
perror("Could not open bmc device");
return (-1);
}
curr_seq = 0;
intf->opened = 1;
if (bmc_method(intf->fd, &method) < 0) {
perror("Could not determine bmc messaging interface");
return (-1);
}
sendrecv_fn = (method == BMC_PUTMSG_METHOD) ?
ipmi_bmc_send_cmd_putmsg : ipmi_bmc_send_cmd_ioctl;
intf->manufacturer_id = ipmi_get_oem(intf);
return (intf->fd);
}
struct ipmi_rs *
ipmi_bmc_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req)
{
/* If not already opened open the device or network connection */
if (!intf->opened && intf->open && intf->open(intf) < 0)
return NULL;
/* sendrecv_fn cannot be NULL at this point */
return ((*sendrecv_fn)(intf, req));
}
static struct ipmi_rs *
ipmi_bmc_send_cmd_ioctl(struct ipmi_intf *intf, struct ipmi_rq *req)
{
struct strioctl istr;
static struct bmc_reqrsp reqrsp;
static struct ipmi_rs rsp;
memset(&reqrsp, 0, sizeof (reqrsp));
reqrsp.req.fn = req->msg.netfn;
reqrsp.req.lun = 0;
reqrsp.req.cmd = req->msg.cmd;
reqrsp.req.datalength = req->msg.data_len;
memcpy(reqrsp.req.data, req->msg.data, req->msg.data_len);
reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE;
istr.ic_cmd = IOCTL_IPMI_KCS_ACTION;
istr.ic_timout = 0;
istr.ic_dp = (char *)&reqrsp;
istr.ic_len = sizeof (struct bmc_reqrsp);
if (verbose) {
printf("--\n");
dump_request(&reqrsp.req);
printf("--\n");
}
if (ioctl(intf->fd, I_STR, &istr) < 0) {
perror("BMC IOCTL: I_STR");
return (NULL);
}
if (verbose > 2) {
dump_response(&reqrsp.rsp);
printf("--\n");
}
memset(&rsp, 0, sizeof (struct ipmi_rs));
rsp.ccode = reqrsp.rsp.ccode;
rsp.data_len = reqrsp.rsp.datalength;
/* Decrement for sizeof lun, cmd and ccode */
rsp.data_len -= 3;
if (!rsp.ccode && (rsp.data_len > 0))
memcpy(rsp.data, reqrsp.rsp.data, rsp.data_len);
return (&rsp);
}
static struct ipmi_rs *
ipmi_bmc_send_cmd_putmsg(struct ipmi_intf *intf, struct ipmi_rq *req)
{
struct strbuf sb;
int flags = 0;
static uint32_t msg_seq = 0;
/*
* The length of the message structure is equal to the size of the
* bmc_req_t structure, PLUS any additional data space in excess of
* the data space already reserved in the data member + <n> for
* the rest of the members in the bmc_msg_t structure.
*/
int msgsz = offsetof(bmc_msg_t, msg) + sizeof(bmc_req_t) +
((req->msg.data_len > SEND_MAX_PAYLOAD_SIZE) ?
(req->msg.data_len - SEND_MAX_PAYLOAD_SIZE) : 0);
bmc_msg_t *msg = malloc(msgsz);
bmc_req_t *request = (bmc_req_t *)&msg->msg[0];
bmc_rsp_t *response;
static struct ipmi_rs rsp;
struct ipmi_rs *ret = NULL;
msg->m_type = BMC_MSG_REQUEST;
msg->m_id = msg_seq++;
request->fn = req->msg.netfn;
request->lun = 0;
request->cmd = req->msg.cmd;
request->datalength = req->msg.data_len;
memcpy(request->data, req->msg.data, req->msg.data_len);
sb.len = msgsz;
sb.buf = (unsigned char *)msg;
if (verbose) {
printf("--\n");
dump_request(request);
printf("--\n");
}
if (putmsg(intf->fd, NULL, &sb, 0) < 0) {
perror("BMC putmsg: ");
free(msg);
msg = NULL;
return (NULL);
}
free(msg);
msg = NULL;
sb.buf = malloc(MESSAGE_BUFSIZE);
sb.maxlen = MESSAGE_BUFSIZE;
if (getmsg(intf->fd, NULL, &sb, &flags) < 0) {
perror("BMC getmsg: ");
free(sb.buf);
sb.buf = NULL;
return (NULL);
}
msg = (bmc_msg_t *)sb.buf;
if (verbose > 3) {
printf("Got msg (id 0x%x) type 0x%x\n", msg->m_id, msg->m_type);
}
/* Did we get an error back from the stream? */
switch (msg->m_type) {
case BMC_MSG_RESPONSE:
response = (bmc_rsp_t *)&msg->msg[0];
if (verbose > 2) {
dump_response(response);
printf("--\n");
}
memset(&rsp, 0, sizeof (struct ipmi_rs));
rsp.ccode = response->ccode;
rsp.data_len = response->datalength;
if (!rsp.ccode && (rsp.data_len > 0))
memcpy(rsp.data, response->data, rsp.data_len);
ret = &rsp;
break;
case BMC_MSG_ERROR:
/* In case of an error, msg->msg[0] has the error code */
printf("bmc_send_cmd: %s\n", strerror(msg->msg[0]));
break;
}
free(sb.buf);
sb.buf = NULL;
return (ret);
}
/*
* Determine which interface to use. Returns the interface method
* to use.
*/
static int
bmc_method(int fd, int *if_type)
{
struct strioctl istr;
int retval = 0;
uint8_t method = BMC_PUTMSG_METHOD;
istr.ic_cmd = IOCTL_IPMI_INTERFACE_METHOD;
istr.ic_timout = 0;
istr.ic_dp = (uint8_t *)&method;
istr.ic_len = 1;
/*
* If the ioctl doesn't exist, we should get an EINVAL back.
* Bail out on any other error.
*/
if (ioctl(fd, I_STR, &istr) < 0) {
if (errno != EINVAL)
retval = -1;
else
method = BMC_IOCTL_METHOD;
}
if (retval == 0)
*if_type = method;
return (retval);
}
static void
dump_request(bmc_req_t *request)
{
int i;
printf("BMC req.fn : 0x%x\n", request->fn);
printf("BMC req.lun : 0x%x\n", request->lun);
printf("BMC req.cmd : 0x%x\n", request->cmd);
printf("BMC req.datalength : 0x%x\n", request->datalength);
printf("BMC req.data : ");
if (request->datalength > 0) {
for (i = 0; i < request->datalength; i++)
printf("0x%x ", request->data[i]);
} else {
printf("<NONE>");
}
printf("\n");
}
static void
dump_response(bmc_rsp_t *response)
{
int i;
printf("BMC rsp.fn : 0x%x\n", response->fn);
printf("BMC rsp.lun : 0x%x\n", response->lun);
printf("BMC rsp.cmd : 0x%x\n", response->cmd);
printf("BMC rsp.ccode : 0x%x\n", response->ccode);
printf("BMC rsp.datalength : 0x%x\n", response->datalength);
printf("BMC rsp.data : ");
if (response->datalength > 0) {
for (i = 0; i < response->datalength; i++)
printf("0x%x ", response->data[i]);
} else {
printf("<NONE>");
}
printf("\n");
}

52
src/plugins/bmc/bmc.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef _IPMI_BMC_H_
#define _IPMI_BMC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <ipmitool/ipmi.h>
#define BMC_DEV "/dev/bmc"
struct ipmi_rs *ipmi_bmc_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req);
int ipmi_bmc_open(struct ipmi_intf *intf);
void ipmi_bmc_close(struct ipmi_intf *intf);
#ifdef __cplusplus
}
#endif
#endif /* _IPMI_BMC_H_ */

207
src/plugins/bmc/bmc_intf.h Normal file
View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef _BMC_INTF_H
#define _BMC_INTF_H
#pragma ident "@(#)bmc_intf.h 1.2 05/03/07 SMI"
#ifdef __cplusplus
extern "C" {
#endif
#define BMC_SUCCESS 0x0
#define BMC_FAILURE 0x1
#define BMC_NETFN_CHASSIS 0x0
#define BMC_NETFN_BRIDGE 0x2
#define BMC_NETFN_SE 0x4
#define BMC_NETFN_APP 0x6
#define BMC_NETFN_FIRMWARE 0x8
#define BMC_NETFN_STORAGE 0xa
#define BMC_NETFN_TRANSPORT 0xc
#define SEND_MAX_PAYLOAD_SIZE 34 /* MAX payload */
#define RECV_MAX_PAYLOAD_SIZE 33 /* MAX payload */
#define BMC_MIN_RESPONSE_SIZE 3
#define BMC_MIN_REQUEST_SIZE 2
#define BMC_MAX_RESPONSE_SIZE (BMC_MIN_RESPONSE_SIZE + RECV_MAX_PAYLOAD_SIZE)
#define BMC_MAX_REQUEST_SIZE (BMC_MIN_REQUEST_SIZE + BMC_MAX_RESPONSE_SIZE)
#define BUF_SIZE 256
#define MAX_BUF_SIZE 256
/*
* Useful macros
*/
#define FORM_NETFNLUN(net, lun) ((((net) << 2) | ((lun) & 0x3)))
#define GET_NETFN(netfn) (((netfn) >> 2) & 0x3f)
#define GET_LUN(netfn) (netfn & 0x3)
#define RESP_NETFN(nflun) ((nflun) | 1)
#define ISREQUEST(nl) (((nl) & 1) == 0) /* test for request */
#define ISRESPONSE(nl) (((nl) & 1) == 1) /* test for response */
/* for checking BMC specific stuff */
#define BMC_GET_DEVICE_ID 0x1 /* GET DEVICE ID COMMAND */
#define BMC_IPMI_15_VER 0x51 /* IPMI 1.5 definion */
/* BMC Completion Code and OEM Completion Code */
#define BMC_IPMI_UNSPECIFIC_ERROR 0xFF /* Unspecific Error */
#define BMC_IPMI_INVALID_COMMAND 0xC1 /* Invalid Command */
#define BMC_IPMI_COMMAND_TIMEOUT 0xC3 /* Command Timeout */
#define BMC_IPMI_DATA_LENGTH_EXCEED 0xC8 /* DataLength exceeded limit */
#define BMC_IPMI_OEM_FAILURE_SENDBMC 0x7E /* Cannot send BMC req */
#define IOCTL_IPMI_KCS_ACTION 0x01
#define IOCTL_IPMI_INTERFACE_METHOD 0x02
/* Interface methods returned from IOCTL_IPMI_INTERFACE_METHOD ioctl: */
#define BMC_IOCTL_METHOD 0 /* Not returned from ioctl, */
/* but can be used by */
/* applications that want to */
/* compare against an */
/* alternative method. */
#define BMC_PUTMSG_METHOD 1
/*
* bmc_req_t is the data structure to send
* request packet from applications to the driver
* module.
*
* the request pkt is mainly for KCS-interface-BMC
* messages. Since the system interface is session-less
* connections, the packet won't have any session
* information.
*
* the data payload will be 2 bytes less than max
* BMC supported packet size.
* the address of the responder is always BMC and so
* rsSa field is not required.
*/
typedef struct bmc_req {
uint8_t fn; /* netFn for command */
uint8_t lun; /* logical unit on responder */
uint8_t cmd; /* command */
uint8_t datalength; /* length of following data */
uint8_t data[SEND_MAX_PAYLOAD_SIZE]; /* request data */
} bmc_req_t;
/*
* bmc_rsp_t is the data structure to send
* respond packet from applications to the driver
* module.
*
* the respond pkt is mainly for KCS-interface-BMC
* messages. Since the system interface is session-less
* connections, the packet won't have any session
* information.
*
* the data payload will be 2 bytes less than max
* BMC supported packet size.
*/
typedef struct bmc_rsp {
uint8_t fn; /* netFn for command */
uint8_t lun; /* logical unit on responder */
uint8_t cmd; /* command */
uint8_t ccode; /* completion code */
uint8_t datalength; /* Length */
uint8_t data[RECV_MAX_PAYLOAD_SIZE]; /* response */
} bmc_rsp_t;
/*
* the data structure for synchronous operation via ioctl (DEPRECATED)
*/
typedef struct bmc_reqrsp {
bmc_req_t req; /* request half */
bmc_rsp_t rsp; /* response half */
} bmc_reqrsp_t;
/*
* The new way of communicating with the bmc driver is to use putmsg() to
* send a message of a particular type. Replies from the driver also have this
* form, and will require the user to process the type field before examining
* the rest of the reply.
*
* The only change that must be observed when using the request and response
* structures defined above is as follows:
* when sending messages to the bmc driver, the data portion is now variable
* (the caller must allocate enough space to store the all structure members,
* plus enough space to cover the amount of data in the request), e.g.:
*
* bmc_msg_t *msg = malloc(offsetof(bmc_msg_t, msg) + sizeof(bmc_req_t) + 10);
*
* The amount allocated for the message is (# of bytes before the msg field) +
* the size of a bmc_req_t (which includes SEND_MAX_PAYLOAD_SIZE
* bytes in the data field), plus an additional 10 bytes for the data
* field (so the data field would occupy (SEND_MAX_PAYLOAD_SIZE + 10)
* bytes). The datalength member must reflect the amount of data in the
* request's data field (as was required when using the ioctl interface).
*/
typedef struct bmc_msg {
uint8_t m_type; /* Message type (see below) */
uint32_t m_id; /* Message ID */
uint8_t reserved[32];
uint8_t msg[1]; /* Variable length message data */
} bmc_msg_t;
/*
* An error response passed back from the bmc driver will have its m_id
* field set to BMC_UNKNOWN_MSG_ID if a message is sent to it that is not
* at least as large as a bmc_msg_t.
*/
#define BMC_UNKNOWN_MSG_ID ~((uint32_t)0)
/*
* Possible values for the m_type field in bmc_msg_t:
*/
#define BMC_MSG_REQUEST 1 /* BMC request (as above, sent to the */
/* driver by the user), bmc_msg.msg */
/* begins with the bmc_req_t */
/* structure. */
#define BMC_MSG_RESPONSE 2 /* BMC response (sent by the driver) */
/* bmc_msg.msg begins with the */
/* bmc_rsp_t structure. */
#define BMC_MSG_ERROR 3 /* Error while processing a user msg */
/* msg[0] is the error code */
/* (interpret as an errno value) */
#ifdef __cplusplus
}
#endif
#endif /* _BMC_INTF_H */

View File

@@ -0,0 +1,8 @@
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_dummy.la
noinst_LTLIBRARIES = @INTF_DUMMY_LIB@
libintf_dummy_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_dummy_la_SOURCES = dummy.c

286
src/plugins/dummy/dummy.c Normal file
View File

@@ -0,0 +1,286 @@
/* Copyright (c) 2013 Zdenek Styblik, All Rights Reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Zdenek Styblik or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* Zdenek Styblik SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* Zdenek Styblik BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF Zdenek Styblik HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/helper.h>
#include <ipmitool/log.h>
#include "dummy.h"
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
extern int verbose;
/* data_read - read data from socket
*
* @data_ptr - pointer to memory where to store read data
* @data_len - how much to read from socket
*
* return 0 on success, otherwise (-1)
*/
int
data_read(int fd, void *data_ptr, int data_len)
{
int rc = 0;
int data_read = 0;
int data_total = 0;
int try = 1;
int errno_save = 0;
if (data_len < 0) {
return (-1);
}
while (data_total < data_len && try < 4) {
errno = 0;
/* TODO - add poll() */
data_read = read(fd, data_ptr, data_len);
errno_save = errno;
if (data_read > 0) {
data_total+= data_read;
}
if (errno_save != 0) {
if (errno_save == EINTR || errno_save == EAGAIN) {
try++;
sleep(2);
continue;
} else {
errno = errno_save;
perror("dummy failed on read(): ");
rc = (-1);
break;
}
}
}
if (try > 3 && data_total != data_len) {
rc = (-1);
}
return rc;
}
/* data_write - write data to the socket
*
* @data_ptr - ptr to data to send
* @data_len - how long is the data to send
*
* returns 0 on success, otherwise (-1)
*/
int
data_write(int fd, void *data_ptr, int data_len)
{
int rc = 0;
int data_written = 0;
int data_total = 0;
int try = 1;
int errno_save = 0;
if (data_len < 0) {
return (-1);
}
while (data_total < data_len && try < 4) {
errno = 0;
/* TODO - add poll() */
data_written = write(fd, data_ptr, data_len);
errno_save = errno;
if (data_read > 0) {
data_total+= data_written;
}
if (errno_save != 0) {
if (errno_save == EINTR || errno_save == EAGAIN) {
try++;
sleep(2);
continue;
} else {
errno = errno_save;
perror("dummy failed on read(): ");
rc = (-1);
break;
}
}
}
if (try > 3 && data_total != data_len) {
rc = (-1);
}
return rc;
}
/* ipmi_dummyipmi_close - send "BYE" and close socket
*
* @intf - ptr to initialize ipmi_intf struct
*
* returns void
*/
static void
ipmi_dummyipmi_close(struct ipmi_intf *intf)
{
struct dummy_rq req;
int data_total = 0;
int data_written = 0;
int try = 0;
if (intf->fd < 0) {
return;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = 0x3f;
req.msg.cmd = 0xff;
if (data_write(intf->fd, &req, sizeof(req)) != 0) {
lprintf(LOG_ERR, "dummy failed to send 'BYE'");
}
close(intf->fd);
intf->fd = (-1);
intf->opened = 0;
}
/* ipmi_dummyipmi_open - open socket and prepare ipmi_intf struct
*
* @intf - ptr to ipmi_inf struct
*
* returns 0 on success, (-1) on error
*/
static int
ipmi_dummyipmi_open(struct ipmi_intf *intf)
{
struct sockaddr_un address;
int len;
int rc;
if (intf->opened == 1) {
return intf->fd;
}
intf->fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (intf->fd == (-1)) {
lprintf(LOG_ERR, "dummy failed on socket()");
return (-1);
}
address.sun_family = AF_UNIX;
strcpy(address.sun_path, DUMMY_SOCKET_PATH);
len = sizeof(address);
rc = connect(intf->fd, (struct sockaddr *)&address, len);
if (rc != 0) {
perror("dummy failed on connect(): ");
return (-1);
}
intf->opened = 1;
return intf->fd;
}
/* ipmi_dummyipmi_send_cmd - send IPMI payload and await reply
*
* @intf - ptr to initialized ipmi_intf struct
* @req - ptr to ipmi_rq struct to send
*
* return pointer to struct ipmi_rs OR NULL on error
*/
static struct ipmi_rs*
ipmi_dummyipmi_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req)
{
static struct ipmi_rs rsp;
struct dummy_rq req_dummy;
struct dummy_rs rsp_dummy;
if (intf == NULL || intf->fd < 0 || intf->opened != 1) {
lprintf(LOG_ERR, "dummy failed on intf check.");
return NULL;
}
memset(&req_dummy, 0, sizeof(req_dummy));
req_dummy.msg.netfn = req->msg.netfn;
req_dummy.msg.lun = req->msg.lun;
req_dummy.msg.cmd = req->msg.cmd;
req_dummy.msg.target_cmd = req->msg.target_cmd;
req_dummy.msg.data_len = req->msg.data_len;
req_dummy.msg.data = req->msg.data;
if (verbose) {
lprintf(LOG_NOTICE, ">>> IPMI req");
lprintf(LOG_NOTICE, "msg.data_len: %i",
req_dummy.msg.data_len);
lprintf(LOG_NOTICE, "msg.netfn: %x", req_dummy.msg.netfn);
lprintf(LOG_NOTICE, "msg.cmd: %x", req_dummy.msg.cmd);
lprintf(LOG_NOTICE, "msg.target_cmd: %x",
req_dummy.msg.target_cmd);
lprintf(LOG_NOTICE, "msg.lun: %x", req_dummy.msg.lun);
lprintf(LOG_NOTICE, ">>>");
}
if (data_write(intf->fd, &req_dummy,
sizeof(struct dummy_rq)) != 0) {
return NULL;
}
if (req->msg.data_len > 0) {
if (data_write(intf->fd, (uint8_t *)(req->msg.data),
req_dummy.msg.data_len) != 0) {
return NULL;
}
}
memset(&rsp_dummy, 0, sizeof(rsp_dummy));
if (data_read(intf->fd, &rsp_dummy, sizeof(struct dummy_rs)) != 0) {
return NULL;
}
if (rsp_dummy.data_len > 0) {
if (data_read(intf->fd, (uint8_t *)&rsp.data,
rsp_dummy.data_len) != 0) {
return NULL;
}
}
rsp.ccode = rsp_dummy.ccode;
rsp.data_len = rsp_dummy.data_len;
rsp.msg.netfn = rsp_dummy.msg.netfn;
rsp.msg.cmd = rsp_dummy.msg.cmd;
rsp.msg.seq = rsp_dummy.msg.seq;
rsp.msg.lun = rsp_dummy.msg.lun;
if (verbose) {
lprintf(LOG_NOTICE, "<<< IPMI rsp");
lprintf(LOG_NOTICE, "ccode: %x", rsp.ccode);
lprintf(LOG_NOTICE, "data_len: %i", rsp.data_len);
lprintf(LOG_NOTICE, "msg.netfn: %x", rsp.msg.netfn);
lprintf(LOG_NOTICE, "msg.cmd: %x", rsp.msg.cmd);
lprintf(LOG_NOTICE, "msg.seq: %x", rsp.msg.seq);
lprintf(LOG_NOTICE, "msg.lun: %x", rsp.msg.lun);
lprintf(LOG_NOTICE, "<<<");
}
return &rsp;
}
struct ipmi_intf ipmi_dummy_intf = {
name: "dummy",
desc: "Linux DummyIPMI Interface",
open: ipmi_dummyipmi_open,
close: ipmi_dummyipmi_close,
sendrecv: ipmi_dummyipmi_send_cmd,
my_addr: IPMI_BMC_SLAVE_ADDR,
target_addr: IPMI_BMC_SLAVE_ADDR,
};

30
src/plugins/dummy/dummy.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef IPMI_DUMMYIPMI_H
# define IPMI_DUMMYIPMI_H
# define DUMMY_SOCKET_PATH "/tmp/.ipmi_dummy"
struct dummy_rq {
struct {
uint8_t netfn;
uint8_t lun;
uint8_t cmd;
uint8_t target_cmd;
uint16_t data_len;
uint8_t *data;
} msg;
};
struct dummy_rs {
struct {
uint8_t netfn;
uint8_t cmd;
uint8_t seq;
uint8_t lun;
} msg;
uint8_t ccode;
int data_len;
uint8_t *data;
};
#endif

View File

@@ -0,0 +1,9 @@
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_free.la
noinst_LTLIBRARIES = @INTF_FREE_LIB@
libintf_free_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_free_la_SOURCES = free.c
libintf_free_la_LDFLAGS = -lfreeipmi

318
src/plugins/free/free.c Normal file
View File

@@ -0,0 +1,318 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
*/
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <freeipmi/freeipmi.h>
#if IPMI_INTF_FREE_0_3_0 || IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
#include <freeipmi/udm/ipmi-udm.h>
#endif
#if IPMI_INTF_FREE_0_6_0
ipmi_ctx_t dev = NULL;
#else /* !IPMI_INTF_FREE_0_6_0 */
ipmi_device_t dev = NULL;
#endif /* !IPMI_INTF_FREE_0_6_0 */
extern int verbose;
static int ipmi_free_open(struct ipmi_intf * intf)
{
int kcs_ret = -1, ssif_ret = -1;
if (getuid() != 0) {
fprintf(stderr, "Permission denied, must be root\n");
return -1;
}
#if IPMI_INTF_FREE_0_3_0
if (!(dev = ipmi_open_inband (IPMI_DEVICE_KCS,
0,
0,
0,
NULL,
IPMI_FLAGS_DEFAULT))) {
if (!(dev = ipmi_open_inband (IPMI_DEVICE_SSIF,
0,
0,
0,
NULL,
IPMI_FLAGS_DEFAULT))) {
perror("ipmi_open_inband()");
goto cleanup;
}
}
#elif IPMI_INTF_FREE_0_4_0
if (!(dev = ipmi_device_create())) {
perror("ipmi_device_create");
goto cleanup;
}
if (ipmi_open_inband (dev,
IPMI_DEVICE_KCS,
0,
0,
0,
NULL,
IPMI_FLAGS_DEFAULT) < 0) {
if (ipmi_open_inband (dev,
IPMI_DEVICE_SSIF,
0,
0,
0,
NULL,
IPMI_FLAGS_DEFAULT) < 0) {
fprintf(stderr,
"ipmi_open_inband(): %s\n",
ipmi_device_strerror(ipmi_device_errnum(dev)));
goto cleanup;
}
}
#elif IPMI_INTF_FREE_0_5_0
if (!(dev = ipmi_device_create())) {
perror("ipmi_device_create");
goto cleanup;
}
if (ipmi_open_inband (dev,
IPMI_DEVICE_KCS,
0,
0,
0,
NULL,
0,
IPMI_FLAGS_DEFAULT) < 0) {
if (ipmi_open_inband (dev,
IPMI_DEVICE_SSIF,
0,
0,
0,
NULL,
0,
IPMI_FLAGS_DEFAULT) < 0) {
fprintf(stderr,
"ipmi_open_inband(): %s\n",
ipmi_device_strerror(ipmi_device_errnum(dev)));
goto cleanup;
}
}
#elif IPMI_INTF_FREE_0_6_0
if (!(dev = ipmi_ctx_create())) {
perror("ipmi_ctx_create");
goto cleanup;
}
if (ipmi_ctx_open_inband (dev,
IPMI_DEVICE_KCS,
0,
0,
0,
NULL,
0,
IPMI_FLAGS_DEFAULT) < 0) {
if (ipmi_ctx_open_inband (dev,
IPMI_DEVICE_SSIF,
0,
0,
0,
NULL,
0,
IPMI_FLAGS_DEFAULT) < 0) {
fprintf(stderr,
"ipmi_open_inband(): %s\n",
ipmi_ctx_strerror(ipmi_ctx_errnum(dev)));
goto cleanup;
}
}
#endif
intf->opened = 1;
intf->manufacturer_id = ipmi_get_oem(intf);
return 0;
cleanup:
if (dev) {
#if IPMI_INTF_FREE_0_3_0
ipmi_close_device(dev);
#elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
ipmi_close_device(dev);
ipmi_device_destroy(dev);
#elif IPMI_INTF_FREE_0_6_0
ipmi_ctx_close(dev);
ipmi_ctx_destroy(dev);
#endif
}
return -1;
}
static void ipmi_free_close(struct ipmi_intf * intf)
{
if (dev) {
#if IPMI_INTF_FREE_0_3_0
ipmi_close_device(dev);
#elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
ipmi_close_device(dev);
ipmi_device_destroy(dev);
#elif IPMI_INTF_FREE_0_6_0
ipmi_ctx_close(dev);
ipmi_ctx_destroy(dev);
#endif
}
intf->opened = 0;
intf->manufacturer_id = IPMI_OEM_UNKNOWN;
}
static struct ipmi_rs * ipmi_free_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
{
u_int8_t lun = req->msg.lun;
u_int8_t cmd = req->msg.cmd;
u_int8_t netfn = req->msg.netfn;
u_int8_t rq_buf[IPMI_BUF_SIZE];
u_int8_t rs_buf[IPMI_BUF_SIZE];
u_int32_t rs_buf_len = IPMI_BUF_SIZE;
int32_t rs_len;
static struct ipmi_rs rsp;
/* achu: FreeIPMI requests have the cmd as the first byte of
* the data. Responses have cmd as the first byte and
* completion code as the second byte. This differs from some
* other APIs, so it must be compensated for within the ipmitool
* interface.
*/
if (!intf || !req)
return NULL;
if (!intf->opened && intf->open && intf->open(intf) < 0)
return NULL;
if (req->msg.data_len > IPMI_BUF_SIZE)
return NULL;
memset(rq_buf, '\0', IPMI_BUF_SIZE);
memset(rs_buf, '\0', IPMI_BUF_SIZE);
memcpy(rq_buf, &cmd, 1);
if (req->msg.data)
memcpy(rq_buf + 1, req->msg.data, req->msg.data_len);
if (intf->target_addr != 0
&& intf->target_addr != IPMI_BMC_SLAVE_ADDR) {
#if IPMI_INTF_FREE_BRIDGING
if ((rs_len = ipmi_cmd_raw_ipmb(dev,
intf->target_channel,
intf->target_addr,
lun,
netfn,
rq_buf,
req->msg.data_len + 1,
rs_buf,
rs_buf_len)) < 0) {
if (verbose > 3)
fprintf(stderr,
"ipmi_cmd_raw_ipmb: %s\n",
ipmi_ctx_strerror(ipmi_ctx_errnum(dev)));
/* Compared to FreeIPMI, user is expected to input
* the target channel on the command line, it is not automatically
* discovered. So that is the likely cause of an error.
*
* Instead of returning an error, return a bad response so output
* of ipmitool commands looks like other interfaces
*/
rs_len = 2;
rs_buf[0] = 0;
rs_buf[1] = 0xC1; /* invalid command */
}
#else /* !IPMI_INTF_FREE_BRIDGING */
if (verbose > 3)
fprintf(stderr, "sensor bridging not supported in this driver version");
/* instead of returning an error, return a bad response so output
* of ipmitool commands looks like other interfaces
*/
rs_len = 2;
rs_buf[0] = 0;
rs_buf[1] = 0xC1; /* invalid command */
#endif /* !IPMI_INTF_FREE_BRIDGING */
}
else {
if ((rs_len = ipmi_cmd_raw(dev,
lun,
netfn,
rq_buf,
req->msg.data_len + 1,
rs_buf,
rs_buf_len)) < 0) {
#if IPMI_INTF_FREE_0_3_0
perror("ipmi_cmd_raw");
#elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
fprintf(stderr,
"ipmi_cmd_raw: %s\n",
ipmi_device_strerror(ipmi_device_errnum(dev)));
#elif IPMI_INTF_FREE_0_6_0
fprintf(stderr,
"ipmi_cmd_raw: %s\n",
ipmi_ctx_strerror(ipmi_ctx_errnum(dev)));
#endif
return NULL;
}
}
memset(&rsp, 0, sizeof(struct ipmi_rs));
rsp.ccode = (unsigned char)rs_buf[1];
rsp.data_len = (int)rs_len - 2;
if (!rsp.ccode && rsp.data_len)
memcpy(rsp.data, rs_buf + 2, rsp.data_len);
return &rsp;
}
struct ipmi_intf ipmi_free_intf = {
name: "free",
desc: "FreeIPMI IPMI Interface",
open: ipmi_free_open,
close: ipmi_free_close,
sendrecv: ipmi_free_send_cmd,
target_addr: IPMI_BMC_SLAVE_ADDR,
};

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_imb.la
noinst_LTLIBRARIES = @INTF_IMB_LIB@
libintf_imb_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_imb_la_SOURCES = imbapi.c imbapi.h imb.c

131
src/plugins/imb/imb.c Normal file
View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/helper.h>
#include "imbapi.h"
#define IPMI_IMB_TIMEOUT (1000 * 1000)
#define IPMI_IMB_MAX_RETRY 3
#define IPMI_IMB_DEV "/dev/imb"
#define IPMI_IMB_BUF_SIZE 64
extern int verbose;
static int ipmi_imb_open(struct ipmi_intf * intf)
{
struct stat stbuf;
if (stat(IPMI_IMB_DEV, &stbuf) < 0) {
printf("Error: no IMB driver found at %s!\n", IPMI_IMB_DEV);
return -1;
}
intf->opened = 1;
intf->manufacturer_id = ipmi_get_oem(intf);
return 0;
}
static void ipmi_imb_close(struct ipmi_intf * intf)
{
intf->opened = 0;
intf->manufacturer_id = IPMI_OEM_UNKNOWN;
}
static struct ipmi_rs * ipmi_imb_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
{
IMBPREQUESTDATA imbreq;
static struct ipmi_rs rsp;
int status, i;
unsigned char ccode;
imbreq.rsSa = IPMI_BMC_SLAVE_ADDR;
imbreq.rsLun = 0;
imbreq.busType = 0;
imbreq.netFn = req->msg.netfn;
imbreq.cmdType = req->msg.cmd;
imbreq.data = req->msg.data;
imbreq.dataLength = req->msg.data_len;
if (verbose > 1) {
printf("IMB rsSa : %x\n", imbreq.rsSa);
printf("IMB netFn : %x\n", imbreq.netFn);
printf("IMB cmdType : %x\n", imbreq.cmdType);
printf("IMB dataLength : %d\n", imbreq.dataLength);
}
rsp.data_len = IPMI_IMB_BUF_SIZE;
memset(rsp.data, 0, rsp.data_len);
for (i=0; i<IPMI_IMB_MAX_RETRY; i++) {
if (verbose > 2)
printbuf(imbreq.data, imbreq.dataLength, "ipmi_imb request");
status = SendTimedImbpRequest(&imbreq, IPMI_IMB_TIMEOUT,
rsp.data, &rsp.data_len, &ccode);
if (status == 0) {
if (verbose > 2)
printbuf(rsp.data, rsp.data_len, "ipmi_imb response");
break;
}
/* error */
printf("Error sending IMB request, status=%x ccode=%x\n",
status, ccode);
}
rsp.ccode = ccode;
return &rsp;
}
struct ipmi_intf ipmi_imb_intf = {
name: "imb",
desc: "Intel IMB Interface",
open: ipmi_imb_open,
close: ipmi_imb_close,
sendrecv: ipmi_imb_send_cmd,
target_addr: IPMI_BMC_SLAVE_ADDR,
};

2090
src/plugins/imb/imbapi.c Normal file

File diff suppressed because it is too large Load Diff

652
src/plugins/imb/imbapi.h Normal file
View File

@@ -0,0 +1,652 @@
/*M*
// PVCS:
// $Workfile: imb_api.h $
// $Revision: 1.2 $
// $Modtime: Jul 22 2002 16:40:32 $
// $Author: iceblink $
//
// Combined include files needed for imbapi.c
//
*M*/
/*----------------------------------------------------------------------*
The BSD License
Copyright (c) 2002, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
a.. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
b.. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
c.. Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------*/
#ifndef _WINDEFS_H
#define _WINDEFS_H
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef WIN32
/* WIN32 defines this in stdio.h */
#ifndef _WCHAR_T
#define _WCHAR_T
typedef long wchar_t;
#endif
#endif
#define far
#define near
#define FAR far
#define NEAR near
#ifndef CONST
#define CONST const
#endif
typedef unsigned long DWORD;
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef float FLOAT;
typedef FLOAT *PFLOAT;
typedef BOOL near *PBOOL;
typedef BOOL far *LPBOOL;
typedef BYTE near *PBYTE;
typedef BYTE far *LPBYTE;
typedef int near *PINT;
typedef int far *LPINT;
typedef WORD near *PWORD;
typedef WORD far *LPWORD;
typedef long far *LPLONG;
typedef DWORD near *PDWORD;
typedef DWORD far *LPDWORD;
typedef void far *LPVOID;
typedef CONST void far *LPCVOID;
typedef int INT;
typedef unsigned int UINT;
typedef unsigned int *PUINT;
typedef DWORD NTSTATUS;
/*
File structures
*/
#ifndef WIN32
typedef struct _OVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
/* HANDLE hEvent; */
} OVERLAPPED, *LPOVERLAPPED;
#endif
/*
* Data structure redefines
*/
typedef char CHAR;
typedef short SHORT;
typedef long LONG;
typedef char * PCHAR;
typedef short * PSHORT;
typedef long * PLONG;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
typedef unsigned char * PUCHAR;
typedef unsigned short * PUSHORT;
typedef unsigned long * PULONG;
typedef char CCHAR;
typedef short CSHORT;
typedef ULONG CLONG;
typedef CCHAR * PCCHAR;
typedef CSHORT * PCSHORT;
typedef CLONG * PCLONG;
typedef void * PVOID;
#ifndef WIN32
typedef void VOID;
typedef struct _LARGE_INTEGER {
ULONG LowPart;
LONG HighPart;
} LARGE_INTEGER;
typedef struct _ULARGE_INTEGER {
ULONG LowPart;
ULONG HighPart;
} ULARGE_INTEGER;
#endif
typedef LARGE_INTEGER * PLARGE_INTEGER;
typedef LARGE_INTEGER PHYSICAL_ADDRESS;
typedef LARGE_INTEGER * PPHYSICAL_ADDRESS;
typedef ULARGE_INTEGER * PULARGE_INTEGER;
typedef UCHAR BOOLEAN;
typedef BOOLEAN *PBOOLEAN;
typedef wchar_t WCHAR;
typedef WCHAR *PWCHAR, *PWSTR;
typedef CONST WCHAR *LPCWSTR, *PCWSTR;
#ifndef _SYS_TYPES_H
#ifndef _CADDR_T
#define _CADDR_T
typedef char * caddr_t;
#endif
#endif
/*
Unicode strings are counted 16-bit character strings. If they are
NULL terminated, Length does not include trailing NULL.
*/
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
#define UNICODE_NULL ((WCHAR)0) /* winnt*/
#define IN /* */
#define OUT /* */
#define OPTIONAL /* */
#ifndef WIN32
#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#define UNREFERENCED_PARAMETER(x)
typedef int HANDLE;
#define INVALID_HANDLE_VALUE ((HANDLE)-1)
#endif
typedef HANDLE *PHANDLE;
/*
Define the method codes for how buffers are passed for I/O and FS controls
*/
#define METHOD_BUFFERED 0
/*
Define the access check value for any access
The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in
ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these
constants *MUST* always be in sync.
*/
#define FILE_ANY_ACCESS 0
/*
These are the generic rights.
*/
#define MAX_PATH 260
#define GetLastError() (NTstatus.Status)
/*
Macro definition for defining IOCTL and FSCTL function control codes. Note
that function codes 0-2047 are reserved for Microsoft Corporation, and
2048-4095 are reserved for customers.
*/
/*
* Linux drivers expect ioctls defined using macros defined in ioctl.h.
* So, instead of using the CTL_CODE defined for NT and UW, I define CTL_CODE
* using these macros. That way imb_if.h, where the ioctls are defined get
* to use the correct ioctl command we expect.
* Notes: I am using the generic _IO macro instead of the more specific
* ones. The macros expect 8bit entities, so I am cleaning what is sent to
* us from imb_if.h - Mahendra
*/
#ifndef WIN32
#define CTL_CODE(DeviceType, Function, Method, Access)\
_IO(DeviceType & 0x00FF, Function & 0x00FF)
#else
#define CTL_CODE( DeviceType, Function, Method, Access ) ((ULONG)( \
((ULONG)(DeviceType) << 16) | ((ULONG)(Access) << 14) | ((ULONG)(Function) << 2) | ((ULONG)Method) \
))
#endif
#endif /*_WINDEFS_H */
/*----------------------------------------------------------------------*/
#ifndef _SMI_H
#define _SMI_H
#define SMI_Version1_00 0x00001000
struct smi {
DWORD smi_VersionNo;
DWORD smi_Reserved1;
DWORD smi_Reserved2;
LPVOID ntstatus; /* address of NT status block*/
LPVOID lpvInBuffer; /* address of buffer for input data*/
DWORD cbInBuffer; /* size of input buffer*/
LPVOID lpvOutBuffer; /* address of output buffer*/
DWORD cbOutBuffer; /* size of output buffer*/
LPDWORD lpcbBytesReturned; /* address of actual bytes of output*/
LPOVERLAPPED lpoOverlapped; /* address of overlapped structure*/
};
#ifndef STATUS_SUCCESS
typedef struct _IO_STATUS_BLOCK {
ULONG Status;
ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
/*
* I2C ioctl's return NTStatus codes
*/
#define STATUS_SUCCESS (0x00000000U)
#define STATUS_UNSUCCESSFUL (0xC0000001U)
#define STATUS_DEVICE_BUSY (0x80000011U)
#ifndef WIN32
#define STATUS_PENDING (0x00000103U)
// see <win2000ddk>\inc\winnt.h(1171)
#endif
#define STATUS_INVALID_PARAMETER (0xC000000DU)
#define STATUS_INVALID_DEVICE_REQUEST (0xC0000010U)
#define STATUS_BUFFER_TOO_SMALL (0xC0000023U)
#define STATUS_FILE_CLOSED (0xC0000128U)
#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AU)
#define STATUS_NO_DATA_DETECTED (0x80000022U)
#define STATUS_NO_SUCH_DEVICE (0xC000000EU)
#define STATUS_ALLOTTED_EXCEEDED (0xC000000FU)
#define STATUS_IO_DEVICE_ERROR (0xC0000185U)
#define STATUS_TOO_MANY_OPEN_FILES (0xC000011FU)
#define STATUS_ACCESS_DENIED (0xC0000022U)
#define STATUS_BUFFER_OVERFLOW (0x80000005U)
#define STATUS_CANCELLED (0xC0000120U)
#endif /* STATUS_SUCCESS*/
#endif /* _SMI_H*/
/*----------------------------------------------------------------------*/
#ifndef IMB_IF__
#define IMB_IF__
/*
* This is the structure passed in to the IOCTL_IMB_SHUTDOWN_CODE request
*/
typedef struct {
int code;
int delayTime;
} ShutdownCmdBuffer;
#define SD_NO_ACTION 0
#define SD_RESET 1
#define SD_POWER_OFF 2
#pragma pack(1)
/*
* This is the generic IMB packet format, the final checksum cant be
* represented in this structure and will show up as the last data byte
*/
typedef struct {
BYTE rsSa;
BYTE nfLn;
BYTE cSum1;
BYTE rqSa;
BYTE seqLn;
BYTE cmd;
BYTE data[1];
} ImbPacket;
#define MIN_IMB_PACKET_SIZE 7
#define MAX_IMB_PACKET_SIZE 33
/*
* This is the standard IMB response format where the first byte of
* IMB packet data is interpreted as a command completion code.
*/
typedef struct {
BYTE rsSa;
BYTE nfLn;
BYTE cSum1;
BYTE rqSa;
BYTE seqLn;
BYTE cmd;
BYTE cCode;
BYTE data[1];
} ImbRespPacket;
#define MIN_IMB_RESPONSE_SIZE 7 /* min packet + completion code */
#define MAX_IMB_RESPONSE_SIZE MAX_IMB_PACKET_SIZE
/************************
* ImbRequestBuffer
************************/
/*D*
// Name: ImbRequestBuffer
// Purpose: Structure definition for holding IMB message data
// Context: Used by SendTimedImbpMessage and SendTimedI2cMessge
// functions in the library interface. In use, it is overlayed on a
// char buffer of size MIN_IMB_REQ_BUF_SIZE +
// Fields:
// respBufSize size of the response buffer
//
// timeout timeout value in milli seconds
//
// req body of request to send
//
*D*/
typedef struct {
BYTE rsSa;
BYTE cmd;
BYTE netFn;
BYTE rsLun;
BYTE dataLength;
BYTE data[1];
} ImbRequest;
typedef struct {
DWORD flags; /* request flags*/
#define NO_RESPONSE_EXPECTED 0x01 /*dont wait around for an IMB response*/
DWORD timeOut; /* in uSec units*/
ImbRequest req; /* message buffer*/
} ImbRequestBuffer;
#define MIN_IMB_REQ_BUF_SIZE 13 /* a buffer without any request data*/
/************************
* ImbResponseBuffer
************************/
/*D*
// Name: ImbResponseBuffer
// Purpose: Structure definition for response of a previous send
// Context: Used by DeviceIoControl to pass the message to be sent to
// MISSMIC port
// Fields:
// cCode completion code returned by firmware
// data buffer for response data from firmware
*D*/
typedef struct {
BYTE cCode;
BYTE data[1];
} ImbResponseBuffer;
#define MIN_IMB_RESP_BUF_SIZE 1
#define MAX_IMB_RESP_SIZE (MIN_IMB_RESP_BUF_SIZE + MAX_IMB_RESPONSE_SIZE)
#pragma pack()
/*
* Async message access structures and types
*/
typedef DWORD ImbAsyncSeq;
/*
* This is the structure passed in to IOCTL_IMB_GET_ASYNC_MSG
*/
typedef struct {
DWORD timeOut;
ImbAsyncSeq lastSeq;
} ImbAsyncRequest;
#define ASYNC_SEQ_START 0
typedef struct {
ImbAsyncSeq thisSeq;
BYTE data[1];
} ImbAsyncResponse;
#define MIN_ASYNC_RESP_SIZE sizeof( ImbAsyncSeq )
#define MAX_ASYNC_RESP_SIZE (MIN_ASYNC_RESP_SIZE + MAX_IMB_PACKET_SIZE)
/*
** Driver Ioctls
** In Linux, these calculate to:
** IOCTL_IMB_SEND_MESSAGE =1082
** IOCTL_IMB_GET_ASYNC_MSG =1088
** IOCTL_IMB_MAP_MEMORY =108e
** IOCTL_IMB_UNMAP_MEMORY =1090
** IOCTL_IMB_SHUTDOWN_CODE =1092
** IOCTL_IMB_REGISTER_ASYNC_OBJ =1098
** IOCTL_IMB_DEREGISTER_ASYNC_OBJ=109a
** IOCTL_IMB_CHECK_EVENT =109c
** IOCTL_IMB_POLL_ASYNC =1094
*/
#define FILE_DEVICE_IMB 0x00008010
#define IOCTL_IMB_BASE 0x00000880
#define IOCTL_IMB_SEND_MESSAGE CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_GET_ASYNC_MSG CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 8), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_MAP_MEMORY CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 14), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_UNMAP_MEMORY CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 16), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_SHUTDOWN_CODE CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 18), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_REGISTER_ASYNC_OBJ CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 24), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_DEREGISTER_ASYNC_OBJ CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 26), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_CHECK_EVENT CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 28), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IMB_POLL_ASYNC CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 20), METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif /* IMB_IF__ */
/*----------------------------------------------------------------------*/
/* No asynchronous messages available */
#define IMB_MSG_NOT_AVAILABLE ((NTSTATUS)0xE0070012L)
#ifdef IMBLOG_H__
/* Define the facility codes */
#define FACILITY_RPC_STUBS 0x3
#define FACILITY_RPC_RUNTIME 0x2
#define FACILITY_IO_ERROR_CODE 0x4
#define IMB_IO_ERROR_CODE 0x7
#define STATUS_SEVERITY_WARNING 0x2
#define STATUS_SEVERITY_SUCCESS 0x0
#define STATUS_SEVERITY_INFORMATIONAL 0x1
#define STATUS_SEVERITY_ERROR 0x3
/* Not enough memory for internal storage of device %1. */
#define INSUFFICIENT_RESOURCES ((NTSTATUS)0xE0070001L)
#define INVALID_INPUT_BUFFER ((NTSTATUS)0xE0070002L)
#define INVALID_OUTPUT_BUFFER ((NTSTATUS)0xE0070003L)
#define IMB_SEND_TIMEOUT ((NTSTATUS)0xE0070004L)
#define IMB_RECEIVE_TIMEOUT ((NTSTATUS)0xE0070005L)
#define IMB_IF_SEND_TIMEOUT ((NTSTATUS)0xE0070006L)
#define IMB_IF_RECEIVE_TIMEOUT ((NTSTATUS)0xE0040007L)
#define HARDWARE_FAILURE ((NTSTATUS)0xE0040008L)
#define DRIVER_FAILURE ((NTSTATUS)0xE0040009L)
#define IMB_INVALID_IF_RESPONSE ((NTSTATUS)0xE004000AL)
#define IMB_INVALID_PACKET ((NTSTATUS)0xE004000BL)
#define IMB_RESPONSE_DATA_OVERFLOW ((NTSTATUS)0xE004000CL)
#define IMB_INVALID_REQUEST ((NTSTATUS)0xE007000DL)
#define INVALID_DRIVER_IOCTL ((NTSTATUS)0xE007000EL)
#define INVALID_DRIVER_REQUEST ((NTSTATUS)0xE007000FL)
#define IMB_CANT_GET_SMS_BUFFER ((NTSTATUS)0xE0070010L)
#define INPUT_BUFFER_TOO_SMALL ((NTSTATUS)0xE0070011L)
#define IMB_SEND_ERROR ((NTSTATUS)0xE0070013L)
#endif /* IMBLOG_H__ */
/*----------------------------------------------------------------------*/
#ifndef IMBAPI_H__
#define IMBAPI_H__
#include <sys/types.h>
#define WRITE_READ_I2C 0x52
#define WRITE_EMP_BUFFER 0x7a
#define GET_DEVICE_ID 0x1
#define SEND_MESSAGE 0x34
#define BMC_SA 0x20
#define BMC_LUN 0
#define APP_NETFN 0x06
#define IPMI_09_VERSION 0x90
#define IPMI_10_VERSION 0x01
#define IPMI_15_VERSION 0x51
#ifndef IPMI10_GET_DEVICE_ID_RESP_LENGTH
#define IPMI10_GET_DEVICE_ID_RESP_LENGTH 12
#endif
#define IPMB_CHANNEL 0x0
#define EMP_CHANNEL 0x1
#define LAN_CHANNEL 0x2
#define RESERVED_LUN 0x3
#define IPMB_LUN 0x2
#define EMP_LUN 0x0
#define PUBLIC_BUS 0
#define BMC_CONTROLLER 0x20
#define FPC_CONTROLLER 0x22
typedef enum {
ACCESN_OK,
ACCESN_ERROR,
ACCESN_OUT_OF_RANGE,
ACCESN_END_OF_DATA,
ACCESN_UNSUPPORTED,
ACCESN_INVALID_TRANSACTION,
ACCESN_TIMED_OUT
} ACCESN_STATUS;
#pragma pack(1)
/*
* Request structure provided to SendTimedImbpRequest()
*/
typedef struct {
unsigned char cmdType;
unsigned char rsSa;
unsigned char busType;
unsigned char netFn;
unsigned char rsLun;
unsigned char * data;
int dataLength;
} IMBPREQUESTDATA;
/*
* Request structure provided to SendTimedI2cRequest()
*/
typedef struct {
unsigned char rsSa;
unsigned char busType;
unsigned char numberOfBytesToRead;
unsigned char * data;
int dataLength;
} I2CREQUESTDATA;
#pragma pack()
/*#ifdef IMB_API
*
* This section is provided to be able to compile using imb_if.h
*
*
* function return type. This is also defined in the local instrumentation
* so we ifdef here to avoid conflict.
*/
#define METHOD_BUFFERED 0
#define FILE_ANY_ACCESS 0
/*
* This is necessary to compile using memIf.h
*/
typedef enum _INTERFACE_TYPE
{
Internal,
Isa,
Eisa,
MicroChannel,
TurboChannel,
MaximumInterfaceType
} INTERFACE_TYPE, * PINTERFACE_TYPE;
#ifdef WIN32
/* From memIf.h */
#pragma pack(1)
typedef struct
{
INTERFACE_TYPE InterfaceType; // Isa, Eisa, etc....
ULONG BusNumber; // Bus number
PHYSICAL_ADDRESS BusAddress; // Bus-relative address
ULONG AddressSpace; // 0 is memory, 1 is I/O
ULONG Length; // Length of section to map
} PHYSICAL_MEMORY_INFO, * PPHYSICAL_MEMORY_INFO;
#pragma pack()
#endif
/*#else // not IMB_API */
/*
* These are defined in imb_if.h but are needed by users of the imbapi library
*/
#define ASYNC_SEQ_START 0
/*
* This is the generic IMB packet format, the final checksum cant be
* represented in this structure and will show up as the last data byte
*/
/*
#define MIN_IMB_PACKET_SIZE 7
#define MAX_IMB_PACKET_SIZE 33
*/
#define MAX_BUFFER_SIZE 64
/*#endif // IMB_API */
/******************************
* FUNCTION PROTOTYPES
******************************/
ACCESN_STATUS
SendTimedImbpRequest (
IMBPREQUESTDATA *reqPtr,
int timeOut,
BYTE * respDataPtr,
int * respDataLen,
BYTE * completionCode
);
ACCESN_STATUS
SendTimedI2cRequest (
I2CREQUESTDATA *reqPtr,
int timeOut,
BYTE * respDataPtr,
int * respDataLen,
BYTE * completionCode
);
ACCESN_STATUS
SendAsyncImbpRequest (
IMBPREQUESTDATA *reqPtr,
BYTE * seqNo
);
ACCESN_STATUS
GetAsyncImbpMessage (
ImbPacket * msgPtr,
DWORD * msgLen,
DWORD timeOut,
ImbAsyncSeq * seqNo,
DWORD channelNumber
);
ACCESN_STATUS
GetAsyncImbpMessage_Ex (
ImbPacket * msgPtr,
DWORD * msgLen,
DWORD timeOut,
ImbAsyncSeq * seqNo,
DWORD channelNumber,
BYTE * sessionHandle,
BYTE * privilege
);
ACCESN_STATUS
UnmapPhysicalMemory( int virtualAddress, int Length );
ACCESN_STATUS
StartAsyncMesgPoll(void);
ACCESN_STATUS
MapPhysicalMemory (
int startAddress,
int addressLength,
int *virtualAddress
);
ACCESN_STATUS
SetShutDownCode (
int delayTime,
int code
);
ACCESN_STATUS
SendTimedEmpMessageResponse (
ImbPacket * ptr,
char *responseDataBuf,
int responseDataLen,
int timeOut
);
ACCESN_STATUS
SendTimedEmpMessageResponse_Ex (
ImbPacket * ptr,
char *responseDataBuf,
int responseDataLen,
int timeOut,
BYTE sessionHandle,
BYTE channelNumber
);
ACCESN_STATUS
SendTimedLanMessageResponse (
ImbPacket * ptr,
char *responseDataBuf,
int responseDataLen,
int timeOut
);
ACCESN_STATUS
SendTimedLanMessageResponse_Ex (
ImbPacket * ptr,
char *responseDataBuf,
int responseDataLen,
int timeOut ,
BYTE sessionHandle,
BYTE channelNumber
);
ACCESN_STATUS
IsAsyncMessageAvailable (unsigned int eventId );
ACCESN_STATUS
RegisterForImbAsyncMessageNotification (unsigned int *handleId);
ACCESN_STATUS
UnRegisterForImbAsyncMessageNotification (unsigned int handleId,int iFlag);
BYTE GetIpmiVersion(void);
#endif /* IMBAPI_H__ */

499
src/plugins/ipmi_intf.c Normal file
View File

@@ -0,0 +1,499 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_sdr.h>
#include <ipmitool/log.h>
#ifdef IPMI_INTF_OPEN
extern struct ipmi_intf ipmi_open_intf;
#endif
#ifdef IPMI_INTF_IMB
extern struct ipmi_intf ipmi_imb_intf;
#endif
#ifdef IPMI_INTF_LIPMI
extern struct ipmi_intf ipmi_lipmi_intf;
#endif
#ifdef IPMI_INTF_BMC
extern struct ipmi_intf ipmi_bmc_intf;
#endif
#ifdef IPMI_INTF_LAN
extern struct ipmi_intf ipmi_lan_intf;
#endif
#ifdef IPMI_INTF_LANPLUS
extern struct ipmi_intf ipmi_lanplus_intf;
#endif
#ifdef IPMI_INTF_FREE
extern struct ipmi_intf ipmi_free_intf;
#endif
#ifdef IPMI_INTF_SERIAL
extern struct ipmi_intf ipmi_serial_term_intf;
extern struct ipmi_intf ipmi_serial_bm_intf;
#endif
#ifdef IPMI_INTF_DUMMY
extern struct ipmi_intf ipmi_dummy_intf;
#endif
struct ipmi_intf * ipmi_intf_table[] = {
#ifdef IPMI_INTF_OPEN
&ipmi_open_intf,
#endif
#ifdef IPMI_INTF_IMB
&ipmi_imb_intf,
#endif
#ifdef IPMI_INTF_LIPMI
&ipmi_lipmi_intf,
#endif
#ifdef IPMI_INTF_BMC
&ipmi_bmc_intf,
#endif
#ifdef IPMI_INTF_LAN
&ipmi_lan_intf,
#endif
#ifdef IPMI_INTF_LANPLUS
&ipmi_lanplus_intf,
#endif
#ifdef IPMI_INTF_FREE
&ipmi_free_intf,
#endif
#ifdef IPMI_INTF_SERIAL
&ipmi_serial_term_intf,
&ipmi_serial_bm_intf,
#endif
#ifdef IPMI_INTF_DUMMY
&ipmi_dummy_intf,
#endif
NULL
};
/* ipmi_intf_print - Print list of interfaces
*
* no meaningful return code
*/
void ipmi_intf_print(struct ipmi_intf_support * intflist)
{
struct ipmi_intf ** intf;
struct ipmi_intf_support * sup;
int def = 1;
int found;
lprintf(LOG_NOTICE, "Interfaces:");
for (intf = ipmi_intf_table; intf && *intf; intf++) {
if (intflist != NULL) {
found = 0;
for (sup=intflist; sup->name != NULL; sup++) {
if (strncmp(sup->name, (*intf)->name, strlen(sup->name)) == 0 &&
strncmp(sup->name, (*intf)->name, strlen((*intf)->name)) == 0 &&
sup->supported == 1)
found = 1;
}
if (found == 0)
continue;
}
lprintf(LOG_NOTICE, "\t%-12s %s %s",
(*intf)->name, (*intf)->desc,
def ? "[default]" : "");
def = 0;
}
lprintf(LOG_NOTICE, "");
}
/* ipmi_intf_load - Load an interface from the interface table above
* If no interface name is given return first entry
*
* @name: interface name to try and load
*
* returns pointer to inteface structure if found
* returns NULL on error
*/
struct ipmi_intf * ipmi_intf_load(char * name)
{
struct ipmi_intf ** intf;
struct ipmi_intf * i;
if (name == NULL) {
i = ipmi_intf_table[0];
if (i->setup != NULL && (i->setup(i) < 0)) {
lprintf(LOG_ERR, "Unable to setup "
"interface %s", name);
return NULL;
}
return i;
}
for (intf = ipmi_intf_table;
((intf != NULL) && (*intf != NULL));
intf++) {
i = *intf;
if (strncmp(name, i->name, strlen(name)) == 0) {
if (i->setup != NULL && (i->setup(i) < 0)) {
lprintf(LOG_ERR, "Unable to setup "
"interface %s", name);
return NULL;
}
return i;
}
}
return NULL;
}
void
ipmi_intf_session_set_hostname(struct ipmi_intf * intf, char * hostname)
{
if (intf->session == NULL)
return;
memset(intf->session->hostname, 0, 16);
if (hostname != NULL) {
memcpy(intf->session->hostname, hostname,
__min(strlen(hostname), 64));
}
}
void
ipmi_intf_session_set_username(struct ipmi_intf * intf, char * username)
{
if (intf->session == NULL)
return;
memset(intf->session->username, 0, 17);
if (username == NULL)
return;
memcpy(intf->session->username, username, __min(strlen(username), 16));
}
void
ipmi_intf_session_set_password(struct ipmi_intf * intf, char * password)
{
if (intf->session == NULL)
return;
memset(intf->session->authcode, 0, IPMI_AUTHCODE_BUFFER_SIZE);
if (password == NULL) {
intf->session->password = 0;
return;
}
intf->session->password = 1;
memcpy(intf->session->authcode, password,
__min(strlen(password), IPMI_AUTHCODE_BUFFER_SIZE));
}
void
ipmi_intf_session_set_privlvl(struct ipmi_intf * intf, uint8_t level)
{
if (intf->session == NULL)
return;
intf->session->privlvl = level;
}
void
ipmi_intf_session_set_lookupbit(struct ipmi_intf * intf, uint8_t lookupbit)
{
if (intf->session == NULL)
return;
intf->session->v2_data.lookupbit = lookupbit;
}
void
ipmi_intf_session_set_cipher_suite_id(struct ipmi_intf * intf, uint8_t cipher_suite_id)
{
if (intf->session == NULL)
return;
intf->session->cipher_suite_id = cipher_suite_id;
}
void
ipmi_intf_session_set_sol_escape_char(struct ipmi_intf * intf, char sol_escape_char)
{
if (intf->session == NULL)
return;
intf->session->sol_escape_char = sol_escape_char;
}
void
ipmi_intf_session_set_kgkey(struct ipmi_intf * intf, char * kgkey)
{
if (intf->session == NULL)
return;
memset(intf->session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE);
if (kgkey == NULL)
return;
memcpy(intf->session->v2_data.kg, kgkey,
__min(strlen(kgkey), IPMI_KG_BUFFER_SIZE));
}
void
ipmi_intf_session_set_port(struct ipmi_intf * intf, int port)
{
if (intf->session == NULL)
return;
intf->session->port = port;
}
void
ipmi_intf_session_set_authtype(struct ipmi_intf * intf, uint8_t authtype)
{
if (intf->session == NULL)
return;
/* clear password field if authtype NONE specified */
if (authtype == IPMI_SESSION_AUTHTYPE_NONE) {
memset(intf->session->authcode, 0, IPMI_AUTHCODE_BUFFER_SIZE);
intf->session->password = 0;
}
intf->session->authtype_set = authtype;
}
void
ipmi_intf_session_set_timeout(struct ipmi_intf * intf, uint32_t timeout)
{
if (intf->session == NULL)
return;
intf->session->timeout = timeout;
}
void
ipmi_intf_session_set_retry(struct ipmi_intf * intf, int retry)
{
if (intf->session == NULL)
return;
intf->session->retry = retry;
}
void
ipmi_cleanup(struct ipmi_intf * intf)
{
ipmi_sdr_list_empty(intf);
}
#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
int
ipmi_intf_socket_connect(struct ipmi_intf * intf)
{
struct ipmi_session *session;
struct sockaddr_storage addr;
struct addrinfo hints;
struct addrinfo *rp0 = NULL, *rp;
char service[NI_MAXSERV];
int rc;
if (!intf || intf->session == NULL) {
return -1;
}
session = intf->session;
if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) {
lprintf(LOG_ERR, "No hostname specified!");
return -1;
}
/* open port to BMC */
memset(&addr, 0, sizeof(addr));
sprintf(service, "%d", session->port);
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0; /* use AI_NUMERICSERV for no name resolution */
hints.ai_protocol = IPPROTO_UDP; /* */
if (getaddrinfo(session->hostname, service, &hints, &rp0) != 0) {
lprintf(LOG_ERR, "Address lookup for %s failed",
session->hostname);
return -1;
}
/* getaddrinfo() returns a list of address structures.
* Try each address until we successfully connect(2).
* If socket(2) (or connect(2)) fails, we (close the socket
* and) try the next address.
*/
session->ai_family = AF_UNSPEC;
for (rp = rp0; rp != NULL; rp = rp->ai_next) {
/* We are only interested in IPv4 and IPv6 */
if ((rp->ai_family != AF_INET6) && (rp->ai_family != AF_INET)) {
continue;
}
intf->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (intf->fd == -1) {
continue;
}
if (rp->ai_family == AF_INET) {
if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen);
session->addrlen = rp->ai_addrlen;
session->ai_family = rp->ai_family;
break; /* Success */
}
} else if (rp->ai_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)rp->ai_addr;
char hbuf[NI_MAXHOST];
socklen_t len;
/* The scope was specified on the command line e.g. with -H FE80::219:99FF:FEA0:BD95%eth0 */
if (addr6->sin6_scope_id != 0) {
len = sizeof(struct sockaddr_in6);
if (getnameinfo((struct sockaddr *)addr6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) {
lprintf(LOG_DEBUG, "Trying address: %s scope=%d",
hbuf,
addr6->sin6_scope_id);
}
if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen);
session->addrlen = rp->ai_addrlen;
session->ai_family = rp->ai_family;
break; /* Success */
}
} else {
/* No scope specified, try to get this from the list of interfaces */
struct ifaddrs *ifaddrs = NULL;
struct ifaddrs *ifa = NULL;
if (getifaddrs(&ifaddrs) < 0) {
lprintf(LOG_ERR, "Interface address lookup for %s failed",
session->hostname);
break;
}
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)ifa->ifa_addr;
/* Skip unwanted addresses */
if (IN6_IS_ADDR_MULTICAST(&tmp6->sin6_addr)) {
continue;
}
if (IN6_IS_ADDR_LOOPBACK(&tmp6->sin6_addr)) {
continue;
}
len = sizeof(struct sockaddr_in6);
if ( getnameinfo((struct sockaddr *)tmp6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) {
lprintf(LOG_DEBUG, "Testing %s interface address: %s scope=%d",
ifa->ifa_name != NULL ? ifa->ifa_name : "???",
hbuf,
tmp6->sin6_scope_id);
}
if (tmp6->sin6_scope_id != 0) {
addr6->sin6_scope_id = tmp6->sin6_scope_id;
} else {
/*
* No scope information in interface address information
* On some OS'es, getifaddrs() is returning out the 'kernel' representation
* of scoped addresses which stores the scope in the 3rd and 4th
* byte. See also this page:
* http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html
*/
if (IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr)
&& (tmp6->sin6_addr.s6_addr16[1] != 0)) {
addr6->sin6_scope_id = ntohs(tmp6->sin6_addr.s6_addr16[1]);
}
}
/* OK, now try to connect with the scope id from this interface address */
if (addr6->sin6_scope_id != 0) {
if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen);
session->addrlen = rp->ai_addrlen;
session->ai_family = rp->ai_family;
lprintf(LOG_DEBUG, "Successful connected on %s interface with scope id %d", ifa->ifa_name, tmp6->sin6_scope_id);
break; /* Success */
}
}
}
}
freeifaddrs(ifaddrs);
}
}
if (session->ai_family != AF_UNSPEC) {
break;
}
close(intf->fd);
intf->fd = -1;
}
/* No longer needed */
freeaddrinfo(rp0);
return ((intf->fd != -1) ? 0 : -1);
}
#endif

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_lan.la
noinst_LTLIBRARIES = @INTF_LAN_LIB@
libintf_lan_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_lan_la_SOURCES = lan.c lan.h asf.h rmcp.h auth.c auth.h md5.c md5.h

75
src/plugins/lan/asf.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_ASF_H
#define IPMI_ASF_H
#include <ipmitool/helper.h>
#include "lan.h"
#define ASF_RMCP_IANA 0x000011be
#define ASF_TYPE_PING 0x80
#define ASF_TYPE_PONG 0x40
static const struct valstr asf_type_vals[] __attribute__((unused)) = {
{ 0x10, "Reset" },
{ 0x11, "Power-up" },
{ 0x12, "Unconditional Power-down" },
{ 0x13, "Power Cycle" },
{ 0x40, "Presence Pong" },
{ 0x41, "Capabilities Response" },
{ 0x42, "System State Response" },
{ 0x80, "Presence Ping" },
{ 0x81, "Capabilities Request" },
{ 0x82, "System State Request" },
{ 0x00, NULL }
};
/* ASF message header */
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
struct asf_hdr {
uint32_t iana;
uint8_t type;
uint8_t tag;
uint8_t __reserved;
uint8_t len;
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
#endif
int handle_asf(struct ipmi_intf * intf, uint8_t * data, int data_len);
#endif /* IPMI_ASF_H */

220
src/plugins/lan/auth.c Normal file
View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <ipmitool/helper.h>
#include <ipmitool/bswap.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_CRYPTO_MD2
# include <openssl/md2.h>
#endif
#ifdef HAVE_CRYPTO_MD5
# include <openssl/md5.h>
#else
# include "md5.h"
#endif
/*
* multi-session authcode generation for MD5
* H(password + session_id + msg + session_seq + password)
*
* Use OpenSSL implementation of MD5 algorithm if found
*/
uint8_t * ipmi_auth_md5(struct ipmi_session * s, uint8_t * data, int data_len)
{
#ifdef HAVE_CRYPTO_MD5
MD5_CTX ctx;
static uint8_t md[16];
uint32_t temp;
#if WORDS_BIGENDIAN
temp = BSWAP_32(s->in_seq);
#else
temp = s->in_seq;
#endif
memset(md, 0, 16);
memset(&ctx, 0, sizeof(MD5_CTX));
MD5_Init(&ctx);
MD5_Update(&ctx, (const uint8_t *)s->authcode, 16);
MD5_Update(&ctx, (const uint8_t *)&s->session_id, 4);
MD5_Update(&ctx, (const uint8_t *)data, data_len);
MD5_Update(&ctx, (const uint8_t *)&temp, sizeof(uint32_t));
MD5_Update(&ctx, (const uint8_t *)s->authcode, 16);
MD5_Final(md, &ctx);
if (verbose > 3)
printf(" MD5 AuthCode : %s\n", buf2str(md, 16));
return md;
#else /*HAVE_CRYPTO_MD5*/
md5_state_t state;
static md5_byte_t digest[16];
uint32_t temp;
memset(digest, 0, 16);
memset(&state, 0, sizeof(md5_state_t));
md5_init(&state);
md5_append(&state, (const md5_byte_t *)s->authcode, 16);
md5_append(&state, (const md5_byte_t *)&s->session_id, 4);
md5_append(&state, (const md5_byte_t *)data, data_len);
#if WORDS_BIGENDIAN
temp = BSWAP_32(s->in_seq);
#else
temp = s->in_seq;
#endif
md5_append(&state, (const md5_byte_t *)&temp, 4);
md5_append(&state, (const md5_byte_t *)s->authcode, 16);
md5_finish(&state, digest);
if (verbose > 3)
printf(" MD5 AuthCode : %s\n", buf2str(digest, 16));
return digest;
#endif /*HAVE_CRYPTO_MD5*/
}
/*
* multi-session authcode generation for MD2
* H(password + session_id + msg + session_seq + password)
*
* Use OpenSSL implementation of MD2 algorithm if found.
* This function is analogous to ipmi_auth_md5
*/
uint8_t * ipmi_auth_md2(struct ipmi_session * s, uint8_t * data, int data_len)
{
#ifdef HAVE_CRYPTO_MD2
MD2_CTX ctx;
static uint8_t md[16];
uint32_t temp;
#if WORDS_BIGENDIAN
temp = BSWAP_32(s->in_seq);
#else
temp = s->in_seq;
#endif
memset(md, 0, 16);
memset(&ctx, 0, sizeof(MD2_CTX));
MD2_Init(&ctx);
MD2_Update(&ctx, (const uint8_t *)s->authcode, 16);
MD2_Update(&ctx, (const uint8_t *)&s->session_id, 4);
MD2_Update(&ctx, (const uint8_t *)data, data_len);
MD2_Update(&ctx, (const uint8_t *)&temp, sizeof(uint32_t));
MD2_Update(&ctx, (const uint8_t *)s->authcode, 16);
MD2_Final(md, &ctx);
if (verbose > 3)
printf(" MD2 AuthCode : %s\n", buf2str(md, 16));
return md;
#else /*HAVE_CRYPTO_MD2*/
static uint8_t md[16];
memset(md, 0, 16);
printf("WARNING: No internal support for MD2! "
"Please re-compile with OpenSSL.\n");
return md;
#endif /*HAVE_CRYPTO_MD2*/
}
/* special authentication method */
uint8_t * ipmi_auth_special(struct ipmi_session * s)
{
#ifdef HAVE_CRYPTO_MD5
MD5_CTX ctx;
static uint8_t md[16];
uint8_t challenge[16];
int i;
memset(challenge, 0, 16);
memset(md, 0, 16);
memset(&ctx, 0, sizeof(MD5_CTX));
MD5_Init(&ctx);
MD5_Update(&ctx, (const uint8_t *)s->authcode, strlen((const char *)s->authcode));
MD5_Final(md, &ctx);
for (i=0; i<16; i++)
challenge[i] = s->challenge[i] ^ md[i];
memset(md, 0, 16);
memset(&ctx, 0, sizeof(MD5_CTX));
MD5_Init(&ctx);
MD5_Update(&ctx, (const uint8_t *)challenge, 16);
MD5_Final(md, &ctx);
return md;
#else /*HAVE_CRYPTO_MD5*/
int i;
md5_state_t state;
static md5_byte_t digest[16];
uint8_t challenge[16];
memset(challenge, 0, 16);
memset(digest, 0, 16);
memset(&state, 0, sizeof(md5_state_t));
md5_init(&state);
md5_append(&state, (const md5_byte_t *)s->authcode, strlen(s->authcode));
md5_finish(&state, digest);
for (i=0; i<16; i++)
challenge[i] = s->challenge[i] ^ digest[i];
memset(digest, 0, 16);
memset(&state, 0, sizeof(md5_state_t));
md5_init(&state);
md5_append(&state, (const md5_byte_t *)challenge, 16);
md5_finish(&state, digest);
return digest;
#endif /*HAVE_CRYPTO_MD5*/
}

40
src/plugins/lan/auth.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_AUTH_H
#define IPMI_AUTH_H
uint8_t * ipmi_auth_md2(struct ipmi_session * s, uint8_t * data, int data_len);
uint8_t * ipmi_auth_md5(struct ipmi_session * s, uint8_t * data, int data_len);
uint8_t * ipmi_auth_special(struct ipmi_session * s);
#endif /*IPMI_AUTH_H*/

2071
src/plugins/lan/lan.c Normal file

File diff suppressed because it is too large Load Diff

41
src/plugins/lan/lan.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_LAN_H
#define IPMI_LAN_H
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
extern struct ipmi_intf ipmi_lan_intf;
#endif /*IPMI_LAN_H*/

381
src/plugins/lan/md5.c Normal file
View File

@@ -0,0 +1,381 @@
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.c,v 1.1 2003/11/18 17:56:02 iceblink Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#include "md5.h"
#include <string.h>
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned */
X = (const md5_word_t *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
{
const md5_byte_t *p = data;
int left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}

91
src/plugins/lan/md5.h Normal file
View File

@@ -0,0 +1,91 @@
/*
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.h,v 1.1 2003/11/18 17:56:02 iceblink Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
# define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
void md5_init(md5_state_t *pms);
/* Append a string to the message. */
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */

99
src/plugins/lan/rmcp.h Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_RMCP_H
#define IPMI_RMCP_H
#include <ipmitool/helper.h>
#include "lan.h"
#include "asf.h"
#define RMCP_VERSION_1 0x06
#define RMCP_UDP_PORT 0x26f /* port 623 */
#define RMCP_UDP_SECURE_PORT 0x298 /* port 664 */
#define RMCP_TYPE_MASK 0x80
#define RMCP_TYPE_NORM 0x00
#define RMCP_TYPE_ACK 0x01
static const struct valstr rmcp_type_vals[] __attribute__((unused)) = {
{ RMCP_TYPE_NORM, "Normal RMCP" },
{ RMCP_TYPE_ACK, "RMCP ACK" },
{ 0, NULL }
};
#define RMCP_CLASS_MASK 0x1f
#define RMCP_CLASS_ASF 0x06
#define RMCP_CLASS_IPMI 0x07
#define RMCP_CLASS_OEM 0x08
static const struct valstr rmcp_class_vals[] __attribute__((unused)) = {
{ RMCP_CLASS_ASF, "ASF" },
{ RMCP_CLASS_IPMI, "IPMI" },
{ RMCP_CLASS_OEM, "OEM" },
{ 0, NULL }
};
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
/* RMCP message header */
struct rmcp_hdr {
uint8_t ver;
uint8_t __reserved;
uint8_t seq;
uint8_t class;
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
#endif
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
struct rmcp_pong {
struct rmcp_hdr rmcp;
struct asf_hdr asf;
uint32_t iana;
uint32_t oem;
uint8_t sup_entities;
uint8_t sup_interact;
uint8_t reserved[6];
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
#endif
int handle_rmcp(struct ipmi_intf * intf, uint8_t * data, int data_len);
#endif /* IPMI_RMCP_H */

View File

@@ -0,0 +1,45 @@
# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_lanplus.la
noinst_LTLIBRARIES = @INTF_LANPLUS_LIB@
libintf_lanplus_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_lanplus_la_SOURCES = \
rmcp.h asf.h \
lanplus.c lanplus.h \
lanplus_strings.c \
lanplus_crypt.c lanplus_crypt.h \
lanplus_dump.h lanplus_dump.c \
lanplus_crypt_impl.h lanplus_crypt_impl.c

View File

@@ -0,0 +1,74 @@
This interface exists to provide a means of connecting to an IPMIv2 enabled
BMC. In some places, the IPMIv2 specification is either unclear or
inconsistent, and interpretations of the intent of the specification had to
be made at the discretion of the implementor. The purpose of this
document is to make those decisions clear so that 1) they can be reviewed
by others and 2) so that the rationale for those decisions can be made
clear.
* Though it's not stated explicitly with which algorithm the K1 and K2 keys
should be generated, we chose to use the authentication algorithm. The
specification states that K1 and K2 are generated with an HMAC algorithm,
and all of the authentication algorithms (except for "none") are HMAC
algorithms, whereas the integrity algorithms are not all HMAC. See section
13.32 for details about K1 and K2, and section
* The IPMIv2 specification describes a key, Kg, that is the "BMC key".
This key functions as a global key that is required to be known in addition
to the user's key, by authenticating users. If the BMC has a null Kg, the
users key, Kuid, is used in its place in algorithms where Kg is required,
per the specification section 13.33. A user can obtain the status of Kg by
querying the BMC with the Get Channel Authentication Capabilities command.
Currently, this implementation does not provide a way for a user to specify
Kg for BMCs that require it.
* The specification is unclear as to which key is used for HMAC based
integrity checking. One the one hand, section 13.28.4 states explicitly
that HMAC integrity algorithms use the session integrity key as the HMAC
key. Confusing that matter is a statement in section 13.32 regarding the
creation of additional keying material. In this section it is stated that
"all keying material for the RSP integrity and confidentiality algorithms
will be generated by processing a pre-defined set of constants using HMAC
per [RFC2104], keyed by sik". And "For the mandatory-to-implement
integrity and confidentiality algorithms defined in this specification,
processing the first two (2) constants will generate the require amount of
keying material." We decided to use K1 as our HMAC key for the generation
of authentication codes (integrity checking). Furthermore, we are using
all 20 bytes of K1.
* IPMIv2 compliant BMCs are supposed to support 20 byte passwords, as well
store metadata describing whether the password was stored as a 16 byte or
20 byte class password. We do not currently support 20 byte passwords. It
should be noted that there are obvious mistakes in the SET USER PASSWORD
command specification, as it mentions the ability to query for 16/20 byte
password status, but the packet format does not support this.
* The IPMIv2 specification describes a type of login called a "role only
login." This feature allows a user to login providing only a requested
privilege level and a password. We do not currently support this feature.
Supporting this feature would only require the ability to specify
username/privilege lookups in the RAKP 1 message sent from ipmitool. We
currently specify the use of username only lookups for authentication.
* In the IPMIv2 packet description in table 13-8 of the IPMv2
specification, there are two fields that are rather ambiguous in meaning.
The fields are "Pad Length" and "Next Header". Although neither field is
listed as belonging to the IPMIv2 packet format, we include/expect them
both in our IPMIv2 packets. Are rationale is 1) the Next Headers field's
comment states what the value of that field should be for IPMIv2, and 2)
for the most part the ASF and IPMIv2 fields seem to parallel each other,
and we feel that the Pad Length and Next Header fields were left out of the
IPMIv2 column by mistake.
* The GET CHANNEL CIPHER SUITES command documentation seems to have
mistakes. The "start of record" byte is stated to be either 0x30 or 0x31,
whereas the detailed description in table 22-18 leads us to believe that
this byte should really be 0xC0 or 0xC1. Also the description of bits 5:0
in the start of record byte should probably be 00_0000 rather than 00_000.

View File

@@ -0,0 +1,76 @@
This document was last updated for release 1.8.8.
This document explains how Serial Over Lan is implemented on in the
ipmitool IPMI client. Obviously, the code itself is authoritative, but
this document should serve as a good starting point.
Serial Over Lan (SOL) is defined in the IPMI v2 specification published by
Intel and available at http://www.intel.com/design/servers/ipmi/. SOL
functionality is built on top of the RMCP+ protocol as an additional
payload type (type 1).
The high end SOL logic is implemented in src/ipmitool/lib/ipmi_sol.c. SOL
sessions are begun in ipmitool using the "sol activate" command. This
command maps directly to the IPMI Activate Payload command. It first
verifies that an RMCP+ session (lanplus interface) is being used to
establish the session. Although the spec allows for a SOL connection to be
established on a port different than the RMCP+ port that the "activate
payload" command issued, ipmitool does not support this.
Once a session has been established (the activate payload command
succeeds), ipmitool simply loops over a select() on user input and data
returned from the BMC. All user input is first filtered so that special
escape sequences can suspend or deactivate the SOL session and so that data
can be broken into chunks no greater than N bytes. This maximum is
specified by the BMC in the response to the Activate Payload command.
User input to the BMC is handled in ipmitool/src/plugins/lanplus/lanplus.c.
Every SOL packet (with one exception) traveling in either direction causes
the recipient to return an acknowledgement packet, though acks themself are
not acknowledged. The transport layer in lanplus.c handles the logic
regarding acks, partial acks, sequence numbers. SOL acknowledgements
packets be acks, partial acks (the remote destination processed only some
of the data), and nacks (requests to stop sending packets). Nacks are not
honored by ipmitool.
Note that one way that SOL communication differs from standard IPMI
commands, is that it is not simply a request response protocol. Packets
may be returned asyncrhonously from the BMC. When establishing a SOL
session, ipmitool registers a callback for asynchonously received data.
This call back simply prints text returned from the BMC.
Once a user has chosen to exit the SOL session (with ~.) ipmitool sends the
IPMI SOL Deactivate command to the BMC.
The standard code path for SOL logic follows:
ipmi_sol_main (ipmi_sol.c):
ipmi_sol_activate (ipmi_sol.c):
Argument validation
Creation and dispatch of IPMI Activate Payload command
ipmi_sol_red_pill (ipmi_sol.c):
Loop on select() for user input and data returned from the BMC
Periodic dispatch of "keep alive" packet to the BMC.
Send user input to the BMC and BMC data to the console.
processSolUserInput (ipmi_sol.c):
Process possible escape sequences (~., ~B, etc.)
Send (with retries) user data to the BMC
Partial creation of packet payload
ipmi_lanplus_send_sol (lanplus.c):
Completion of packet payload
Send (with retries) of SOL packet
ipmi_lanplus_send_payload (lanplus.c):
Creation of RMCP+ packet
Details general to all V2 packet processing, as
well as a some logic to handle ack reception.
is_sol_partial_ack (lanplus.c):
Determine whether a data needs to be resent
ipmi_lanplus_recv_sol (lanplus.c):
Handle data received by the BMC. Ack as appropriate.

75
src/plugins/lanplus/asf.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_ASF_H
#define IPMI_ASF_H
#include <ipmitool/helper.h>
#include "lanplus.h"
#define ASF_RMCP_IANA 0x000011be
#define ASF_TYPE_PING 0x80
#define ASF_TYPE_PONG 0x40
static const struct valstr asf_type_vals[] __attribute__((unused)) = {
{ 0x10, "Reset" },
{ 0x11, "Power-up" },
{ 0x12, "Unconditional Power-down" },
{ 0x13, "Power Cycle" },
{ 0x40, "Presence Pong" },
{ 0x41, "Capabilities Response" },
{ 0x42, "System State Response" },
{ 0x80, "Presence Ping" },
{ 0x81, "Capabilities Request" },
{ 0x82, "System State Request" },
{ 0x00, NULL }
};
/* ASF message header */
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
struct asf_hdr {
uint32_t iana;
uint8_t type;
uint8_t tag;
uint8_t __reserved;
uint8_t len;
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
#endif
int handle_asf(struct ipmi_intf * intf, uint8_t * data, int data_len);
#endif /* IPMI_ASF_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_LANPLUS_H
#define IPMI_LANPLUS_H
#include <ipmitool/ipmi.h>
#define IPMI_LANPLUS_PORT 0x26f
/*
* RAKP return codes. These values come from table 13-15 of the IPMI v2
* specification.
*/
#define IPMI_RAKP_STATUS_NO_ERRORS 0x00
#define IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_SESSION 0x01
#define IPMI_RAKP_STATUS_INVALID_SESSION_ID 0x02
#define IPMI_RAKP_STATUS_INVALID_PAYLOAD_TYPE 0x03
#define IPMI_RAKP_STATUS_INVALID_AUTHENTICATION_ALGORITHM 0x04
#define IPMI_RAKP_STATUS_INVALID_INTEGRITTY_ALGORITHM 0x05
#define IPMI_RAKP_STATUS_NO_MATCHING_AUTHENTICATION_PAYLOAD 0x06
#define IPMI_RAKP_STATUS_NO_MATCHING_INTEGRITY_PAYLOAD 0x07
#define IPMI_RAKP_STATUS_INACTIVE_SESSION_ID 0x08
#define IPMI_RAKP_STATUS_INVALID_ROLE 0x09
#define IPMI_RAKP_STATUS_UNAUTHORIZED_ROLE_REQUESTED 0x0A
#define IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_ROLE 0x0B
#define IPMI_RAKP_STATUS_INVALID_NAME_LENGTH 0x0C
#define IPMI_RAKP_STATUS_UNAUTHORIZED_NAME 0x0D
#define IPMI_RAKP_STATUS_UNAUTHORIZED_GUID 0x0E
#define IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE 0x0F
#define IPMI_RAKP_STATUS_INVALID_CONFIDENTIALITY_ALGORITHM 0x10
#define IPMI_RAKP_STATUS_NO_CIPHER_SUITE_MATCH 0x11
#define IPMI_RAKP_STATUS_ILLEGAL_PARAMTER 0x12
#define IPMI_LAN_CHANNEL_1 0x07
#define IPMI_LAN_CHANNEL_2 0x06
#define IPMI_LAN_CHANNEL_E 0x0e
#define IPMI_LAN_TIMEOUT 1
#define IPMI_LAN_RETRY 4
#define IPMI_PRIV_CALLBACK 1
#define IPMI_PRIV_USER 2
#define IPMI_PRIV_OPERATOR 3
#define IPMI_PRIV_ADMIN 4
#define IPMI_PRIV_OEM 5
#define IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE 0x10
/* Session message offsets, from table 13-8 of the v2 specification */
#define IPMI_LANPLUS_OFFSET_AUTHTYPE 0x04
#define IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE 0x05
#define IPMI_LANPLUS_OFFSET_SESSION_ID 0x06
#define IPMI_LANPLUS_OFFSET_SEQUENCE_NUM 0x0A
#define IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE 0x0E
#define IPMI_LANPLUS_OFFSET_PAYLOAD 0x10
#define IPMI_GET_CHANNEL_AUTH_CAP 0x38
/*
* TODO: these are wild guesses and should be checked
*/
#define IPMI_MAX_CONF_HEADER_SIZE 0x20
#define IPMI_MAX_PAYLOAD_SIZE 0xFFFF /* Includes confidentiality header/trailer */
#define IPMI_MAX_CONF_TRAILER_SIZE 0x20
#define IPMI_MAX_INTEGRITY_PAD_SIZE 0x20
#define IPMI_MAX_AUTH_CODE_SIZE 0x20
#define IPMI_REQUEST_MESSAGE_SIZE 0x07
#define IPMI_MAX_MAC_SIZE 0x14 /* The largest mac we ever expect to generate */
#define IPMI_SHA1_AUTHCODE_SIZE 0x0C
/*
*This is accurate, as long as we're only passing 1 auth algorithm,
* one integrity algorithm, and 1 encyrption alogrithm
*/
#define IPMI_OPEN_SESSION_REQUEST_SIZE 32
#define IPMI_RAKP1_MESSAGE_SIZE 44
#define IPMI_RAKP3_MESSAGE_MAX_SIZE 28
#define IPMI_MAX_USER_NAME_LENGTH 16
extern const struct valstr ipmi_privlvl_vals[];
extern const struct valstr ipmi_authtype_vals[];
extern struct ipmi_intf ipmi_lanplus_intf;
struct ipmi_rs * ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req);
int ipmi_lanplus_open(struct ipmi_intf * intf);
void ipmi_lanplus_close(struct ipmi_intf * intf);
int ipmiv2_lan_ping(struct ipmi_intf * intf);
#endif /*IPMI_LAN_H*/

View File

@@ -0,0 +1,934 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <assert.h>
#include <string.h>
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#include <ipmitool/bswap.h>
#include <ipmitool/log.h>
#include "lanplus.h"
#include "lanplus_crypt.h"
#include "lanplus_crypt_impl.h"
/*
* lanplus_rakp2_hmac_matches
*
* param session holds all the state data that we need to generate the hmac
* param hmac is the HMAC sent by the BMC in the RAKP 2 message
*
* The HMAC was generated [per RFC2404] from :
*
* SIDm - Remote console session ID
* SIDc - BMC session ID
* Rm - Remote console random number
* Rc - BMC random number
* GUIDc - BMC guid
* ROLEm - Requested privilege level (entire byte)
* ULENGTHm - Username length
* <UNAMEm> - Username (absent for null user names)
*
* generated by using Kuid. I am aware that the subscripts on the values
* look backwards, but that's the way they are written in the specification.
*
* If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
*
* return 0 on success (the authcode matches)
* 1 on failure (the authcode does not match)
*/
int
lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
const uint8_t * bmc_mac, struct ipmi_intf * intf)
{
uint8_t * buffer;
int bufferLength, i;
uint8_t mac[20];
uint32_t macLength;
uint32_t SIDm_lsbf, SIDc_lsbf;
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
return 1;
/* We don't yet support other algorithms */
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
bufferLength =
4 + /* SIDm */
4 + /* SIDc */
16 + /* Rm */
16 + /* Rc */
16 + /* GUIDc */
1 + /* ROLEm */
1 + /* ULENGTHm */
strlen((const char *)session->username); /* optional */
buffer = malloc(bufferLength);
if (buffer == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return 1;
}
/*
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
* multibyte numbers in use.
*/
/* SIDm */
SIDm_lsbf = session->v2_data.console_id;
#if WORDS_BIGENDIAN
SIDm_lsbf = BSWAP_32(SIDm_lsbf);
#endif
memcpy(buffer, &SIDm_lsbf, 4);
/* SIDc */
SIDc_lsbf = session->v2_data.bmc_id;
#if WORDS_BIGENDIAN
SIDc_lsbf = BSWAP_32(SIDc_lsbf);
#endif
memcpy(buffer + 4, &SIDc_lsbf, 4);
/* Rm */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
buffer[8 + i] = session->v2_data.console_rand[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
buffer[8 + i] = session->v2_data.console_rand[i];
#endif
/* Rc */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
buffer[24 + i] = session->v2_data.bmc_rand[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
buffer[24 + i] = session->v2_data.bmc_rand[i];
#endif
/* GUIDc */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
buffer[40 + i] = session->v2_data.bmc_guid[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
buffer[40 + i] = session->v2_data.bmc_guid[i];
#endif
/* ROLEm */
buffer[56] = session->v2_data.requested_role;
if (ipmi_oem_active(intf, "i82571spt")) {
/*
* The HMAC calculation code in the Intel 82571 GbE
* skips this bit! Looks like a GbE bug, but we need
* to work around it here anyway...
*/
buffer[56] &= ~0x10;
}
/* ULENGTHm */
buffer[57] = strlen((const char *)session->username);
/* UserName [optional] */
for (i = 0; i < buffer[57]; ++i)
buffer[58 + i] = session->username[i];
if (verbose > 2)
{
printbuf((const uint8_t *)buffer, bufferLength, ">> rakp2 mac input buffer");
printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp2 mac key");
}
/*
* The buffer is complete. Let's hash.
*/
lanplus_HMAC(session->v2_data.auth_alg,
session->authcode,
IPMI_AUTHCODE_BUFFER_SIZE,
buffer,
bufferLength,
mac,
&macLength);
free(buffer);
buffer = NULL;
if (verbose > 2)
{
printbuf(mac, macLength, ">> rakp2 mac as computed by the remote console");
}
return (memcmp(bmc_mac, mac, macLength) == 0);
}
/*
* lanplus_rakp4_hmac_matches
*
* param session holds all the state data that we need to generate the hmac
* param hmac is the HMAC sent by the BMC in the RAKP 4 message
*
* The HMAC was generated [per RFC2404] from :
*
* Rm - Remote console random number
* SIDc - BMC session ID
* GUIDc - BMC guid
*
* generated by using SIK (the session integrity key). I am aware that the
* subscripts on the values look backwards, but that's the way they are
* written in the specification.
*
* If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success.
*
* return 1 on success (the authcode matches)
* 0 on failure (the authcode does not match)
*
*/
int
lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
const uint8_t * bmc_mac, struct ipmi_intf * intf)
{
uint8_t * buffer;
int bufferLength, i;
uint8_t mac[20];
uint32_t macLength;
uint32_t SIDc_lsbf;
if (ipmi_oem_active(intf, "intelplus")){
/* Intel BMC responds with the integrity Algorithm in RAKP4 */
if (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE)
return 1;
/* We don't yet support other algorithms */
assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96);
} else {
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
return 1;
/* We don't yet support other algorithms */
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
}
bufferLength =
16 + /* Rm */
4 + /* SIDc */
16; /* GUIDc */
buffer = (uint8_t *)malloc(bufferLength);
if (buffer == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return 1;
}
/*
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
* multibyte numbers in use.
*/
/* Rm */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
buffer[i] = session->v2_data.console_rand[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
buffer[i] = session->v2_data.console_rand[i];
#endif
/* SIDc */
SIDc_lsbf = session->v2_data.bmc_id;
#if WORDS_BIGENDIAN
SIDc_lsbf = BSWAP_32(SIDc_lsbf);
#endif
memcpy(buffer + 16, &SIDc_lsbf, 4);
/* GUIDc */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
buffer[i + 20] = session->v2_data.bmc_guid[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
buffer[i + 20] = session->v2_data.bmc_guid[i];
#endif
if (verbose > 2)
{
printbuf((const uint8_t *)buffer, bufferLength, ">> rakp4 mac input buffer");
printbuf(session->v2_data.sik, 20l, ">> rakp4 mac key (sik)");
}
/*
* The buffer is complete. Let's hash.
*/
lanplus_HMAC((ipmi_oem_active(intf, "intelplus"))
? session->v2_data.integrity_alg
: session->v2_data.auth_alg ,
session->v2_data.sik,
IPMI_SIK_BUFFER_SIZE,
buffer,
bufferLength,
mac,
&macLength);
if (verbose > 2)
{
printbuf(bmc_mac, macLength, ">> rakp4 mac as computed by the BMC");
printbuf(mac, macLength, ">> rakp4 mac as computed by the remote console");
}
free(buffer);
buffer = NULL;
assert(macLength == 20);
return (memcmp(bmc_mac, mac, 12) == 0);
}
/*
* lanplus_generate_rakp3_auth_code
*
* This auth code is an HMAC generated with :
*
* Rc - BMC random number
* SIDm - Console session ID
* ROLEm - Requested privilege level (entire byte)
* ULENGTHm - Username length
* <USERNAME> - Usename (absent for null usernames)
*
* The key used to generated the MAC is Kuid
*
* I am aware that the subscripts look backwards, but that is the way they are
* written in the spec.
*
* param output_buffer [out] will hold the generated MAC
* param session [in] holds all the state data we need to generate the auth code
* param mac_length [out] will be set to the length of the auth code
*
* returns 0 on success
* 1 on failure
*/
int
lanplus_generate_rakp3_authcode(uint8_t * output_buffer,
const struct ipmi_session * session,
uint32_t * mac_length, struct ipmi_intf * intf)
{
int ret = 0;
int input_buffer_length, i;
uint8_t * input_buffer;
uint32_t SIDm_lsbf;
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
{
*mac_length = 0;
return 0;
}
/* We don't yet support other algorithms */
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
input_buffer_length =
16 + /* Rc */
4 + /* SIDm */
1 + /* ROLEm */
1 + /* ULENGTHm */
strlen((const char *)session->username);
input_buffer = malloc(input_buffer_length);
if (input_buffer == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return 1;
}
/*
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
* multibyte numbers in use.
*/
/* Rc */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
input_buffer[i] = session->v2_data.bmc_rand[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
input_buffer[i] = session->v2_data.bmc_rand[i];
#endif
/* SIDm */
SIDm_lsbf = session->v2_data.console_id;
#if WORDS_BIGENDIAN
SIDm_lsbf = BSWAP_32(SIDm_lsbf);
#endif
memcpy(input_buffer + 16, &SIDm_lsbf, 4);
/* ROLEm */
if (ipmi_oem_active(intf, "intelplus") || ipmi_oem_active(intf, "i82571spt"))
input_buffer[20] = session->privlvl;
else
input_buffer[20] = session->v2_data.requested_role;
/* ULENGTHm */
input_buffer[21] = strlen((const char *)session->username);
/* USERNAME */
for (i = 0; i < input_buffer[21]; ++i)
input_buffer[22 + i] = session->username[i];
if (verbose > 2)
{
printbuf((const uint8_t *)input_buffer, input_buffer_length, ">> rakp3 mac input buffer");
printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp3 mac key");
}
lanplus_HMAC(session->v2_data.auth_alg,
session->authcode,
IPMI_AUTHCODE_BUFFER_SIZE,
input_buffer,
input_buffer_length,
output_buffer,
mac_length);
if (verbose > 2)
printbuf((const uint8_t *)output_buffer, *mac_length, "generated rakp3 mac");
free(input_buffer);
input_buffer = NULL;
return ret;
}
/*
* lanplus_generate_sik
*
* Generate the session integrity key (SIK) used for integrity checking
* during the IPMI v2 / RMCP+ session
*
* This session integrity key is a HMAC generated with :
*
* Rm - Console generated random number
* Rc - BMC generated random number
* ROLEm - Requested privilege level (entire byte)
* ULENGTHm - Username length
* <USERNAME> - Usename (absent for null usernames)
*
* The key used to generated the SIK is Kg if Kg is not null (two-key logins are
* enabled). Otherwise Kuid (the user authcode) is used as the key to genereate
* the SIK.
*
* I am aware that the subscripts look backwards, but that is the way they are
* written in the spec.
*
* param session [in/out] contains our input and output fields.
*
* returns 0 on success
* 1 on failure
*/
int
lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf)
{
uint8_t * input_buffer;
int input_buffer_length, i;
uint8_t * input_key;
uint32_t mac_length;
memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE);
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
return 0;
/* We don't yet support other algorithms */
assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1);
input_buffer_length =
16 + /* Rm */
16 + /* Rc */
1 + /* ROLEm */
1 + /* ULENGTHm */
strlen((const char *)session->username);
input_buffer = malloc(input_buffer_length);
if (input_buffer == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return 1;
}
/*
* Fill the buffer. I'm assuming that we're using the LSBF representation of the
* multibyte numbers in use.
*/
/* Rm */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
input_buffer[i] = session->v2_data.console_rand[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
input_buffer[i] = session->v2_data.console_rand[i];
#endif
/* Rc */
#if WORDS_BIGENDIAN
for (i = 0; i < 16; ++i)
input_buffer[16 + i] = session->v2_data.bmc_rand[16 - 1 - i];
#else
for (i = 0; i < 16; ++i)
input_buffer[16 + i] = session->v2_data.bmc_rand[i];
#endif
/* ROLEm */
input_buffer[32] = session->v2_data.requested_role;
if (ipmi_oem_active(intf, "i82571spt")) {
/*
* The HMAC calculation code in the Intel 82571 GbE
* skips this bit! Looks like a GbE bug, but we need
* to work around it here anyway...
*/
input_buffer[32] &= ~0x10;
}
/* ULENGTHm */
input_buffer[33] = strlen((const char *)session->username);
/* USERNAME */
for (i = 0; i < input_buffer[33]; ++i)
input_buffer[34 + i] = session->username[i];
if (session->v2_data.kg[0])
{
/* We will be hashing with Kg */
/*
* Section 13.31 of the IPMI v2 spec describes the SIK creation
* using Kg. It specifies that Kg should not be truncated.
* Kg is set in ipmi_intf.
*/
input_key = session->v2_data.kg;
}
else
{
/* We will be hashing with Kuid */
input_key = session->authcode;
}
if (verbose >= 2)
printbuf((const uint8_t *)input_buffer, input_buffer_length, "session integrity key input");
lanplus_HMAC(session->v2_data.auth_alg,
input_key,
IPMI_AUTHCODE_BUFFER_SIZE,
input_buffer,
input_buffer_length,
session->v2_data.sik,
&mac_length);
free(input_buffer);
input_buffer = NULL;
assert(mac_length == 20);
/*
* The key MAC generated is 20 bytes, but we will only be using the first
* 12 for SHA1 96
*/
if (verbose >= 2)
printbuf(session->v2_data.sik, 20, "Generated session integrity key");
return 0;
}
/*
* lanplus_generate_k1
*
* Generate K1, the key presumably used to generate integrity authcodes
*
* We use the authentication algorithm to generated the HMAC, using
* the session integrity key (SIK) as our key.
*
* param session [in/out].
*
* returns 0 on success
* 1 on failure
*/
int
lanplus_generate_k1(struct ipmi_session * session)
{
uint32_t mac_length;
uint8_t CONST_1[] =
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
memcpy(session->v2_data.k1, CONST_1, 20);
else
{
lanplus_HMAC(session->v2_data.auth_alg,
session->v2_data.sik,
IPMI_SIK_BUFFER_SIZE, /* SIK length */
CONST_1,
20,
session->v2_data.k1,
&mac_length);
assert(mac_length == 20);
}
if (verbose >= 2)
printbuf(session->v2_data.k1, 20, "Generated K1");
return 0;
}
/*
* lanplus_generate_k2
*
* Generate K2, the key used for RMCP+ AES encryption.
*
* We use the authentication algorithm to generated the HMAC, using
* the session integrity key (SIK) as our key.
*
* param session [in/out].
*
* returns 0 on success
* 1 on failure
*/
int
lanplus_generate_k2(struct ipmi_session * session)
{
uint32_t mac_length;
uint8_t CONST_2[] =
{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE)
memcpy(session->v2_data.k2, CONST_2, 20);
else
{
lanplus_HMAC(session->v2_data.auth_alg,
session->v2_data.sik,
IPMI_SIK_BUFFER_SIZE, /* SIK length */
CONST_2,
20,
session->v2_data.k2,
&mac_length);
assert(mac_length == 20);
}
if (verbose >= 2)
printbuf(session->v2_data.k2, 20, "Generated K2");
return 0;
}
/*
* lanplus_encrypt_payload
*
* Perform the appropriate encryption on the input data. Output the encrypted
* data to output, including the required confidentiality header and trailer.
* If the crypt_alg is IPMI_CRYPT_NONE, simply copy the input to the output and
* set bytes_written to input_length.
*
* param crypt_alg specifies the encryption algorithm (from table 13-19 of the
* IPMI v2 spec)
* param key is the used as input to the encryption algorithmf
* param input is the input data to be encrypted
* param input_length is the length of the input data to be encrypted
* param output is the cipher text generated by the encryption process
* param bytes_written is the number of bytes written during the encryption
* process
*
* returns 0 on success
* 1 on failure
*/
int
lanplus_encrypt_payload(uint8_t crypt_alg,
const uint8_t * key, const uint8_t * input,
uint32_t input_length, uint8_t * output,
uint16_t * bytes_written)
{
uint8_t * padded_input;
uint32_t mod, i, bytes_encrypted;
uint8_t pad_length = 0;
if (crypt_alg == IPMI_CRYPT_NONE)
{
/* Just copy the input to the output */
*bytes_written = input_length;
return 0;
}
/* Currently, we only support AES */
assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
assert(input_length <= IPMI_MAX_PAYLOAD_SIZE);
/*
* The input to the AES encryption algorithm has to be a multiple of the
* block size (16 bytes). The extra byte we are adding is the pad length
* byte.
*/
mod = (input_length + 1) % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE;
if (mod)
pad_length = IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE - mod;
padded_input = (uint8_t*)malloc(input_length + pad_length + 1);
if (padded_input == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return 1;
}
memcpy(padded_input, input, input_length);
/* add the pad */
for (i = 0; i < pad_length; ++i)
padded_input[input_length + i] = i + 1;
/* add the pad length */
padded_input[input_length + pad_length] = pad_length;
/* Generate an initialization vector, IV, for the encryption process */
if (lanplus_rand(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE))
{
lprintf(LOG_ERR, "lanplus_encrypt_payload: Error generating IV");
if (padded_input != NULL) {
free(padded_input);
padded_input = NULL;
}
return 1;
}
if (verbose > 2)
printbuf(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, ">> Initialization vector");
lanplus_encrypt_aes_cbc_128(output, /* IV */
key, /* K2 */
padded_input, /* Data to encrypt */
input_length + pad_length + 1, /* Input length */
output + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* output */
&bytes_encrypted); /* bytes written */
*bytes_written =
IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE + /* IV */
bytes_encrypted;
free(padded_input);
padded_input = NULL;
return 0;
}
/*
* lanplus_has_valid_auth_code
*
* Determine whether the packets authcode field is valid for packet.
*
* We always return success if any of the following are true.
* - this is not an IPMIv2 packet
* - the session is not yet active
* - the packet specifies that it is not authenticated
* - the integrity algorithm agreed upon during session creation is "none"
*
* The authcode is computed using the specified integrity algorithm starting
* with the AuthType / Format field, and ending with the field immediately
* preceeding the authcode itself.
*
* The key key used to generate the authcode MAC is K1.
*
* param rs holds the response structure.
* param session holds our session state, including our chosen algorithm, key, etc.
*
* returns 1 on success (authcode is valid)
* 0 on failure (autchode integrity check failed)
*/
int
lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session)
{
uint8_t * bmc_authcode;
uint8_t generated_authcode[IPMI_MAX_MAC_SIZE];
uint32_t generated_authcode_length;
if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) ||
(session->v2_data.session_state != LANPLUS_STATE_ACTIVE) ||
(! rs->session.bAuthenticated) ||
(session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE))
return 1;
/* We only support SHA1-96 now */
assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96);
/*
* For SHA1-96, the authcode will be the last 12 bytes in the packet
*/
bmc_authcode = rs->data + (rs->data_len - IPMI_SHA1_AUTHCODE_SIZE);
lanplus_HMAC(session->v2_data.integrity_alg,
session->v2_data.k1,
IPMI_AUTHCODE_BUFFER_SIZE,
rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE,
rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE,
generated_authcode,
&generated_authcode_length);
if (verbose > 3)
{
lprintf(LOG_DEBUG+2, "Validating authcode");
printbuf(session->v2_data.k1, 20, "K1");
printbuf(rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE,
rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE,
"Authcode Input Data");
printbuf(generated_authcode, 12, "Generated authcode");
printbuf(bmc_authcode, 12, "Expected authcode");
}
assert(generated_authcode_length == 20);
return (memcmp(bmc_authcode, generated_authcode, 12) == 0);
}
/*
* lanplus_decrypt_payload
*
*
* param input points to the beginning of the payload (which will be the IV if
* we are using AES)
* param payload_size [out] will be set to the size of the payload EXCLUDING
* padding
*
* returns 0 on success (we were able to successfully decrypt the packet)
* 1 on failure (we were unable to successfully decrypt the packet)
*/
int
lanplus_decrypt_payload(uint8_t crypt_alg, const uint8_t * key,
const uint8_t * input, uint32_t input_length,
uint8_t * output, uint16_t * payload_size)
{
uint8_t * decrypted_payload;
uint32_t bytes_decrypted;
if (crypt_alg == IPMI_CRYPT_NONE)
{
/* We are not encrypted. The paylaod size is is everything. */
*payload_size = input_length;
memmove(output, input, input_length);
return 0;
}
/* We only support AES */
assert(crypt_alg == IPMI_CRYPT_AES_CBC_128);
decrypted_payload = (uint8_t*)malloc(input_length);
if (decrypted_payload == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return 1;
}
lanplus_decrypt_aes_cbc_128(input, /* IV */
key, /* Key */
input +
IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* Data to decrypt */
input_length -
IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* Input length */
decrypted_payload, /* output */
&bytes_decrypted); /* bytes written */
if (bytes_decrypted != 0)
{
/* Success */
uint8_t conf_pad_length;
int i;
memmove(output,
decrypted_payload,
bytes_decrypted);
/*
* We have to determine the payload size, by substracting the padding, etc.
* The last byte of the decrypted payload is the confidentiality pad length.
*/
conf_pad_length = decrypted_payload[bytes_decrypted - 1];
*payload_size = bytes_decrypted - conf_pad_length - 1;
/*
* Extra test to make sure that the padding looks like it should (should start
* with 0x01, 0x02, 0x03, etc...
*/
for (i = 0; i < conf_pad_length; ++i)
{
if (decrypted_payload[*payload_size + i] != (i + 1))
{
lprintf(LOG_ERR, "Malformed payload padding");
assert(0);
}
}
}
else
{
lprintf(LOG_ERR, "ERROR: lanplus_decrypt_aes_cbc_128 decryptd 0 bytes");
assert(0);
}
free(decrypted_payload);
decrypted_payload = NULL;
return (bytes_decrypted == 0);
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_LANPLUS_CRYPT_H
#define IPMI_LANPLUS_CRYPT_H
#include <ipmitool/ipmi_intf.h>
/*
* See the implementation file for documentation
* ipmi_intf can be used for oem specific implementations
* e.g. if (ipmi_oem_active(intf, "OEM_XYZ"))
*/
int lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
const uint8_t * hmac,
struct ipmi_intf * intf);
int lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
const uint8_t * hmac,
struct ipmi_intf * intf);
int lanplus_generate_rakp3_authcode(uint8_t * buffer,
const struct ipmi_session * session,
uint32_t * auth_length,
struct ipmi_intf * intf);
int lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf);
int lanplus_generate_k1(struct ipmi_session * session);
int lanplus_generate_k2(struct ipmi_session * session);
int lanplus_encrypt_payload(uint8_t crypt_alg,
const uint8_t * key,
const uint8_t * input,
uint32_t input_length,
uint8_t * output,
uint16_t * bytesWritten);
int lanplus_decrypt_payload(uint8_t crypt_alg,
const uint8_t * key,
const uint8_t * input,
uint32_t input_length,
uint8_t * output,
uint16_t * payload_size);
int lanplus_has_valid_auth_code(struct ipmi_rs * rs,
struct ipmi_session * session);
#endif /* IPMI_LANPLUS_CRYPT_H */

View File

@@ -0,0 +1,293 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "ipmitool/log.h"
#include "ipmitool/ipmi_constants.h"
#include "lanplus.h"
#include "lanplus_crypt_impl.h"
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <assert.h>
/*
* lanplus_seed_prng
*
* Seed our PRNG with the specified number of bytes from /dev/random
*
* param bytes specifies the number of bytes to read from /dev/random
*
* returns 0 on success
* 1 on failure
*/
int lanplus_seed_prng(uint32_t bytes)
{
if (! RAND_load_file("/dev/urandom", bytes))
return 1;
else
return 0;
}
/*
* lanplus_rand
*
* Generate a random number of the specified size
*
* param num_bytes [in] is the size of the random number to be
* generated
* param buffer [out] is where we will place our random number
*
* return 0 on success
* 1 on failure
*/
int
lanplus_rand(uint8_t * buffer, uint32_t num_bytes)
{
#undef IPMI_LANPLUS_FAKE_RAND
#ifdef IPMI_LANPLUS_FAKE_RAND
/*
* This code exists so that we can easily find the generated random number
* in the hex dumps.
*/
int i;
for (i = 0; i < num_bytes; ++i)
buffer[i] = 0x70 | i;
return 0;
#else
return (! RAND_bytes(buffer, num_bytes));
#endif
}
/*
* lanplus_HMAC
*
* param mac specifies the algorithm to be used, currently only SHA1 is supported
* param key is the key used for HMAC generation
* param key_len is the lenght of key
* param d is the data to be MAC'd
* param n is the length of the data at d
* param md is the result of the HMAC algorithm
* param md_len is the length of md
*
* returns a pointer to md
*/
uint8_t *
lanplus_HMAC(uint8_t mac,
const void *key,
int key_len,
const uint8_t *d,
int n,
uint8_t *md,
uint32_t *md_len)
{
const EVP_MD *evp_md = NULL;
if ((mac == IPMI_AUTH_RAKP_HMAC_SHA1) ||
(mac == IPMI_INTEGRITY_HMAC_SHA1_96))
evp_md = EVP_sha1();
else
{
lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac);
assert(0);
}
return HMAC(evp_md, key, key_len, d, n, md, (unsigned int *)md_len);
}
/*
* lanplus_encrypt_aes_cbc_128
*
* Encrypt with the AES CBC 128 algorithm
*
* param iv is the 16 byte initialization vector
* param key is the 16 byte key used by the AES algorithm
* param input is the data to be encrypted
* param input_length is the number of bytes to be encrypted. This MUST
* be a multiple of the block size, 16.
* param output is the encrypted output
* param bytes_written is the number of bytes written. This param is set
* to 0 on failure, or if 0 bytes were input.
*/
void
lanplus_encrypt_aes_cbc_128(const uint8_t * iv,
const uint8_t * key,
const uint8_t * input,
uint32_t input_length,
uint8_t * output,
uint32_t * bytes_written)
{
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_set_padding(&ctx, 0);
*bytes_written = 0;
if (input_length == 0)
return;
if (verbose >= 5)
{
printbuf(iv, 16, "encrypting with this IV");
printbuf(key, 16, "encrypting with this key");
printbuf(input, input_length, "encrypting this data");
}
/*
* The default implementation adds a whole block of padding if the input
* data is perfectly aligned. We would like to keep that from happening.
* We have made a point to have our input perfectly padded.
*/
assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);
if(!EVP_EncryptUpdate(&ctx, output, (int *)bytes_written, input, input_length))
{
/* Error */
*bytes_written = 0;
return;
}
else
{
uint32_t tmplen;
if(!EVP_EncryptFinal_ex(&ctx, output + *bytes_written, (int *)&tmplen))
{
*bytes_written = 0;
return; /* Error */
}
else
{
/* Success */
*bytes_written += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
}
}
}
/*
* lanplus_decrypt_aes_cbc_128
*
* Decrypt with the AES CBC 128 algorithm
*
* param iv is the 16 byte initialization vector
* param key is the 16 byte key used by the AES algorithm
* param input is the data to be decrypted
* param input_length is the number of bytes to be decrypted. This MUST
* be a multiple of the block size, 16.
* param output is the decrypted output
* param bytes_written is the number of bytes written. This param is set
* to 0 on failure, or if 0 bytes were input.
*/
void
lanplus_decrypt_aes_cbc_128(const uint8_t * iv,
const uint8_t * key,
const uint8_t * input,
uint32_t input_length,
uint8_t * output,
uint32_t * bytes_written)
{
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_set_padding(&ctx, 0);
if (verbose >= 5)
{
printbuf(iv, 16, "decrypting with this IV");
printbuf(key, 16, "decrypting with this key");
printbuf(input, input_length, "decrypting this data");
}
*bytes_written = 0;
if (input_length == 0)
return;
/*
* The default implementation adds a whole block of padding if the input
* data is perfectly aligned. We would like to keep that from happening.
* We have made a point to have our input perfectly padded.
*/
assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);
if (!EVP_DecryptUpdate(&ctx, output, (int *)bytes_written, input, input_length))
{
/* Error */
lprintf(LOG_DEBUG, "ERROR: decrypt update failed");
*bytes_written = 0;
return;
}
else
{
uint32_t tmplen;
if (!EVP_DecryptFinal_ex(&ctx, output + *bytes_written, (int *)&tmplen))
{
char buffer[1000];
ERR_error_string(ERR_get_error(), buffer);
lprintf(LOG_DEBUG, "the ERR error %s", buffer);
lprintf(LOG_DEBUG, "ERROR: decrypt final failed");
*bytes_written = 0;
return; /* Error */
}
else
{
/* Success */
*bytes_written += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
}
}
if (verbose >= 5)
{
lprintf(LOG_DEBUG, "Decrypted %d encrypted bytes", input_length);
printbuf(output, *bytes_written, "Decrypted this data");
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_LANPLUS_CRYPT_IMPL_H
#define IPMI_LANPLUS_CRYPT_IMPL_H
int
lanplus_seed_prng(uint32_t bytes);
int
lanplus_rand(uint8_t * buffer, uint32_t num_bytes);
uint8_t *
lanplus_HMAC(uint8_t mac, const void *key, int key_len,
const uint8_t *d, int n, uint8_t *md,
uint32_t *md_len);
void
lanplus_encrypt_aes_cbc_128(const uint8_t * iv,
const uint8_t * key,
const uint8_t * input,
uint32_t input_length,
uint8_t * output,
uint32_t * bytes_written);
void
lanplus_decrypt_aes_cbc_128(const uint8_t * iv,
const uint8_t * key,
const uint8_t * input,
uint32_t input_length,
uint8_t * output,
uint32_t * bytes_written);
#endif /* IPMI_LANPLUS_CRYPT_IMPL_H */

View File

@@ -0,0 +1,192 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "lanplus.h"
#include "lanplus_dump.h"
extern const struct valstr ipmi_rakp_return_codes[];
extern const struct valstr ipmi_priv_levels[];
extern const struct valstr ipmi_auth_algorithms[];
extern const struct valstr ipmi_integrity_algorithms[];
extern const struct valstr ipmi_encryption_algorithms[];
#define DUMP_PREFIX_INCOMING "<<"
void lanplus_dump_open_session_response(const struct ipmi_rs * rsp)
{
if (verbose < 2)
return;
printf("%sOPEN SESSION RESPONSE\n", DUMP_PREFIX_INCOMING);
printf("%s Message tag : 0x%02x\n",
DUMP_PREFIX_INCOMING,
rsp->payload.open_session_response.message_tag);
printf("%s RMCP+ status : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.open_session_response.rakp_return_code,
ipmi_rakp_return_codes));
printf("%s Maximum privilege level : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.open_session_response.max_priv_level,
ipmi_priv_levels));
printf("%s Console Session ID : 0x%08lx\n",
DUMP_PREFIX_INCOMING,
(long)rsp->payload.open_session_response.console_id);
/* only tag, status, privlvl, and console id are returned if error */
if (rsp->payload.open_session_response.rakp_return_code !=
IPMI_RAKP_STATUS_NO_ERRORS)
return;
printf("%s BMC Session ID : 0x%08lx\n",
DUMP_PREFIX_INCOMING,
(long)rsp->payload.open_session_response.bmc_id);
printf("%s Negotiated authenticatin algorithm : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.open_session_response.auth_alg,
ipmi_auth_algorithms));
printf("%s Negotiated integrity algorithm : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.open_session_response.integrity_alg,
ipmi_integrity_algorithms));
printf("%s Negotiated encryption algorithm : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.open_session_response.crypt_alg,
ipmi_encryption_algorithms));
printf("\n");
}
void lanplus_dump_rakp2_message(const struct ipmi_rs * rsp, uint8_t auth_alg)
{
int i;
if (verbose < 2)
return;
printf("%sRAKP 2 MESSAGE\n", DUMP_PREFIX_INCOMING);
printf("%s Message tag : 0x%02x\n",
DUMP_PREFIX_INCOMING,
rsp->payload.rakp2_message.message_tag);
printf("%s RMCP+ status : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.rakp2_message.rakp_return_code,
ipmi_rakp_return_codes));
printf("%s Console Session ID : 0x%08lx\n",
DUMP_PREFIX_INCOMING,
(long)rsp->payload.rakp2_message.console_id);
printf("%s BMC random number : 0x", DUMP_PREFIX_INCOMING);
for (i = 0; i < 16; ++i)
printf("%02x", rsp->payload.rakp2_message.bmc_rand[i]);
printf("\n");
printf("%s BMC GUID : 0x", DUMP_PREFIX_INCOMING);
for (i = 0; i < 16; ++i)
printf("%02x", rsp->payload.rakp2_message.bmc_guid[i]);
printf("\n");
switch(auth_alg)
{
case IPMI_AUTH_RAKP_NONE:
printf("%s Key exchange auth code : none\n", DUMP_PREFIX_INCOMING);
break;
case IPMI_AUTH_RAKP_HMAC_SHA1:
printf("%s Key exchange auth code [sha1] : 0x", DUMP_PREFIX_INCOMING);
for (i = 0; i < 20; ++i)
printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]);
printf("\n");
break;
case IPMI_AUTH_RAKP_HMAC_MD5:
printf("%s Key exchange auth code [md5] : 0x", DUMP_PREFIX_INCOMING);
for (i = 0; i < 16; ++i)
printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]);
printf("\n");
break;
default:
printf("%s Key exchange auth code : invalid", DUMP_PREFIX_INCOMING);
}
printf("\n");
}
void lanplus_dump_rakp4_message(const struct ipmi_rs * rsp, uint8_t auth_alg)
{
int i;
if (verbose < 2)
return;
printf("%sRAKP 4 MESSAGE\n", DUMP_PREFIX_INCOMING);
printf("%s Message tag : 0x%02x\n",
DUMP_PREFIX_INCOMING,
rsp->payload.rakp4_message.message_tag);
printf("%s RMCP+ status : %s\n",
DUMP_PREFIX_INCOMING,
val2str(rsp->payload.rakp4_message.rakp_return_code,
ipmi_rakp_return_codes));
printf("%s Console Session ID : 0x%08lx\n",
DUMP_PREFIX_INCOMING,
(long)rsp->payload.rakp4_message.console_id);
switch(auth_alg)
{
case IPMI_AUTH_RAKP_NONE:
printf("%s Key exchange auth code : none\n", DUMP_PREFIX_INCOMING);
break;
case IPMI_AUTH_RAKP_HMAC_SHA1:
printf("%s Key exchange auth code [sha1] : 0x", DUMP_PREFIX_INCOMING);
for (i = 0; i < 12; ++i)
printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]);
printf("\n");
break;
case IPMI_AUTH_RAKP_HMAC_MD5:
printf("%s Key exchange auth code [md5] : 0x", DUMP_PREFIX_INCOMING);
for (i = 0; i < 12; ++i)
printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]);
printf("\n");
break;
default:
printf("%s Key exchange auth code : invalid", DUMP_PREFIX_INCOMING);
}
printf("\n");
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_LANPLUS_DUMP_H
#define IPMI_LANPLUS_DUMP_H
#include <ipmitool/ipmi_intf.h>
/* See the implementation file for documentation */
void lanplus_dump_open_session_response(const struct ipmi_rs * rsp);
void lanplus_dump_rakp2_message(const struct ipmi_rs * rsp, uint8_t auth_alg);
void lanplus_dump_rakp4_message(const struct ipmi_rs * rsp, uint8_t auth_alg);
#endif /* IPMI_LANPLUS_DUMP_H */

View File

@@ -0,0 +1,39 @@
#include "lanplus.h"
#include "ipmitool/ipmi_constants.h"
const struct valstr ipmi_rakp_return_codes[] = {
{ IPMI_RAKP_STATUS_NO_ERRORS, "no errors" },
{ IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_SESSION, "insufficient resources for session" },
{ IPMI_RAKP_STATUS_INVALID_SESSION_ID, "invalid session ID" },
{ IPMI_RAKP_STATUS_INVALID_PAYLOAD_TYPE, "invalid payload type" },
{ IPMI_RAKP_STATUS_INVALID_AUTHENTICATION_ALGORITHM, "invalid authentication algorithm" },
{ IPMI_RAKP_STATUS_INVALID_INTEGRITTY_ALGORITHM, "invalid integrity algorithm" },
{ IPMI_RAKP_STATUS_NO_MATCHING_AUTHENTICATION_PAYLOAD, "no matching authentication algorithm"},
{ IPMI_RAKP_STATUS_NO_MATCHING_INTEGRITY_PAYLOAD, "no matching integrity payload" },
{ IPMI_RAKP_STATUS_INACTIVE_SESSION_ID, "inactive session ID" },
{ IPMI_RAKP_STATUS_INVALID_ROLE, "invalid role" },
{ IPMI_RAKP_STATUS_UNAUTHORIZED_ROLE_REQUESTED, "unauthorized role requested" },
{ IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_ROLE, "insufficient resources for role" },
{ IPMI_RAKP_STATUS_INVALID_NAME_LENGTH, "invalid name length" },
{ IPMI_RAKP_STATUS_UNAUTHORIZED_NAME, "unauthorized name" },
{ IPMI_RAKP_STATUS_UNAUTHORIZED_GUID, "unauthorized GUID" },
{ IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE, "invalid integrity check value" },
{ IPMI_RAKP_STATUS_INVALID_CONFIDENTIALITY_ALGORITHM, "invalid confidentiality algorithm" },
{ IPMI_RAKP_STATUS_NO_CIPHER_SUITE_MATCH, "no matching cipher suite" },
{ IPMI_RAKP_STATUS_ILLEGAL_PARAMTER, "illegal parameter" },
{ 0, 0 },
};
const struct valstr ipmi_priv_levels[] = {
{ IPMI_PRIV_CALLBACK, "callback" },
{ IPMI_PRIV_USER, "user" },
{ IPMI_PRIV_OPERATOR, "operator" },
{ IPMI_PRIV_ADMIN, "admin" },
{ IPMI_PRIV_OEM, "oem" },
{ 0, 0 },
};

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_RMCP_H
#define IPMI_RMCP_H
#include <ipmitool/helper.h>
#include "lanplus.h"
#define RMCP_VERSION_1 0x06
#define RMCP_UDP_PORT 0x26f /* port 623 */
#define RMCP_UDP_SECURE_PORT 0x298 /* port 664 */
#define RMCP_TYPE_MASK 0x80
#define RMCP_TYPE_NORM 0x00
#define RMCP_TYPE_ACK 0x01
static const struct valstr rmcp_type_vals[] __attribute__((unused)) = {
{ RMCP_TYPE_NORM, "Normal RMCP" },
{ RMCP_TYPE_ACK, "RMCP ACK" },
{ 0, NULL }
};
#define RMCP_CLASS_MASK 0x1f
#define RMCP_CLASS_ASF 0x06
#define RMCP_CLASS_IPMI 0x07
#define RMCP_CLASS_OEM 0x08
static const struct valstr rmcp_class_vals[] __attribute__((unused)) = {
{ RMCP_CLASS_ASF, "ASF" },
{ RMCP_CLASS_IPMI, "IPMI" },
{ RMCP_CLASS_OEM, "OEM" },
{ 0, NULL }
};
/* RMCP message header */
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
struct rmcp_hdr {
uint8_t ver;
uint8_t __reserved;
uint8_t seq;
uint8_t class;
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
#endif
int handle_rmcp(struct ipmi_intf * intf, uint8_t * data, int data_len);
#endif /* IPMI_RMCP_H */

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_lipmi.la
noinst_LTLIBRARIES = @INTF_LIPMI_LIB@
libintf_lipmi_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_lipmi_la_SOURCES = lipmi.c

129
src/plugins/lipmi/lipmi.c Normal file
View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stropts.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <sys/lipmi/lipmi_intf.h>
#define IPMI_LIPMI_DEV "/dev/lipmi"
extern int verbose;
static int ipmi_lipmi_open(struct ipmi_intf * intf)
{
intf->fd = open(IPMI_LIPMI_DEV, O_RDWR);
if (intf->fd < 0) {
perror("Could not open lipmi device");
return -1;
}
intf->opened = 1;
intf->manufacturer_id = ipmi_get_oem(intf);
return intf->fd;
}
static void ipmi_lipmi_close(struct ipmi_intf * intf)
{
if (intf && intf->fd >= 0)
close(intf->fd);
intf->fd = -1;
intf->opened = 0;
intf->manufacturer_id = IPMI_OEM_UNKNOWN;
}
static struct ipmi_rs * ipmi_lipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
{
struct strioctl istr;
static struct lipmi_reqrsp reqrsp;
static struct ipmi_rs rsp;
static int curr_seq = 0;
if (!intf || !req)
return NULL;
if (!intf->opened && intf->open && intf->open(intf) < 0)
return NULL;
memset(&reqrsp, 0, sizeof(reqrsp));
reqrsp.req.fn = req->msg.netfn;
reqrsp.req.lun = 0;
reqrsp.req.cmd = req->msg.cmd;
reqrsp.req.datalength = req->msg.data_len;
memcpy(reqrsp.req.data, req->msg.data, req->msg.data_len);
reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE;
istr.ic_cmd = IOCTL_IPMI_KCS_ACTION;
istr.ic_timout = 0;
istr.ic_dp = (char *)&reqrsp;
istr.ic_len = sizeof(struct lipmi_reqrsp);
if (verbose > 1) {
printf("LIPMI req.fn : %x\n", reqrsp.req.fn);
printf("LIPMI req.lun : %x\n", reqrsp.req.lun);
printf("LIPMI req.cmd : %x\n", reqrsp.req.cmd);
printf("LIPMI req.datalength : %d\n", reqrsp.req.datalength);
}
if (ioctl(intf->fd, I_STR, &istr) < 0) {
perror("LIPMI IOCTL: I_STR");
return NULL;
}
memset(&rsp, 0, sizeof(struct ipmi_rs));
rsp.ccode = reqrsp.rsp.ccode;
rsp.data_len = reqrsp.rsp.datalength;
if (!rsp.ccode && rsp.data_len)
memcpy(rsp.data, reqrsp.rsp.data, rsp.data_len);
return &rsp;
}
struct ipmi_intf ipmi_lipmi_intf = {
name: "lipmi",
desc: "Solaris x86 LIPMI Interface",
open: ipmi_lipmi_open,
close: ipmi_lipmi_close,
sendrecv: ipmi_lipmi_send_cmd,
target_addr: IPMI_BMC_SLAVE_ADDR,
};

46
src/plugins/lipmi/lipmi.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_LIPMI_H
#define IPMI_LIPMI_H
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#define LIPMI_DEV "/dev/lipmi"
struct ipmi_rs * ipmi_lipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req);
int ipmi_lipmi_open(struct ipmi_intf * intf);
void ipmi_lipmi_close(struct ipmi_intf * intf);
int lipmi_intf_setup(struct ipmi_intf ** intf);
#endif

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_open.la
noinst_LTLIBRARIES = @INTF_OPEN_LIB@
libintf_open_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_open_la_SOURCES = open.c open.h

413
src/plugins/open/open.c Normal file
View File

@@ -0,0 +1,413 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/helper.h>
#include <ipmitool/log.h>
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#if defined(HAVE_SYS_IOCCOM_H)
# include <sys/ioccom.h>
#endif
#if defined(HAVE_OPENIPMI_H)
# if defined(HAVE_LINUX_COMPILER_H)
# include <linux/compiler.h>
# endif
# include <linux/ipmi.h>
#elif defined(HAVE_FREEBSD_IPMI_H)
/* FreeBSD OpenIPMI-compatible header */
# include <sys/ipmi.h>
#else
# include "open.h"
#endif
extern int verbose;
static int
ipmi_openipmi_open(struct ipmi_intf * intf)
{
int i = 0;
char ipmi_dev[16];
char ipmi_devfs[16];
char ipmi_devfs2[16];
int devnum = 0;
devnum = intf->devnum;
sprintf(ipmi_dev, "/dev/ipmi%d", devnum);
sprintf(ipmi_devfs, "/dev/ipmi/%d", devnum);
sprintf(ipmi_devfs2, "/dev/ipmidev/%d", devnum);
lprintf(LOG_DEBUG, "Using ipmi device %d", devnum);
intf->fd = open(ipmi_dev, O_RDWR);
if (intf->fd < 0) {
intf->fd = open(ipmi_devfs, O_RDWR);
if (intf->fd < 0) {
intf->fd = open(ipmi_devfs2, O_RDWR);
}
if (intf->fd < 0) {
lperror(LOG_ERR, "Could not open device at %s or %s or %s",
ipmi_dev, ipmi_devfs , ipmi_devfs2);
return -1;
}
}
if (ioctl(intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i) < 0) {
lperror(LOG_ERR, "Could not enable event receiver");
return -1;
}
intf->opened = 1;
/* This is never set to 0, the default is IPMI_BMC_SLAVE_ADDR */
if (intf->my_addr != 0) {
if (intf->set_my_addr(intf, intf->my_addr) < 0) {
lperror(LOG_ERR, "Could not set IPMB address");
return -1;
}
lprintf(LOG_DEBUG, "Set IPMB address to 0x%x",
intf->my_addr );
}
intf->manufacturer_id = ipmi_get_oem(intf);
return intf->fd;
}
static int
ipmi_openipmi_set_my_addr(struct ipmi_intf *intf, uint8_t addr)
{
unsigned int a = addr;
if (ioctl(intf->fd, IPMICTL_SET_MY_ADDRESS_CMD, &a) < 0) {
lperror(LOG_ERR, "Could not set IPMB address");
return -1;
}
intf->my_addr = addr;
return 0;
}
static void
ipmi_openipmi_close(struct ipmi_intf * intf)
{
if (intf->fd >= 0) {
close(intf->fd);
intf->fd = -1;
}
intf->opened = 0;
intf->manufacturer_id = IPMI_OEM_UNKNOWN;
}
static struct ipmi_rs *
ipmi_openipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
{
struct ipmi_recv recv;
struct ipmi_addr addr;
struct ipmi_system_interface_addr bmc_addr = {
addr_type: IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
channel: IPMI_BMC_CHANNEL,
};
struct ipmi_ipmb_addr ipmb_addr = {
addr_type: IPMI_IPMB_ADDR_TYPE,
};
struct ipmi_req _req;
static struct ipmi_rs rsp;
static int curr_seq = 0;
fd_set rset;
uint8_t * data = NULL;
int data_len = 0;
if (intf == NULL || req == NULL)
return NULL;
ipmb_addr.channel = intf->target_channel & 0x0f;
if (intf->opened == 0 && intf->open != NULL)
if (intf->open(intf) < 0)
return NULL;
if (verbose > 2)
printbuf(req->msg.data, req->msg.data_len,
"OpenIPMI Request Message");
/*
* setup and send message
*/
memset(&_req, 0, sizeof(struct ipmi_req));
if (intf->target_addr != 0 &&
intf->target_addr != intf->my_addr) {
/* use IPMB address if needed */
ipmb_addr.slave_addr = intf->target_addr;
ipmb_addr.lun = req->msg.lun;
lprintf(LOG_DEBUG, "Sending request 0x%x to "
"IPMB target @ 0x%x:0x%x (from 0x%x)",
req->msg.cmd,
intf->target_addr,intf->target_channel, intf->my_addr);
if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) {
uint8_t index = 0;
lprintf(LOG_DEBUG, "Encapsulating data sent to "
"end target [0x%02x,0x%02x] using transit [0x%02x,0x%02x] from 0x%x ",
(0x40 | intf->target_channel),
intf->target_addr,
intf->transit_channel,
intf->transit_addr,
intf->my_addr
);
/* Convert Message to 'Send Message' */
/* Supplied req : req , internal req : _req */
if (verbose > 4) {
fprintf(stderr, "Converting message:\n");
fprintf(stderr, " netfn = 0x%x\n", req->msg.netfn );
fprintf(stderr, " cmd = 0x%x\n", req->msg.cmd);
if (recv.msg.data && recv.msg.data_len) {
fprintf(stderr, " data_len = %d\n", req->msg.data_len);
fprintf(stderr, " data = %s\n",
buf2str(req->msg.data,req->msg.data_len));
}
}
/* Modify target address to use 'transit' instead */
ipmb_addr.slave_addr = intf->transit_addr;
ipmb_addr.channel = intf->transit_channel;
/* FIXME backup "My address" */
data_len = req->msg.data_len + 8;
data = malloc(data_len);
if (data == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return NULL;
}
memset(data, 0, data_len);
data[index++] = (0x40|intf->target_channel);
data[index++] = intf->target_addr;
data[index++] = ( req->msg.netfn << 2 ) | req->msg.lun ;
data[index++] = ipmi_csum(data+1, 2);
data[index++] = 0xFF; /* normally 0x20 , overwritten by IPMC */
data[index++] = ( (0) << 2) | 0 ; /* FIXME */
data[index++] = req->msg.cmd;
memcpy( (data+index) , req->msg.data, req->msg.data_len);
index += req->msg.data_len;
data[index++] = ipmi_csum( (data+4),(req->msg.data_len + 3) );
if (verbose > 4) {
fprintf(stderr, "Encapsulated message:\n");
fprintf(stderr, " netfn = 0x%x\n", IPMI_NETFN_APP );
fprintf(stderr, " cmd = 0x%x\n", 0x34 );
if (data && data_len) {
fprintf(stderr, " data_len = %d\n", data_len);
fprintf(stderr, " data = %s\n",
buf2str(data,data_len));
}
}
}
_req.addr = (unsigned char *) &ipmb_addr;
_req.addr_len = sizeof(ipmb_addr);
} else {
/* otherwise use system interface */
lprintf(LOG_DEBUG+2, "Sending request 0x%x to "
"System Interface", req->msg.cmd);
bmc_addr.lun = req->msg.lun;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
}
_req.msgid = curr_seq++;
/* In case of a bridge request */
if( data != NULL && data_len != 0 ) {
_req.msg.data = data;
_req.msg.data_len = data_len;
_req.msg.netfn = IPMI_NETFN_APP;
_req.msg.cmd = 0x34;
} else {
_req.msg.data = req->msg.data;
_req.msg.data_len = req->msg.data_len;
_req.msg.netfn = req->msg.netfn;
_req.msg.cmd = req->msg.cmd;
}
if (ioctl(intf->fd, IPMICTL_SEND_COMMAND, &_req) < 0) {
lperror(LOG_ERR, "Unable to send command");
if (data != NULL) {
free(data);
data = NULL;
}
return NULL;
}
/*
* wait for and retrieve response
*/
if (intf->noanswer) {
if (data != NULL) {
free(data);
data = NULL;
}
return NULL;
}
FD_ZERO(&rset);
FD_SET(intf->fd, &rset);
if (select(intf->fd+1, &rset, NULL, NULL, NULL) < 0) {
lperror(LOG_ERR, "I/O Error");
if (data != NULL) {
free(data);
data = NULL;
}
return NULL;
}
if (FD_ISSET(intf->fd, &rset) == 0) {
lprintf(LOG_ERR, "No data available");
if (data != NULL) {
free(data);
data = NULL;
}
return NULL;
}
recv.addr = (unsigned char *) &addr;
recv.addr_len = sizeof(addr);
recv.msg.data = rsp.data;
recv.msg.data_len = sizeof(rsp.data);
/* get data */
if (ioctl(intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) {
lperror(LOG_ERR, "Error receiving message");
if (errno != EMSGSIZE) {
if (data != NULL) {
free(data);
data = NULL;
}
return NULL;
}
}
if (verbose > 4) {
fprintf(stderr, "Got message:");
fprintf(stderr, " type = %d\n", recv.recv_type);
fprintf(stderr, " channel = 0x%x\n", addr.channel);
fprintf(stderr, " msgid = %ld\n", recv.msgid);
fprintf(stderr, " netfn = 0x%x\n", recv.msg.netfn);
fprintf(stderr, " cmd = 0x%x\n", recv.msg.cmd);
if (recv.msg.data && recv.msg.data_len) {
fprintf(stderr, " data_len = %d\n", recv.msg.data_len);
fprintf(stderr, " data = %s\n",
buf2str(recv.msg.data, recv.msg.data_len));
}
}
if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) {
uint8_t index = 0;
/* ipmb_addr.transit_slave_addr = intf->transit_addr; */
lprintf(LOG_DEBUG, "Decapsulating data received from transit "
"IPMB target @ 0x%x", intf->transit_addr);
/* comp code */
/* Check data */
if( recv.msg.data[0] == 0 ) {
recv.msg.netfn = recv.msg.data[2] >> 2;
recv.msg.cmd = recv.msg.data[6];
recv.msg.data = memmove(recv.msg.data ,recv.msg.data+7 , recv.msg.data_len - 7);
recv.msg.data_len -=8;
if (verbose > 4) {
fprintf(stderr, "Decapsulated message:\n");
fprintf(stderr, " netfn = 0x%x\n", recv.msg.netfn );
fprintf(stderr, " cmd = 0x%x\n", recv.msg.cmd);
if (recv.msg.data && recv.msg.data_len) {
fprintf(stderr, " data_len = %d\n", recv.msg.data_len);
fprintf(stderr, " data = %s\n",
buf2str(recv.msg.data,recv.msg.data_len));
}
}
}
}
/* save completion code */
rsp.ccode = recv.msg.data[0];
rsp.data_len = recv.msg.data_len - 1;
/* save response data for caller */
if (rsp.ccode == 0 && rsp.data_len > 0) {
memmove(rsp.data, rsp.data + 1, rsp.data_len);
rsp.data[recv.msg.data_len] = 0;
}
if (data != NULL) {
free(data);
data = NULL;
}
return &rsp;
}
struct ipmi_intf ipmi_open_intf = {
name: "open",
desc: "Linux OpenIPMI Interface",
open: ipmi_openipmi_open,
close: ipmi_openipmi_close,
sendrecv: ipmi_openipmi_send_cmd,
set_my_addr: ipmi_openipmi_set_my_addr,
my_addr: IPMI_BMC_SLAVE_ADDR,
target_addr: 0, /* init so -m local_addr does not cause bridging */
};

106
src/plugins/open/open.h Normal file
View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef IPMI_OPENIPMI_H
#define IPMI_OPENIPMI_H
#define IPMI_MAX_ADDR_SIZE 0x20
#define IPMI_BMC_CHANNEL 0xf
#define IPMI_NUM_CHANNELS 0x10
#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
#define IPMI_IPMB_ADDR_TYPE 0x01
#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41
#define IPMI_RESPONSE_RECV_TYPE 1
#define IPMI_ASYNC_EVENT_RECV_TYPE 2
#define IPMI_CMD_RECV_TYPE 3
struct ipmi_addr {
int addr_type;
short channel;
char data[IPMI_MAX_ADDR_SIZE];
};
struct ipmi_msg {
unsigned char netfn;
unsigned char cmd;
unsigned short data_len;
unsigned char *data;
};
struct ipmi_req {
unsigned char *addr;
unsigned int addr_len;
long msgid;
struct ipmi_msg msg;
};
struct ipmi_recv {
int recv_type;
unsigned char *addr;
unsigned int addr_len;
long msgid;
struct ipmi_msg msg;
};
struct ipmi_cmdspec {
unsigned char netfn;
unsigned char cmd;
};
struct ipmi_system_interface_addr {
int addr_type;
short channel;
unsigned char lun;
};
struct ipmi_ipmb_addr {
int addr_type;
short channel;
unsigned char slave_addr;
unsigned char lun;
};
#define IPMI_IOC_MAGIC 'i'
#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv)
#define IPMICTL_RECEIVE_MSG _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv)
#define IPMICTL_SEND_COMMAND _IOR(IPMI_IOC_MAGIC, 13, struct ipmi_req)
#define IPMICTL_REGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 14, struct ipmi_cmdspec)
#define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, struct ipmi_cmdspec)
#define IPMICTL_SET_GETS_EVENTS_CMD _IOR(IPMI_IOC_MAGIC, 16, int)
#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int)
#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int)
#define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int)
#define IPMICTL_GET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 20, unsigned int)
#endif /*IPMI_OPENIPMI_H*/

View File

@@ -0,0 +1,38 @@
# * Copyright (c) 2012 Pigeon Point Systems. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistribution of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistribution in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of Pigeon Point Systems, Inc. or the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind.
# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
# PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
# PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_serial.la
noinst_LTLIBRARIES = @INTF_SERIAL_LIB@
libintf_serial_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_serial_la_SOURCES = serial_terminal.c serial_basic.c

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,915 @@
/*
* Copyright (c) 2007-2012 Pigeon Point Systems. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Pigeon Point Systems nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/* Serial Interface, Terminal Mode plugin. */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <termios.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/helper.h>
#include <ipmitool/log.h>
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#define IPMI_SERIAL_TIMEOUT 5
#define IPMI_SERIAL_RETRY 5
#define IPMI_SERIAL_MAX_RESPONSE 256
/*
* Terminal Mode interface is required to support 40 byte transactions.
*/
#define IPMI_SERIAL_MAX_RQ_SIZE 37 /* 40 - 3 */
#define IPMI_SERIAL_MAX_RS_SIZE 36 /* 40 - 4 */
/*
* IPMB message header
*/
struct ipmb_msg_hdr {
unsigned char rsSA;
unsigned char netFn; /* NET FN | RS LUN */
unsigned char csum1;
unsigned char rqSA;
unsigned char rqSeq; /* RQ SEQ | RQ LUN */
unsigned char cmd;
unsigned char data[0];
};
/*
* Send Message command request for IPMB-format
*/
struct ipmi_send_message_rq {
unsigned char channel;
struct ipmb_msg_hdr msg;
};
/*
* Get Message command response for IPMB-format
*/
struct ipmi_get_message_rp {
unsigned char completion;
unsigned char channel;
unsigned char netFn;
unsigned char csum1;
unsigned char rsSA;
unsigned char rqSeq;
unsigned char cmd;
unsigned char data[0];
};
/*
* Terminal mode message header
*/
struct serial_term_hdr {
unsigned char netFn;
unsigned char seq;
unsigned char cmd;
};
/*
* Sending context
*/
struct serial_term_request_ctx {
uint8_t netFn;
uint8_t sa;
uint8_t seq;
uint8_t cmd;
};
/*
* Table of supported baud rates
*/
static const struct {
int baudinit;
int baudrate;
} rates[] = {
{ B2400, 2400 },
{ B9600, 9600 },
{ B19200, 19200 },
{ B38400, 38400 },
{ B57600, 57600 },
{ B115200, 115200 },
{ B230400, 230400 },
#ifdef B460800
{ B460800, 460800 },
#endif
};
static int is_system;
static int
ipmi_serial_term_open(struct ipmi_intf * intf)
{
struct termios ti;
unsigned int rate = 9600;
char *p;
int i;
if (!intf->devfile) {
lprintf(LOG_ERR, "Serial device is not specified");
return -1;
}
is_system = 0;
/* check if baud rate is specified */
if ((p = strchr(intf->devfile, ':'))) {
char * pp;
/* separate device name from baud rate */
*p++ = '\0';
/* check for second colon */
if ((pp = strchr(p, ':'))) {
/* this is needed to normally acquire baud rate */
*pp++ = '\0';
/* check if it is a system interface */
if (pp[0] == 'S' || pp[0] == 's') {
is_system = 1;
}
}
if (str2uint(p, &rate)) {
lprintf(LOG_ERR, "Invalid baud rate specified\n");
return -1;
}
}
intf->fd = open(intf->devfile, O_RDWR | O_NONBLOCK, 0);
if (intf->fd < 0) {
lperror(LOG_ERR, "Could not open device at %s", intf->devfile);
return -1;
}
for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
if (rates[i].baudrate == rate) {
break;
}
}
if (i >= sizeof(rates) / sizeof(rates[0])) {
lprintf(LOG_ERR, "Unsupported baud rate %i specified", rate);
return -1;
}
tcgetattr(intf->fd, &ti);
cfsetispeed(&ti, rates[i].baudinit);
cfsetospeed(&ti, rates[i].baudinit);
/* 8N1 */
ti.c_cflag &= ~PARENB;
ti.c_cflag &= ~CSTOPB;
ti.c_cflag &= ~CSIZE;
ti.c_cflag |= CS8;
/* enable the receiver and set local mode */
ti.c_cflag |= (CLOCAL | CREAD);
/* no flow control */
ti.c_cflag &= ~CRTSCTS;
ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP
| IXON | IXOFF | IXANY);
#ifdef IUCLC
/* Only disable uppercase-to-lowercase mapping on input for
platforms supporting the flag. */
ti.c_iflag &= ~(IUCLC);
#endif
ti.c_oflag &= ~(OPOST);
ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH);
/* set the new options for the port with flushing */
tcsetattr(intf->fd, TCSAFLUSH, &ti);
if (intf->session->timeout == 0)
intf->session->timeout = IPMI_SERIAL_TIMEOUT;
if (intf->session->retry == 0)
intf->session->retry = IPMI_SERIAL_RETRY;
intf->opened = 1;
return 0;
}
static void
ipmi_serial_term_close(struct ipmi_intf * intf)
{
if (intf->opened) {
close(intf->fd);
intf->fd = -1;
}
if (intf->session) {
free(intf->session);
intf->session = NULL;
}
intf->opened = 0;
}
/*
* This function waits for incoming byte during timeout (ms).
*/
static int
serial_wait_for_data(struct ipmi_intf * intf)
{
int n;
struct pollfd pfd;
pfd.fd = intf->fd;
pfd.events = POLLIN;
pfd.revents = 0;
n = poll(&pfd, 1, intf->session->timeout*1000);
if (n < 0) {
lperror(LOG_ERR, "Poll for serial data failed");
return -1;
} else if (!n) {
return -1;
}
return 0;
}
/*
* Read a line from serial port
* Returns > 0 if there is a line, < 0 on error or timeout
*/
static int
serial_read_line(struct ipmi_intf * intf, char *str, int len)
{
int rv, i;
*str = 0;
i = 0;
while (i < len) {
if (serial_wait_for_data(intf)) {
return -1;
}
rv = read(intf->fd, str + i, 1);
if (rv < 0) {
return -1;
} else if (!rv) {
lperror(LOG_ERR, "Serial read failed: %s", strerror(errno));
return -1;
}
if (str[i] == '\n' || str[i] == '\r') {
if (verbose > 4) {
char c = str[i];
str[i] = '\0';
fprintf(stderr, "Received data: %s\n", str);
str[i] = c;
}
return i + 1;
} else {
i++;
}
}
lprintf(LOG_ERR, "Serial data is too long");
return -1;
}
/*
* Send zero-terminated string to serial port
* Returns the string length or negative error code
*/
static int
serial_write_line(struct ipmi_intf * intf, const char *str)
{
int rv, cnt = 0;
int cb = strlen(str);
while (cnt < cb) {
rv = write(intf->fd, str + cnt, cb - cnt);
if (rv < 0) {
return -1;
} else if (rv == 0) {
return -1;
}
cnt += rv;
}
return cnt;
}
/*
* Flush the buffers
*/
static int
serial_flush(struct ipmi_intf * intf)
{
#if defined(TCFLSH)
return ioctl(intf->fd, TCFLSH, TCIOFLUSH);
#elif defined(TIOCFLUSH)
return ioctl(intf->fd, TIOCFLUSH);
#else
# error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)"
#endif
}
/*
* Receive IPMI response from the device
* Len: buffer size
* Returns: -1 or response lenth on success
*/
static int
recv_response(struct ipmi_intf * intf, unsigned char *data, int len)
{
char hex_rs[IPMI_SERIAL_MAX_RESPONSE * 3];
int i, j, resp_len = 0;
unsigned long rv;
char *p, *pp;
char ch, str_hex[3];
p = hex_rs;
while (1) {
if ((rv = serial_read_line(intf, p, sizeof(hex_rs) - resp_len)) < 0) {
/* error */
return -1;
}
p += rv;
resp_len += rv;
if (*(p - 2) == ']' && (*(p - 1) == '\n' || *(p - 1) == '\r')) {
*p = 0;
break;
}
}
p = strrchr(hex_rs, '[');
if (!p) {
lprintf(LOG_ERR, "Serial response is invalid");
return -1;
}
p++;
pp = strchr(p, ']');
if (!pp) {
lprintf(LOG_ERR, "Serial response is invalid");
return -1;
}
*pp = 0;
/* was it an error? */
if (strncmp(p, "ERR ", 4) == 0) {
serial_write_line(intf, "\r\r\r\r");
sleep(1);
serial_flush(intf);
errno = 0;
rv = strtoul(p + 4, &p, 16);
if ((rv && rv < 0x100 && *p == '\0')
|| (rv == 0 && !errno)) {
/* The message didn't get it through. The upper
level will have to re-send */
return 0;
} else {
lprintf(LOG_ERR, "Serial response is invalid");
return -1;
}
}
/* this is needed for correct string to long conversion */
str_hex[2] = 0;
/* parse the response */
i = 0;
j = 0;
while (*p) {
if (i >= len) {
lprintf(LOG_ERR, "Serial response is too long(%d, %d)", i, len);
return -1;
}
ch = *(p++);
if (isxdigit(ch)) {
str_hex[j++] = ch;
} else {
if (j == 1 || !isspace(ch)) {
lprintf(LOG_ERR, "Serial response is invalid");
return -1;
}
}
if (j == 2) {
unsigned long tmp;
errno = 0;
/* parse the hex number */
tmp = strtoul(str_hex, NULL, 16);
if ( tmp > 0xFF || ( !tmp && errno ) ) {
lprintf(LOG_ERR, "Serial response is invalid");
return -1;
}
data[i++] = tmp;
j = 0;
}
}
return i;
}
/*
* Allocate sequence number for tracking
*/
static uint8_t
serial_term_alloc_seq(void)
{
static uint8_t seq = 0;
if (++seq == 64) {
seq = 0;
}
return seq;
}
/*
* Build IPMB message to be transmitted
*/
static int
serial_term_build_msg(const struct ipmi_intf * intf,
const struct ipmi_rq * req, uint8_t * msg, size_t max_len,
struct serial_term_request_ctx * ctx, int * msg_len)
{
uint8_t * data = msg, seq;
struct serial_term_hdr * term_hdr = (struct serial_term_hdr *) msg;
struct ipmi_send_message_rq * outer_rq = NULL;
struct ipmi_send_message_rq * inner_rq = NULL;
int bridging_level;
/* acquire bridging level */
if (intf->target_addr && intf->target_addr != intf->my_addr) {
if (intf->transit_addr != 0) {
bridging_level = 2;
} else {
bridging_level = 1;
}
} else {
bridging_level = 0;
}
/* check overall packet length */
if(req->msg.data_len + 3 + bridging_level * 8 > max_len) {
lprintf(LOG_ERR, "ipmitool: Message data is too long");
return -1;
}
/* allocate new sequence number */
seq = serial_term_alloc_seq() << 2;
/* check for bridging */
if (bridging_level) {
/* compose terminal message header */
term_hdr->netFn = 0x18;
term_hdr->seq = seq;
term_hdr->cmd = 0x34;
/* set pointer to send message request data */
outer_rq = (struct ipmi_send_message_rq *) (term_hdr + 1);
if (bridging_level == 2) {
/* compose the outer send message request */
outer_rq->channel = intf->transit_channel | 0x40;
outer_rq->msg.rsSA = intf->transit_addr;
outer_rq->msg.netFn = 0x18;
outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn);
outer_rq->msg.rqSA = intf->my_addr;
outer_rq->msg.rqSeq = seq;
outer_rq->msg.cmd = 0x34;
/* inner request is further */
inner_rq = (outer_rq + 1);
} else {
/* there is only one header */
inner_rq = outer_rq;
}
/* compose the inner send message request */
inner_rq->channel = intf->target_channel | 0x40;
inner_rq->msg.rsSA = intf->target_addr;
inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun;
inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn);
inner_rq->msg.rqSA = intf->my_addr;
inner_rq->msg.rqSeq = seq;
inner_rq->msg.cmd = req->msg.cmd;
/* check if interface is the system one */
if (is_system) {
/* need response to LUN 2 */
outer_rq->msg.rqSeq |= 2;
/* do not track response */
outer_rq->channel &= ~0x40;
/* restore BMC SA if bridging not to primary IPMB channel */
if (outer_rq->channel) {
outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR;
}
}
/* fill the second context */
ctx[1].netFn = outer_rq->msg.netFn;
ctx[1].sa = outer_rq->msg.rsSA;
ctx[1].seq = outer_rq->msg.rqSeq;
ctx[1].cmd = outer_rq->msg.cmd;
/* move write pointer */
msg = (uint8_t *)(inner_rq + 1);
} else {
/* compose terminal message header */
term_hdr->netFn = (req->msg.netfn << 2) | req->msg.lun;
term_hdr->seq = seq;
term_hdr->cmd = req->msg.cmd;
/* move write pointer */
msg = (uint8_t *)(term_hdr + 1);
}
/* fill the first context */
ctx[0].netFn = term_hdr->netFn;
ctx[0].seq = term_hdr->seq;
ctx[0].cmd = term_hdr->cmd;
/* write request data */
memcpy(msg, req->msg.data, req->msg.data_len);
/* move write pointer */
msg += req->msg.data_len;
if (bridging_level) {
/* write inner message checksum */
*msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3);
/* check for double bridging */
if (bridging_level == 2) {
/* write outer message checksum */
*msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4);
}
}
/* save message length */
*msg_len = msg - data;
/* return bridging level */
return bridging_level;
}
/*
* Send message to serial port
*/
static int
serial_term_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len)
{
int i, size, tmp = 0;
uint8_t * buf, * data;
if (verbose > 3) {
fprintf(stderr, "Sending request:\n");
fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[0]);
fprintf(stderr, " rqSeq = 0x%x\n", msg[1]);
fprintf(stderr, " cmd = 0x%x\n", msg[2]);
if (msg_len > 7) {
fprintf(stderr, " data_len = %d\n", msg_len - 3);
fprintf(stderr, " data = %s\n",
buf2str(msg + 3, msg_len - 3));
}
}
if (verbose > 4) {
fprintf(stderr, "Message data:\n");
fprintf(stderr, " %s\n", buf2str(msg, msg_len));
}
/* calculate required buffer size */
size = msg_len * 2 + 4;
/* allocate buffer for output data */
buf = data = (uint8_t *) alloca(size);
if (!buf) {
lperror(LOG_ERR, "ipmitool: alloca error");
return -1;
}
/* start character */
*buf++ = '[';
/* body */
for (i = 0; i < msg_len; i++) {
buf += sprintf( buf, "%02x", msg[i]);
}
/* stop character */
*buf++ = ']';
/* carriage return */
*buf++ = '\r';
/* line feed */
*buf++ = '\n';
/* write data to serial port */
tmp = write(intf->fd, data, size);
if (tmp <= 0) {
lperror(LOG_ERR, "ipmitool: write error");
return -1;
}
return 0;
}
/*
* Wait for request response
*/
static int
serial_term_wait_response(struct ipmi_intf * intf,
struct serial_term_request_ctx * req_ctx,
uint8_t * msg, size_t max_len)
{
struct serial_term_hdr * hdr = (struct serial_term_hdr *) msg;
int msg_len;
/* wait for response(s) */
do {
/* receive message */
msg_len = recv_response(intf, msg, max_len);
/* check if valid message received */
if (msg_len > 0) {
/* validate message size */
if (msg_len < 4) {
/* either bad response or non-related message */
continue;
}
/* check for the waited response */
if (hdr->netFn == (req_ctx->netFn|4)
&& (hdr->seq & ~3) == req_ctx->seq
&& hdr->cmd == req_ctx->cmd) {
/* check if something new has been parsed */
if (verbose > 3) {
fprintf(stderr, "Got response:\n");
fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[0]);
fprintf(stderr, " rqSeq/Bridge = 0x%x\n", msg[1]);
fprintf(stderr, " cmd = 0x%x\n", msg[2]);
fprintf(stderr, " completion code = 0x%x\n", msg[3]);
if (msg_len > 8) {
fprintf(stderr, " data_len = %d\n",
msg_len - 4);
fprintf(stderr, " data = %s\n",
buf2str(msg + 4, msg_len - 4));
}
}
/* move to start from completion code */
memmove(msg, hdr + 1, msg_len - sizeof (*hdr));
/* the waited one */
return msg_len - sizeof (*hdr);
}
}
} while (msg_len > 0);
return 0;
}
/*
* Get message from receive message queue
*/
static int
serial_term_get_message(struct ipmi_intf * intf,
struct serial_term_request_ctx * req_ctx,
uint8_t * msg, size_t max_len)
{
uint8_t data[IPMI_SERIAL_MAX_RESPONSE];
struct serial_term_request_ctx tmp_ctx;
struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data;
struct serial_term_hdr hdr;
clock_t start, tm;
int rv, netFn, rqSeq;
start = clock();
do {
/* fill-in request context */
tmp_ctx.netFn = 0x18;
tmp_ctx.seq = serial_term_alloc_seq() << 2;
tmp_ctx.cmd = 0x33;
/* fill-in request data */
hdr.netFn = tmp_ctx.netFn;
hdr.seq = tmp_ctx.seq;
hdr.cmd = tmp_ctx.cmd;
/* send request */
serial_flush(intf);
serial_term_send_msg(intf, (uint8_t *) &hdr, 3);
/* wait for response */
rv = serial_term_wait_response(intf, &tmp_ctx, data, sizeof (data));
/* check for IO error or timeout */
if (rv <= 0) {
return rv;
}
netFn = (req_ctx->netFn & ~3)|(req_ctx->seq & 3)|4;
rqSeq = req_ctx->seq & ~3;
/* check completion code */
if (rp->completion == 0) {
/* check for the waited response */
if (rp->netFn == netFn
&& rp->rsSA == req_ctx->sa
&& rp->rqSeq == rqSeq
&& rp->cmd == req_ctx->cmd) {
/* copy the rest of message */
memcpy(msg, rp + 1, rv - sizeof (*rp) - 1);
return rv - sizeof (*rp) - 1;
}
} else if (rp->completion != 0x80) {
return 0;
}
tm = clock() - start;
tm /= CLOCKS_PER_SEC;
} while (tm < intf->session->timeout);
return 0;
}
static struct ipmi_rs *
ipmi_serial_term_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
{
static struct ipmi_rs rsp;
uint8_t msg[IPMI_SERIAL_MAX_RESPONSE], * resp = msg;
struct serial_term_request_ctx req_ctx[2];
int retry, rv, msg_len, bridging_level;
if (!intf->opened && intf->open && intf->open(intf) < 0) {
return NULL;
}
/* Send the message and receive the answer */
for (retry = 0; retry < intf->session->retry; retry++) {
/* build output message */
bridging_level = serial_term_build_msg(intf, req, msg,
sizeof (msg), req_ctx, &msg_len);
if (msg_len < 0) {
return NULL;
}
/* send request */
serial_flush(intf);
serial_term_send_msg(intf, msg, msg_len);
/* wait for response */
rv = serial_term_wait_response(intf, &req_ctx[0], msg, sizeof (msg));
/* check for IO error */
if (rv < 0) {
return NULL;
}
/* check for timeout */
if (rv == 0) {
continue;
}
/* check for bridging */
if (bridging_level && msg[0] == 0) {
/* in the case of payload interface we check receive message queue */
if (is_system) {
/* check message flags */
rv = serial_term_get_message(intf, &req_ctx[1],
msg, sizeof (msg));
/* check for IO error */
if (rv < 0) {
return NULL;
}
/* check for timeout */
if (rv == 0) {
continue;
}
/* check if response for inner request is not encapsulated */
} else if (rv == 1) {
/* wait for response for inner request */
rv = serial_term_wait_response(intf, &req_ctx[1],
msg, sizeof (msg));
/* check for IO error */
if (rv < 0) {
return NULL;
}
/* check for timeout */
if (rv == 0) {
continue;
}
} else {
/* skip outer level header */
resp = msg + sizeof (struct ipmb_msg_hdr) + 1;
/* decrement response size */
rv -= + sizeof (struct ipmb_msg_hdr) + 2;
}
/* check response size */
if (resp[0] == 0 && bridging_level == 2 && rv < 8) {
lprintf(LOG_ERR, "ipmitool: Message response is too short");
/* invalid message length */
return NULL;
}
}
/* check for double bridging */
if (bridging_level == 2 && resp[0] == 0) {
/* get completion code */
rsp.ccode = resp[7];
rsp.data_len = rv - 9;
memcpy(rsp.data, resp + 8, rsp.data_len);
} else {
rsp.ccode = resp[0];
rsp.data_len = rv - 1;
memcpy(rsp.data, resp + 1, rsp.data_len);
}
/* return response */
return &rsp;
}
/* no valid response */
return NULL;
}
static int
ipmi_serial_term_setup(struct ipmi_intf * intf)
{
intf->session = malloc(sizeof(struct ipmi_session));
if (intf->session == NULL) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return -1;
}
memset(intf->session, 0, sizeof(struct ipmi_session));
return 0;
}
int
ipmi_serial_term_set_my_addr(struct ipmi_intf * intf, uint8_t addr)
{
intf->my_addr = addr;
return 0;
}
struct ipmi_intf ipmi_serial_term_intf = {
name: "serial-terminal",
desc: "Serial Interface, Terminal Mode",
setup: ipmi_serial_term_setup,
open: ipmi_serial_term_open,
close: ipmi_serial_term_close,
sendrecv: ipmi_serial_term_send_cmd,
set_my_addr:ipmi_serial_term_set_my_addr
};