On Fri, Apr 05, 2019 at 05:32:09PM -0400, Asmaa Mnebhi wrote: > Support receiving IPMB request on Satellite MC. The Satellite > MC uses this code to handle the incoming IPMB request, > generate a response and send it back to the requester. > > For instance, if it is an IPMB bridged request, a BMC will be > fowarding the request message to the responder device > (satellite MC for example), so this code would be supported > on the responder device, which will generate a response and send > it back to the BMC.
This looks good, I have some minor nits but it shoudl be very close. Comments inline... > > Signed-off-by: Asmaa Mnebhi <as...@mellanox.com> > --- > lanserv/Makefile.am | 2 +- > lanserv/OpenIPMI/Makefile.am | 2 +- > lanserv/OpenIPMI/ipmbserv.h | 62 +++++++++++++ > lanserv/OpenIPMI/serv.h | 1 + > lanserv/README.design | 6 +- > lanserv/bmc.c | 3 + > lanserv/config.c | 13 +++ > lanserv/ipmb_ipmi.c | 209 > +++++++++++++++++++++++++++++++++++++++++++ > lanserv/ipmi_sim.c | 79 ++++++++++++++++ > lanserv/lan.conf | 9 ++ > 10 files changed, 383 insertions(+), 3 deletions(-) > create mode 100644 lanserv/OpenIPMI/ipmbserv.h > create mode 100644 lanserv/ipmb_ipmi.c > > diff --git a/lanserv/Makefile.am b/lanserv/Makefile.am > index 265b74a..659e957 100644 > --- a/lanserv/Makefile.am > +++ b/lanserv/Makefile.am > @@ -34,7 +34,7 @@ noinst_HEADERS = emu.h bmc.h > > libIPMIlanserv_la_SOURCES = lanserv_ipmi.c lanserv_asf.c priv_table.c \ > lanserv_oem_force.c lanserv_config.c config.c serv.c serial_ipmi.c \ > - persist.c extcmd.c > + persist.c extcmd.c ipmb_ipmi.c > libIPMIlanserv_la_LIBADD = $(OPENSSLLIBS) -ldl $(RT_LIB) > libIPMIlanserv_la_LDFLAGS = -version-info $(LD_VERSION) \ > ../utils/libOpenIPMIutils.la > diff --git a/lanserv/OpenIPMI/Makefile.am b/lanserv/OpenIPMI/Makefile.am > index ab1e514..7c17c10 100644 > --- a/lanserv/OpenIPMI/Makefile.am > +++ b/lanserv/OpenIPMI/Makefile.am > @@ -1,3 +1,3 @@ > > pkginclude_HEADERS = lanserv.h serserv.h serv.h extcmd.h persist.h msg.h \ > - mcserv.h > + mcserv.h ipmbserv.h > diff --git a/lanserv/OpenIPMI/ipmbserv.h b/lanserv/OpenIPMI/ipmbserv.h > new file mode 100644 > index 0000000..fcc6958 > --- /dev/null > +++ b/lanserv/OpenIPMI/ipmbserv.h > @@ -0,0 +1,62 @@ > +/* > + * ipmbserv.h > + * > + * IPMB server include file > + * > + * Copyright 2019 Mellanox > + * > + * This software is available to you under a choice of one of two > + * licenses. You may choose to be licensed under the terms of the GNU > + * Lesser General Public License (GPL) Version 2 or the modified BSD > + * license below. The following disclamer applies to both licenses: > + * > + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. > + * > + * GNU Lesser General Public Licence > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public License > + * as published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this program; if not, write to the Free > + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > + * > + * Modified BSD Licence > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. 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. > + * 3. The name of the author may not be used to endorse or promote > + * products derived from this software without specific prior > + * written permission. > + */ > + > +#ifndef __IPMBSERV_H > +#define __IPMBSERV_H > + > +#include <OpenIPMI/msg.h> > +#include <OpenIPMI/serserv.h> > + > +typedef struct serserv_data_s ipmbserv_data_t; > + > +int ipmb_read_config(sys_data_t *sys, const char **errstr, unsigned int > chan_num); > + > +#endif /* __IPMBSERV_H */ > diff --git a/lanserv/OpenIPMI/serv.h b/lanserv/OpenIPMI/serv.h > index d2087f5..10f2fb0 100644 > --- a/lanserv/OpenIPMI/serv.h > +++ b/lanserv/OpenIPMI/serv.h > @@ -408,6 +408,7 @@ struct sys_data_s { > void (*cfree)(channel_t *chan, void *data); > int (*lan_channel_init)(void *info, channel_t *chan); > int (*ser_channel_init)(void *info, channel_t *chan); > + int (*ipmb_channel_init)(void *info, channel_t *chan); > }; > > static inline void > diff --git a/lanserv/README.design b/lanserv/README.design > index 2f897c4..5260a6c 100644 > --- a/lanserv/README.design > +++ b/lanserv/README.design > @@ -31,6 +31,8 @@ msg.h - This defines an IPMI message that is passed around, > and a few > > serserv.h - The configuration of a serial interface. > > +ipmbserv.h - The configuration of an IPMB interface. > + > serv.h - This defines data structures used by the whole system. > > > @@ -77,6 +79,8 @@ emu.h - Defines the interface between bmc_xxx.c and > emu_cmd.c > extcmd.c - Code for running the external command for dealing with LAN > configuration. > > +ipmb_ipmi.c - An implementation of the IPMB protocol. > + > ipmi_sim.c - The main file for the ipmi_sim program. > > lanserv_asf.c - Handles LAN ASF commands. > @@ -179,4 +183,4 @@ It is called from config.c to handle sol-specific > configuration. > It installs a hook into lanserv_ipmi.c to receive the SOL payload and > send the SOL payload. > > -It ties into bmc.c to handle SOL-specific commands. > \ No newline at end of file > +It ties into bmc.c to handle SOL-specific commands. > diff --git a/lanserv/bmc.c b/lanserv/bmc.c > index 93d0b3f..ceb3b41 100644 > --- a/lanserv/bmc.c > +++ b/lanserv/bmc.c > @@ -613,6 +613,9 @@ ipmi_mc_enable(lmc_data_t *mc) > err = sys->lan_channel_init(sys->info, chan); > else if (chan->medium_type == IPMI_CHANNEL_MEDIUM_RS232) > err = sys->ser_channel_init(sys->info, chan); > + else if ((chan->medium_type == IPMI_CHANNEL_MEDIUM_IPMB) && > + (chan->channel_num != 0)) Why not channel 0? > + err = sys->ipmb_channel_init(sys->info, chan); > else > chan_init(chan); > if (err) { > diff --git a/lanserv/config.c b/lanserv/config.c > index f0dda9f..e018080 100644 > --- a/lanserv/config.c > +++ b/lanserv/config.c > @@ -64,6 +64,7 @@ > #include <OpenIPMI/serv.h> > #include <OpenIPMI/lanserv.h> > #include <OpenIPMI/serserv.h> > +#include <OpenIPMI/ipmbserv.h> > #include <OpenIPMI/persist.h> > > void > @@ -829,6 +830,18 @@ read_config(sys_data_t *sys, > } > } else if (strcmp(tok, "user") == 0) { > err = get_user(&tokptr, sys, &errstr); > + } else if (strcmp(tok, "ipmb") == 0) { > + err = get_uint(&tokptr, &val, &errstr); > + if (!err && (val >= IPMI_MAX_CHANNELS)) { > + err = -1; > + errstr = "Channel number out of range"; > + } else if (val == 0) { > + err = -1; > + errstr = "Channel number should not be set to primary IPMB"; > + } Can we do all of the above in ipmb_read_config()? Why can't you set ipmb channel 0? That seems like what you would normally want to do. Also, there is no checking that the channel number is not already in use, and this assumes that you can only have a single ipmb channel. I would like some flexibility to add multiple ipmb channels and have different types. Could it be something like: ipmb <chan> ipmidev /dev/ipmb-dev What is /dev/ipmb-dev, btw? I'm not familiar with that? Is it just a normal I2C channel on Linux? > + if (!err) { > + err = ipmb_read_config(sys, &errstr, val); > + } > } else if (strcmp(tok, "serial") == 0) { > err = serserv_read_config(&tokptr, sys, &errstr); > } else if (strcmp(tok, "sol") == 0) { > diff --git a/lanserv/ipmb_ipmi.c b/lanserv/ipmb_ipmi.c > new file mode 100644 > index 0000000..f68b79a > --- /dev/null > +++ b/lanserv/ipmb_ipmi.c > @@ -0,0 +1,209 @@ > +/* > + * ipmb_ipmi.c > + * > + * IPMB server interface. > + * > + * Copyright 2019 Mellanox > + * > + * This software is available to you under a choice of one of two > + * licenses. You may choose to be licensed under the terms of the GNU > + * Lesser General Public License (GPL) Version 2 or the modified BSD > + * license below. The following disclamer applies to both licenses: > + * > + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. > + * > + * GNU Lesser General Public Licence > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public License > + * as published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this program; if not, write to the Free > + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > + * > + * Modified BSD Licence > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. 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. > + * 3. The name of the author may not be used to endorse or promote > + * products derived from this software without specific prior > + * written permission. > + */ > + > +#include <string.h> > +#include <stdlib.h> > +#include <OpenIPMI/ipmbserv.h> > +#include <OpenIPMI/ipmi_mc.h> > + > +static void > +raw_send(ipmbserv_data_t *ipmb, unsigned char *data, unsigned int len) > +{ > + if (ipmb->sysinfo->debug & DEBUG_RAW_MSG) > + debug_log_raw_msg(ipmb->sysinfo, data, len, "Raw serial send:"); > + ipmb->send_out(ipmb, data, len); > +} > + > +/*********************************************************************** > + * > + * IPMB message > + * > + * According to the IPMI spec, the IPMB message size should never > + * exceed 32 bytes. So it doesn't harm to set the max size of the > + * recv_msg to 36 bytes. > + * > + ***********************************************************************/ > +struct ipmb_data { > + unsigned char recv_msg[IPMI_SIM_MAX_MSG_LENGTH + 4]; > + unsigned int recv_msg_len; > + int recv_msg_too_many; > +}; > + > +static void > +ipmb_handle_msg(unsigned char *imsg, unsigned int len, ipmbserv_data_t *ipmb) > +{ > + msg_t msg; > + > + if (len < 8) { > + fprintf(stderr, "Message too short\n"); > + return; > + } > + /* subtract len field and checksum */ > + len--; > + imsg++; > + > + if (ipmb_checksum(imsg, len, 0) != 0) { > + fprintf(stderr, "Message checksum failure\n"); > + return; > + } > + len--; > + > + memset(&msg, 0, sizeof(msg)); > + > + msg.rs_addr = imsg[0]; > + msg.netfn = imsg[1] >> 2; > + msg.rs_lun = imsg[1] & 3; > + /* imsg[2] is first checksum */ > + msg.rq_addr = imsg[3]; > + msg.rq_seq = imsg[4] >> 2; > + msg.rq_lun = imsg[4] & 3; > + msg.cmd = imsg[5]; > + > + msg.len = len - 6; > + msg.data = imsg + 6; > + > + msg.src_addr = NULL; > + msg.src_len = 0; > + > + channel_smi_send(&ipmb->channel, &msg); > +} > + > +static void > +ipmb_handle_char(unsigned char ch, ipmbserv_data_t *ipmb) > +{ > + struct ipmb_data *info = ipmb->codec_info; > + unsigned int len = info->recv_msg_len; > + > + if (ipmb->bind_fd == 0) { > + if (info->recv_msg_len != 0) { > + ipmb_handle_msg(info->recv_msg, info->recv_msg_len, ipmb); > + info->recv_msg_len = 0; > + } > + return; > + } > + > + if (len >= sizeof(info->recv_msg)) > + return; > + > + info->recv_msg[len] = ch; > + info->recv_msg_len++; > +} > + > +static void > +ipmb_send(msg_t *imsg, ipmbserv_data_t *ipmb) > +{ > + unsigned char msg[(IPMI_SIM_MAX_MSG_LENGTH + 7) * 3]; > + unsigned int msg_len; > + > + msg[0] = imsg->len + 7; > + msg[1] = imsg->rs_addr; > + msg[2] = (imsg->netfn << 2) | imsg->rs_lun; > + msg[3] = -ipmb_checksum(msg + 1, 2, 0); > + msg[4] = imsg->rq_addr; > + msg[5] = (imsg->rq_seq << 2) | imsg->rq_lun; > + msg[6] = imsg->cmd; > + memcpy(msg + 7, imsg->data, imsg->len); > + msg_len = imsg->len + 7; > + msg[msg_len] = -ipmb_checksum(msg + 4, msg_len - 4, 0); > + msg_len++; > + > + raw_send(ipmb, msg, msg_len); > +} > + > +static int > +ipmb_setup(ipmbserv_data_t *ipmb) > +{ > + struct ipmb_data *info; > + > + info = malloc(sizeof(*info)); > + if (!info) > + return -1; > + memset(info, 0, sizeof(*info)); > + ipmb->codec_info = info; > + ipmb->connected = 1; > + return 0; > +} > + > +int > +ipmb_read_config(sys_data_t *sys, const char **errstr, unsigned int chan_num) > +{ > + ipmbserv_data_t *ipmb; > + > + ipmb = malloc(sizeof(*ipmb)); > + if (!ipmb) { > + *errstr = "Out of memory"; > + return -1; > + } > + memset(ipmb, 0, sizeof(*ipmb)); > + > + ipmb->codec = (ser_codec_t *)malloc(sizeof(ser_codec_t)); > + if (!ipmb->codec) { > + *errstr = "Out of memory"; > + return -1; > + } > + > + ipmb->channel.session_support = IPMI_CHANNEL_SESSION_LESS; > + ipmb->channel.medium_type = IPMI_CHANNEL_MEDIUM_IPMB; > + ipmb->channel.protocol_type = IPMI_CHANNEL_PROTOCOL_IPMB; > + > + ipmb->channel.channel_num = chan_num; > + > + ipmb->codec->handle_char = ipmb_handle_char; > + ipmb->codec->send = ipmb_send; > + ipmb->codec->setup = ipmb_setup; > + > + ipmb->sysinfo = sys; > + ipmb->channel.chan_info = ipmb; > + > + sys->chan_set[chan_num] = &ipmb->channel; You should check if this is already set by something else. > + > + return 0; > +} > diff --git a/lanserv/ipmi_sim.c b/lanserv/ipmi_sim.c > index c4e5b18..a3ae795 100644 > --- a/lanserv/ipmi_sim.c > +++ b/lanserv/ipmi_sim.c > @@ -90,6 +90,7 @@ > #include <OpenIPMI/serv.h> > #include <OpenIPMI/lanserv.h> > #include <OpenIPMI/serserv.h> > +#include <OpenIPMI/ipmbserv.h> > > #include "emu.h" > #include <OpenIPMI/persist.h> > @@ -567,6 +568,83 @@ ser_channel_init(void *info, channel_t *chan) > return err; > } > > +static int > +ipmb_open(char *ipmi_dev) > +{ > + int ipmi_fd; > + > + ipmi_fd = open("/dev/ipmb-dev", O_RDWR); > + > + if (ipmi_fd == -1) { > + perror("Could not open ipmi device /dev/ipmb-dev"); > + } > + > + return ipmi_fd; > +} > + > +static void > +ipmb_data_ready(int fd, void *cb_data, os_hnd_fd_id_t *id) > +{ > + ipmbserv_data_t *ipmb = cb_data; > + unsigned int len; > + unsigned char msgd[256]; > + > + len = read(fd, msgd, sizeof(msgd)); > + > + if (ipmb->sysinfo->debug & DEBUG_MSG) > + printf(">ipmb_data_ready size %d\n", len); > + if (len <= 0) { > + if ((len < 0) && (errno == EINTR)) > + return; > + > + ipmb->os_hnd->remove_fd_to_wait_for(ipmb->os_hnd, id); > + close(fd); > + ipmb->con_fd = -1; > + return; > + } > + > + ipmb->bind_fd = -1; > + serserv_handle_data(ipmb, msgd, len); > + ipmb->bind_fd = 0; > + serserv_handle_data(ipmb, msgd, 1); > +} > + > +static int > +ipmb_channel_init(void *info, channel_t *chan) > +{ > + misc_data_t *data = info; > + ipmbserv_data_t *ipmb = chan->chan_info; > + int err; > + int fd; > + os_hnd_fd_id_t *fd_id; > + > + ipmb->os_hnd = data->os_hnd; > + ipmb->user_info = data; > + ipmb->send_out = ser_send; > + err = serserv_init(ipmb); > + > + if (err) { > + fprintf(stderr, "Unable to init ipmb: 0x%x\n", err); > + exit(1); > + } > + > + fd = ipmb_open(NULL); > + if (fd == -1){ > + fprintf(stderr, "Unable to open ipmi device file: 0x%x\n", err); > + exit(1); > + } > + > + ipmb->con_fd = fd; > + > + err = data->os_hnd->add_fd_to_wait_for(data->os_hnd, ipmb->con_fd, > + ipmb_data_ready, ipmb, > + NULL, &fd_id); > + if (!err) > + isim_add_fd(fd); > + > + return err; > +} > + > static void > isim_log(sys_data_t *sys, int logtype, msg_t *msg, const char *format, > va_list ap, int len) > @@ -1438,6 +1516,7 @@ main(int argc, const char *argv[]) > sysinfo.cfree = ifree; > sysinfo.lan_channel_init = lan_channel_init; > sysinfo.ser_channel_init = ser_channel_init; > + sysinfo.ipmb_channel_init = ipmb_channel_init; > data.sys = &sysinfo; > > err = pipe(sigpipeh); > diff --git a/lanserv/lan.conf b/lanserv/lan.conf > index 37732d4..8d512b2 100644 > --- a/lanserv/lan.conf > +++ b/lanserv/lan.conf > @@ -126,3 +126,12 @@ set_working_mc 0x30 > # where initstr is the init string passed on the module load line. > # It should return 0 on success or an errno no failure. > #loadlib "/opt/lib/ipmi_sim_extend.so" "Initialization String" > + > +# "ipmb" should be added to the config file of a device > +# that needs to handle an IPMB request and generate a response > +# back to the requester. > +# In the case of an IPMB bridge request for example, the > +# BMC is considered the requester and the responder device > +# should have a config file defining the IPMB channel number. > +# For example: > +# ipmb 2 > -- > 2.1.2 > > > > _______________________________________________ > Openipmi-developer mailing list > Openipmi-developer@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/openipmi-developer _______________________________________________ Openipmi-developer mailing list Openipmi-developer@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openipmi-developer