summaryrefslogtreecommitdiffstats
path: root/chassishandler.cpp
diff options
context:
space:
mode:
authorRatan Gupta <ratagupt@in.ibm.com>2016-08-01 04:58:01 -0500
committerPatrick Williams <patrick@stwcx.xyz>2016-09-02 03:30:33 +0000
commitfd28dd7ae4dafc8b919098feb2876623474eeeaa (patch)
tree33919d8b0322e57c3e21abfa4fae6df21fda39b7 /chassishandler.cpp
parenteb9b814403895d6435e04f02a9ff6c2b1b02cf54 (diff)
downloadphosphor-host-ipmid-fd28dd7ae4dafc8b919098feb2876623474eeeaa.tar.gz
phosphor-host-ipmid-fd28dd7ae4dafc8b919098feb2876623474eeeaa.zip
Implement Network Settings Override
We want to implement the network settings override functionality. This is an OEM boot parameter selector, using parameter ID 0x61. The first byte of the parameter data is the same as parameter ID 5 (ie, the valid flag in the top bit). Persistency doesn't matter here, as petitboot will not clear out this setting. The rest of the parameter data is a host network settings description. For other BMC firmware, the BMC just treats this as opaque (the BMC will just return the same data (including that data1 byte), in response to a Get System Boot Option). For OpenBMC, we may want the BMC to know how to construct that data; the spec for that is at: http://ozlabs.org/~sam/ipmi-network-format Closes openbmc/openbmc#267 Change-Id: I2af8776718deda97acf90d10504783085ccf7323 Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
Diffstat (limited to 'chassishandler.cpp')
-rw-r--r--chassishandler.cpp397
1 files changed, 377 insertions, 20 deletions
diff --git a/chassishandler.cpp b/chassishandler.cpp
index 92d9752..1df4c0a 100644
--- a/chassishandler.cpp
+++ b/chassishandler.cpp
@@ -1,17 +1,45 @@
#include "chassishandler.h"
#include "ipmid-api.h"
#include <stdio.h>
-#include <string.h>
+#include <stdlib.h>
#include <stdint.h>
#include <mapper.h>
-
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <limits.h>
+#include <string.h>
+#include <endian.h>
+#include <sstream>
+#include <array>
//Defines
-#define SET_PARM_VERSION 1
-#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on
+#define SET_PARM_VERSION 0x01
+#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on
#define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 //boot flags data1 8th bit on
-#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on
-
+#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on
+
+constexpr size_t SIZE_MAC = 18;
+constexpr size_t SIZE_BOOT_OPTION = (uint8_t)BootOptionResponseSize::
+ OPAL_NETWORK_SETTINGS;//Maximum size of the boot option parametrs
+constexpr size_t SIZE_PREFIX = 7;
+constexpr size_t MAX_PREFIX_VALUE = 32;
+constexpr size_t SIZE_COOKIE = 4;
+constexpr size_t SIZE_VERSION = 2;
+constexpr auto MAC_ADDRESS_FORMAT = "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx";
+constexpr auto IP_ADDRESS_FORMAT = "%d.%d.%d.%d";
+constexpr auto PREFIX_FORMAT = "%d";
+constexpr auto ADDR_TYPE_FORMAT = "%hhx";
+//PetiBoot-Specific
+static constexpr uint8_t net_conf_initial_bytes[] = {0x80,0x21, 0x70 ,0x62 ,0x21,
+ 0x00 ,0x01 ,0x06 ,0x04};
+
+static constexpr size_t COOKIE_OFFSET = 1;
+static constexpr size_t VERSION_OFFSET = 5;
+static constexpr size_t MAC_OFFSET = 9;
+static constexpr size_t ADDRTYPE_OFFSET = 16;
+static constexpr size_t IPADDR_OFFSET = 17;
+static constexpr size_t PREFIX_OFFSET = 21;
+static constexpr size_t GATEWAY_OFFSET = 22;
// OpenBMC Chassis Manager dbus framework
@@ -153,14 +181,310 @@ struct get_sys_boot_options_t {
struct get_sys_boot_options_response_t {
uint8_t version;
uint8_t parm;
- uint8_t data[5];
+ uint8_t data[SIZE_BOOT_OPTION];
} __attribute__ ((packed));
struct set_sys_boot_options_t {
uint8_t parameter;
- uint8_t data[8];
+ uint8_t data[SIZE_BOOT_OPTION];
} __attribute__ ((packed));
+struct host_network_config_t {
+ std::string ipaddress;
+ std::string prefix;
+ std::string gateway;
+ std::string macaddress;
+ std::string addrType;
+
+ host_network_config_t()=default;
+};
+
+void fillNetworkConfig( host_network_config_t & host_config ,
+ const std::string& conf_str ) {
+
+ constexpr auto COMMA_DELIMITER = ",";
+ constexpr auto EQUAL_DELIMITER = "=";
+ size_t commaDelimtrPos = 0;
+ size_t equalDelimtrPos = 0,commaDelimtrPrevPos = 0;
+ std::string value;
+ while ( commaDelimtrPos < conf_str.length() ) {
+
+ commaDelimtrPos = conf_str.find(COMMA_DELIMITER,commaDelimtrPos);
+ //This condition is to extract the last
+ //Substring as we will not be having the delimeter
+ //at end. std::string::npos is -1
+
+ if ( commaDelimtrPos == std::string::npos ) {
+ commaDelimtrPos = conf_str.length();
+ }
+
+ equalDelimtrPos = conf_str.find (EQUAL_DELIMITER,commaDelimtrPrevPos);
+
+ //foo,ipaddress=1234
+ if ( equalDelimtrPos == std::string::npos ) {
+
+ commaDelimtrPos++;
+ commaDelimtrPrevPos= commaDelimtrPos;
+ continue;
+ }
+
+ value = conf_str.substr((equalDelimtrPos+1),
+ commaDelimtrPos-(equalDelimtrPos+1));
+
+#ifdef _IPMI_DEBUG_
+ printf ("Name=[%s],Value=[%s],commaDelimtrPos=[%d],\
+ commaDelimtrPrevPos=[%d],equalDelimtrPos=[%d]\n",
+ name.c_str(),value.c_str(),commaDelimtrPos,
+ commaDelimtrPrevPos,equalDelimtrPos);
+#endif
+
+ if ( 0 == conf_str.compare(commaDelimtrPrevPos,
+ equalDelimtrPos-commaDelimtrPrevPos,"ipaddress" )) {
+
+ host_config.ipaddress = std::move(value);
+ }
+ else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
+ equalDelimtrPos-commaDelimtrPrevPos,"prefix" )) {
+
+ host_config.prefix = std::move(value);
+ }
+ else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
+ equalDelimtrPos-commaDelimtrPrevPos, "gateway" )) {
+ host_config.gateway = std::move(value);
+ }
+ else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
+ equalDelimtrPos-commaDelimtrPrevPos, "mac" )) {
+ host_config.macaddress = std::move(value);
+ }
+ else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
+ equalDelimtrPos-commaDelimtrPrevPos, "addr_type" )) {
+ host_config.addrType = std::move(value);
+ }
+
+ commaDelimtrPos++;
+ commaDelimtrPrevPos= commaDelimtrPos;
+ }
+}
+
+int getHostNetworkData(get_sys_boot_options_response_t* respptr)
+{
+
+ char *prop = nullptr;
+ int rc = dbus_get_property("network_config",&prop);
+
+ if ( rc < 0 ) {
+ fprintf(stderr, "Dbus get property(boot_flags) failed\
+ for get_sys_boot_options.\n");
+ return rc;
+ }
+
+ std::string conf_str(prop);
+
+ if ( prop ) {
+
+ free(prop);
+ prop = nullptr;
+ }
+
+ /* network_config property Value would be in the form of
+ * ipaddress=1.1.1.1,prefix=16,gateway=2.2.2.2,mac=11:22:33:44:55:66,dhcp=0
+ */
+
+ /* Parsing the string and fill the hostconfig structure with the
+ * values */
+
+ printf ("Configuration String[%s]\n ",conf_str.c_str());
+
+ host_network_config_t host_config;
+
+ // Fill the host_config from the configuration string
+ fillNetworkConfig(host_config,conf_str);
+
+ //Assigning the index as intialByteLength as it is fixed and prefilled.
+ printf ("host_config.macaddress.c_str()=[%s]\n",host_config.macaddress.c_str());
+ do{
+
+ rc = sscanf(host_config.macaddress.c_str(),MAC_ADDRESS_FORMAT,
+ (respptr->data+MAC_OFFSET), (respptr->data+MAC_OFFSET+1),
+ (respptr->data+MAC_OFFSET+2),(respptr->data+MAC_OFFSET+3),
+ (respptr->data+MAC_OFFSET+4), (respptr->data+MAC_OFFSET+5));
+
+
+ if ( rc < 6 ){
+ fprintf(stderr, "sscanf Failed in extracting mac address.\n");
+ rc = -1;
+ break;
+ }
+
+ //Conevrt the dhcp,ipaddress,mask and gateway as hex number
+ respptr->data[MAC_OFFSET+6]=0x00;
+
+ rc = sscanf(host_config.addrType.c_str(),ADDR_TYPE_FORMAT,
+ (respptr->data+ADDRTYPE_OFFSET));
+
+ if ( rc <= 0 ) {
+ fprintf(stderr, "sscanf Failed in extracting address type.\n");
+ rc = -1;
+ break;
+ }
+
+ //ipaddress and gateway would be in IPv4 format
+ rc = inet_pton(AF_INET,host_config.ipaddress.c_str(),
+ (respptr->data+IPADDR_OFFSET));
+
+ if ( rc <= 0 ) {
+ fprintf(stderr, "inet_pton failed during ipaddress coneversion\n");
+ rc = -1;
+ break;
+ }
+
+ rc = sscanf(host_config.prefix.c_str(),PREFIX_FORMAT,
+ (respptr->data+PREFIX_OFFSET));
+
+ if ( rc <= 0 ) {
+ fprintf(stderr, "sscanf failed during prefix extraction.\n");
+ rc = -1;
+ break;
+ }
+
+ rc = inet_pton(AF_INET,host_config.gateway.c_str(),
+ (respptr->data+GATEWAY_OFFSET));
+
+ if ( rc <= 0 ) {
+ fprintf(stderr, "inet_pton failed during gateway conversion.\n");
+ rc = -1;
+ break;
+ }
+
+ }while (0);
+
+ if ( rc ) {
+
+ //PetiBoot-Specific
+ //If sucess then copy the first 9 bytes to the data
+ //else set the respptr to 0
+
+ memcpy(respptr->data,net_conf_initial_bytes,
+ sizeof(net_conf_initial_bytes));
+
+#ifdef _IPMI_DEBUG_
+ printf ("\n===Printing the IPMI Formatted Data========\n");
+
+ for ( uint8_t pos = 0; pos<index; pos++ )
+ printf("%02x ", respptr->data[pos]);
+#endif
+
+ }else {
+
+ memset(respptr->data,0,SIZE_BOOT_OPTION);
+ }
+
+ return rc;
+}
+
+int setHostNetworkData(set_sys_boot_options_t * reqptr)
+{
+ std::string host_network_config;
+ char mac[SIZE_MAC] = {0};
+ char ipAddress[INET_ADDRSTRLEN] = {0};
+ char gateway[INET_ADDRSTRLEN] = {0};
+ char dhcp[SIZE_PREFIX] = {0};
+ char prefix[SIZE_PREFIX] = {0};
+ int rc = 0;
+ uint32_t zeroCookie=0;
+
+ //cookie starts from second byte
+ // version starts from sixth byte
+
+ do {
+
+ // cookie == 0x21 0x70 0x62 0x21
+ if ( memcmp(&(reqptr->data[COOKIE_OFFSET]),
+ (net_conf_initial_bytes+COOKIE_OFFSET),
+ SIZE_COOKIE) != 0 ) {
+ //cookie == 0
+ if ( memcmp(&(reqptr->data[COOKIE_OFFSET]),
+ &zeroCookie,
+ SIZE_COOKIE) == 0 ) {
+ rc = 0;
+ break;
+ }
+ //Invalid cookie
+ fprintf(stderr, "Invalid Cookie\n");
+ rc = -1;
+ break;
+ }
+ // vesion == 0x00 0x01
+ if ( memcmp(&(reqptr->data[VERSION_OFFSET]),
+ (net_conf_initial_bytes+VERSION_OFFSET),
+ SIZE_VERSION) != 0 ) {
+
+ fprintf(stderr, "Invalid Version\n");
+ rc = -1;
+ break;
+ }
+
+ snprintf(mac, SIZE_MAC, MAC_ADDRESS_FORMAT,
+ reqptr->data[MAC_OFFSET],
+ reqptr->data[MAC_OFFSET+1],
+ reqptr->data[MAC_OFFSET+2],
+ reqptr->data[MAC_OFFSET+3],
+ reqptr->data[MAC_OFFSET+4],
+ reqptr->data[MAC_OFFSET+5]);
+
+ snprintf(dhcp,SIZE_PREFIX, ADDR_TYPE_FORMAT, reqptr->data[ADDRTYPE_OFFSET]);
+ //Validating the address type which could be
+ //either static or dynamic
+ if( *(reqptr->data+ADDRTYPE_OFFSET) > 1 ) {
+
+ fprintf(stderr, "Invalid Address Type\n");
+ rc = -1;
+ break;
+
+ }
+
+ snprintf(ipAddress, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT,
+ reqptr->data[IPADDR_OFFSET], reqptr->data[IPADDR_OFFSET+1],
+ reqptr->data[IPADDR_OFFSET+2], reqptr->data[IPADDR_OFFSET+3]);
+
+ //validating prefix
+ if ( *(reqptr->data+PREFIX_OFFSET) > (uint8_t)MAX_PREFIX_VALUE ) {
+
+ fprintf(stderr, "Invalid Prefix\n");
+ rc = -1;
+ break;
+ }
+
+ snprintf(prefix,SIZE_PREFIX,PREFIX_FORMAT, reqptr->data[PREFIX_OFFSET]);
+
+ snprintf(gateway, INET_ADDRSTRLEN,IP_ADDRESS_FORMAT,
+ reqptr->data[GATEWAY_OFFSET], reqptr->data[GATEWAY_OFFSET+1],
+ reqptr->data[GATEWAY_OFFSET+2], reqptr->data[GATEWAY_OFFSET+3]);
+
+
+ }while(0);
+
+ if( !rc )
+ {
+ //Cookie == 0 or it is a valid cookie
+ host_network_config += "ipaddress="+std::string(ipAddress)+",prefix="+
+ std::string(prefix)+",gateway="+std::string(gateway)+
+ ",mac="+std::string(mac)+",addr_type="+std::string(dhcp);
+
+ printf ("Network configuration changed: %s\n",host_network_config.c_str());
+
+ rc = dbus_set_property("network_config",host_network_config.c_str());
+
+ if ( rc < 0 ) {
+ fprintf(stderr, "Dbus set property(network_config)\
+ failed for set_sys_boot_options.\n");
+ rc = -1;
+ }
+
+ }
+ return rc;
+}
+
ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -326,14 +650,15 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
resp->parm = 5;
resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
- *data_len = sizeof(*resp);
/*
* Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
* This is the only parameter used by petitboot.
*/
- if (reqptr->parameter == 5) {
+ if ( reqptr->parameter == static_cast<uint8_t>
+ ( BootOptionParameter::BOOT_FLAGS )) {
+ *data_len = static_cast<uint8_t>(BootOptionResponseSize::BOOT_FLAGS);
/* Get the boot device */
int r = dbus_get_property("boot_flags",&p);
@@ -364,7 +689,7 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
} else {
- printf("BootPolicy is[%s]", p);
+ printf("BootPolicy is[%s]", p);
resp->data[0] = (strncmp(p,"ONETIME",strlen("ONETIME"))==0) ?
SET_PARM_BOOT_FLAGS_VALID_ONE_TIME:
SET_PARM_BOOT_FLAGS_VALID_PERMANENT;
@@ -373,13 +698,36 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
}
- } else {
+ } else if ( reqptr->parameter == static_cast<uint8_t>
+ ( BootOptionParameter::OPAL_NETWORK_SETTINGS )) {
+
+ *data_len = static_cast<uint8_t>(BootOptionResponseSize::OPAL_NETWORK_SETTINGS);
+
+ resp->parm = static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS);
+
+ int ret = getHostNetworkData(resp);
+
+ if (ret < 0) {
+
+ fprintf(stderr, "getHostNetworkData failed for get_sys_boot_options.\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+
+ }else
+ rc = IPMI_CC_OK;
+ }
+
+ else {
fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
}
if (p)
free(p);
+ if (rc == IPMI_CC_OK)
+ {
+ *data_len += 2;
+ }
+
return rc;
}
@@ -391,11 +739,10 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
{
ipmi_ret_t rc = IPMI_CC_OK;
char *s;
-
- printf("IPMI SET_SYS_BOOT_OPTIONS\n");
-
set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
+ printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n",reqptr->parameter);
+
// This IPMI command does not have any resposne data
*data_len = 0;
@@ -403,7 +750,8 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
* Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
* This is the only parameter used by petitboot.
*/
- if (reqptr->parameter == 5) {
+
+ if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) {
s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
@@ -421,12 +769,12 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
rc = IPMI_CC_UNSPECIFIED_ERROR;
}
}
-
+
/* setting the boot policy */
s = (char *)(((reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) ==
- SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
+ SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
- printf ( "\nBoot Policy is %s",s);
+ printf ( "\nBoot Policy is %s",s);
int r = dbus_set_property("boot_policy",s);
if (r < 0) {
@@ -434,7 +782,16 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
rc = IPMI_CC_UNSPECIFIED_ERROR;
}
- } else {
+ } else if (reqptr->parameter ==
+ (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) {
+
+ int ret = setHostNetworkData(reqptr);
+ if (ret < 0) {
+ fprintf(stderr, "setHostNetworkData failed for set_sys_boot_options.\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+ else {
fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
rc = IPMI_CC_PARM_NOT_SUPPORTED;
}
OpenPOWER on IntegriCloud