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 <[email protected]> --- 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
