The "Set LAN Configuration Parameters" IPMI command is added to the
`ipmi_bmc_sim` device to support dynamically setting fake LAN channel
configurations. With the fake LAN channel enabled, inside the guest OS,
tools such as `ipmitool` can be used to modify the configurations.
Signed-off-by: Yunpeng Yang <yunpeng.yang@nutanix.com>
---
hw/ipmi/ipmi_bmc_sim.c | 110 ++++++++++++++++++++++++++++++++++++
tests/qtest/ipmi-kcs-test.c | 83 +++++++++++++++++++++++++++
2 files changed, 193 insertions(+)
diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index 2ead46ee55..f4cea91fde 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -106,6 +106,7 @@
#define IPMI_NETFN_TRANSPORT 0x0c
+#define IPMI_CMD_SET_LAN_CONFIG 0x01
#define IPMI_CMD_GET_LAN_CONFIG 0x02
@@ -300,6 +301,7 @@ struct IPMIBmcSim {
((ibs)->lan.channel != 0 && (ibs)->lan.channel == (c))
#define IPMI_BMC_LAN_CFG_CC_PARAM_NOT_SUPPORTED 0x80
+#define IPMI_BMC_LAN_CFG_CC_PARAM_READONLY 0x82
#define IPMI_BMC_LAN_CFG_PARAM_SET_IN_PROGRESS 0x00
#define IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_SUPPORT 0x01
@@ -2131,6 +2133,113 @@ static inline bool is_valid_netmask(const uint8_t *netmask)
return mask != 0 && (inverted & (inverted + 1)) == 0;
}
+/*
+ * Request data (from cmd[2] on):
+ * bytes meaning
+ * 1 [bits 3:0] channel number
+ * 2 parameter selector
+ * [3:N] configuration parameter data (from cmd[4] on)
+ */
+static void set_lan_config(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ RspBuffer *rsp)
+{
+ uint8_t channel;
+ uint8_t *param; /* pointer to configuration parameter data */
+ unsigned int param_len;
+
+ if (ibs->lan.channel == 0) {
+ /* LAN channel disabled. Fail as if this command were not defined. */
+ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
+ return;
+ }
+ if (cmd_len < 5) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ channel = cmd[2] & 0xf;
+ param = cmd + 4;
+ param_len = cmd_len - 4;
+
+ if (!IPMI_BMC_CHANNEL_IS_LAN(ibs, channel)) {
+ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+ return;
+ }
+
+ switch (cmd[3]) {
+ case IPMI_BMC_LAN_CFG_PARAM_IP_ADDR:
+ if (param_len < NBYTES_IP) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ memcpy(ibs->lan.ipaddr, param, NBYTES_IP);
+ break;
+
+ case IPMI_BMC_LAN_CFG_PARAM_IP_ADDR_SOURCE:
+ if (param_len < 1) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ if (!IPMI_BMC_LAN_CFG_IS_VALID_IP_SOURCE(*param)) {
+ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+ return;
+ }
+ ibs->lan.ipsrc = *param;
+ break;
+
+ case IPMI_BMC_LAN_CFG_PARAM_MAC_ADDR:
+ if (param_len < NBYTES_MAC) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ memcpy(ibs->lan.macaddr.a, param, NBYTES_MAC);
+ break;
+
+ case IPMI_BMC_LAN_CFG_PARAM_SUBNET_MASK:
+ if (param_len < NBYTES_IP) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ if (!is_valid_netmask(param)) {
+ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+ return;
+ }
+ memcpy(ibs->lan.netmask, param, NBYTES_IP);
+ break;
+
+ case IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_IP_ADDR:
+ if (param_len < NBYTES_IP) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ memcpy(ibs->lan.defgw_ipaddr, param, NBYTES_IP);
+ break;
+
+ case IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_MAC_ADDR:
+ if (param_len < NBYTES_MAC) {
+ rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+ return;
+ }
+ memcpy(ibs->lan.defgw_macaddr.a, param, NBYTES_MAC);
+ break;
+
+ case IPMI_BMC_LAN_CFG_PARAM_SET_IN_PROGRESS:
+ case IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_SUPPORT:
+ case IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_ENABLES:
+ case IPMI_BMC_LAN_CFG_PARAM_IPV4_HDR_PARAMS:
+ case IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_ADDR:
+ case IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_MAC_ADDR:
+ case IPMI_BMC_LAN_CFG_PARAM_COMMUNITY_STRING:
+ case IPMI_BMC_LAN_CFG_PARAM_NUM_DESTINATIONS:
+ rsp_buffer_set_error(rsp, IPMI_BMC_LAN_CFG_CC_PARAM_READONLY);
+ return;
+
+ default:
+ rsp_buffer_set_error(rsp, IPMI_BMC_LAN_CFG_CC_PARAM_NOT_SUPPORTED);
+ return;
+ }
+}
+
/*
* Request data (from cmd[2] to cmd[5] inclusive):
* bytes meaning
@@ -2329,6 +2438,7 @@ static const IPMINetfn storage_netfn = {
};
static const IPMICmdHandler transport_cmds[] = {
+ [IPMI_CMD_SET_LAN_CONFIG] = { set_lan_config },
[IPMI_CMD_GET_LAN_CONFIG] = { get_lan_config },
};
static const IPMINetfn transport_netfn = {
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index d0a207477e..9bab0d84ad 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -318,6 +318,88 @@ static void test_kcs_lan_get(void)
}
+/* set/get ip address: 192.0.2.2 */
+static uint8_t lan_set_ipaddr_cmd[] = { 0x30, 0x01, 0x01, 0x03,
+ 0xc0, 0x00, 0x02, 0x02 };
+static uint8_t lan_set_ipaddr_rsp[] = { 0x34, 0x01, 0x00 };
+static uint8_t lan_get_ipaddr_cmd[] = { 0x30, 0x02, 0x01, 0x03, 0x00, 0x00 };
+static uint8_t lan_get_ipaddr_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+ 0xc0, 0x00, 0x02, 0x02 };
+/* set ip address source: static */
+static uint8_t lan_set_ipsrc_cmd[] = { 0x30, 0x01, 0x01, 0x04, 0x01 };
+static uint8_t lan_set_ipsrc_rsp[] = { 0x34, 0x01, 0x00 };
+
+/* set/get subnet mask: 255.255.255.0 */
+static uint8_t lan_set_netmask_cmd[] = { 0x30, 0x01, 0x01, 0x06,
+ 0xff, 0xff, 0xff, 0x00 };
+static uint8_t lan_set_netmask_rsp[] = { 0x34, 0x01, 0x00 };
+static uint8_t lan_get_netmask_cmd[] = { 0x30, 0x02, 0x01, 0x06, 0x00, 0x00 };
+static uint8_t lan_get_netmask_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+ 0xff, 0xff, 0xff, 0x00 };
+
+/* set/get default gateway ip address: 192.0.2.1 */
+static uint8_t lan_set_defgw_ipaddr_cmd[] = { 0x30, 0x01, 0x01, 0x0c,
+ 0xc0, 0x00, 0x02, 0x01 };
+static uint8_t lan_set_defgw_ipaddr_rsp[] = { 0x34, 0x01, 0x00 };
+static uint8_t lan_get_defgw_ipaddr_cmd[] = { 0x30, 0x02, 0x01, 0x0c,
+ 0x00, 0x00 };
+static uint8_t lan_get_defgw_ipaddr_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+ 0xc0, 0x00, 0x02, 0x01 };
+
+/*
+ * Set and then get LAN configurations
+ */
+static void test_kcs_lan_set_get(void)
+{
+ uint8_t rsp[20];
+ unsigned int rsplen = 0;
+
+ /* set ip address */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_set_ipaddr_cmd, sizeof(lan_set_ipaddr_cmd), rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_set_ipaddr_rsp));
+ g_assert(memcmp(lan_set_ipaddr_rsp, rsp, rsplen) == 0);
+
+ /* get ip address */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_get_ipaddr_cmd, sizeof(lan_get_ipaddr_cmd), rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_get_ipaddr_rsp));
+ g_assert(memcmp(lan_get_ipaddr_rsp, rsp, rsplen) == 0);
+
+ /* set ip address source */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_set_ipsrc_cmd, sizeof(lan_set_ipsrc_cmd), rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_set_ipsrc_rsp));
+ g_assert(memcmp(lan_set_ipsrc_rsp, rsp, rsplen) == 0);
+
+ /* set subnet mask */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_set_netmask_cmd, sizeof(lan_set_netmask_cmd), rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_set_netmask_rsp));
+ g_assert(memcmp(lan_set_netmask_rsp, rsp, rsplen) == 0);
+
+ /* get subnet mask */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_get_netmask_cmd, sizeof(lan_get_netmask_cmd), rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_get_netmask_rsp));
+ g_assert(memcmp(lan_get_netmask_rsp, rsp, rsplen) == 0);
+
+ /* set default gateway ip address */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_set_defgw_ipaddr_cmd, sizeof(lan_set_defgw_ipaddr_cmd),
+ rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_set_defgw_ipaddr_rsp));
+ g_assert(memcmp(lan_set_defgw_ipaddr_rsp, rsp, rsplen) == 0);
+
+ /* get default gateway ip address */
+ rsplen = sizeof(rsp);
+ kcs_cmd(lan_get_defgw_ipaddr_cmd, sizeof(lan_get_defgw_ipaddr_cmd),
+ rsp, &rsplen);
+ g_assert(rsplen == sizeof(lan_get_defgw_ipaddr_rsp));
+ g_assert(memcmp(lan_get_defgw_ipaddr_rsp, rsp, rsplen) == 0);
+}
+
+
int main(int argc, char **argv)
{
char *cmdline;
@@ -340,6 +422,7 @@ int main(int argc, char **argv)
qtest_add_func("/ipmi/local/kcs_channel_access", test_kcs_channel_access);
qtest_add_func("/ipmi/local/kcs_channel_info", test_kcs_channel_info);
qtest_add_func("/ipmi/local/kcs_lan_get", test_kcs_lan_get);
+ qtest_add_func("/ipmi/local/kcs_lan_set_get", test_kcs_lan_set_get);
ret = g_test_run();
qtest_quit(global_qtest);
--
2.43.7
© 2016 - 2025 Red Hat, Inc.