Add IPV6 handling for host network settings

Change-Id: I41a35d274476f69681c2516b84900f0e0c358181
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/chassishandler.cpp b/chassishandler.cpp
index 0b991fd..506d628 100644
--- a/chassishandler.cpp
+++ b/chassishandler.cpp
@@ -44,17 +44,19 @@
 constexpr auto   IP_ADDRESS_FORMAT = "%d.%d.%d.%d";
 constexpr auto   PREFIX_FORMAT = "%hhd";
 constexpr auto   ADDR_TYPE_FORMAT = "%hhx";
+constexpr auto   IPV4_ADDRESS_SIZE_BYTE = 4;
+constexpr auto   IPV6_ADDRESS_SIZE_BYTE = 16;
+
 //PetiBoot-Specific
-static constexpr uint8_t net_conf_initial_bytes[] = {0x80,0x21, 0x70 ,0x62 ,0x21,
-        0x00 ,0x01 ,0x06 ,0x04};
+static constexpr uint8_t net_conf_initial_bytes[] = {0x80, 0x21, 0x70, 0x62,
+        0x21, 0x00, 0x01, 0x06};
 
 static constexpr size_t COOKIE_OFFSET = 1;
 static constexpr size_t VERSION_OFFSET = 5;
+static constexpr size_t ADDR_SIZE_OFFSET = 8;
 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;
 
 
 void register_netfn_chassis_functions() __attribute__((constructor));
@@ -65,7 +67,6 @@
 const char *settings_intf_name    =  "org.freedesktop.DBus.Properties";
 const char *host_intf_name        =  "org.openbmc.settings.Host";
 
-
 constexpr auto MAPPER_BUS_NAME = "xyz.openbmc_project.ObjectMapper";
 constexpr auto MAPPER_OBJ = "/xyz/openbmc_project/object_mapper";
 constexpr auto MAPPER_INTF = "xyz.openbmc_project.ObjectMapper";
@@ -452,6 +453,7 @@
 {
     ipmi::PropertyMap properties;
     int rc = 0;
+    uint8_t addrSize = IPV4_ADDRESS_SIZE_BYTE;
 
     try
     {
@@ -485,21 +487,36 @@
 
         respptr->data[MAC_OFFSET + 6] = 0x00;
 
-        uint8_t addrType = (properties["Origin"].get<std::string>() ==
+        uint8_t addrOrigin = (properties["Origin"].get<std::string>() ==
             "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ? 1 : 0;
 
-        memcpy(respptr->data + ADDRTYPE_OFFSET, &addrType, sizeof(addrType));
+        memcpy(respptr->data + ADDRTYPE_OFFSET, &addrOrigin,
+               sizeof(addrOrigin));
+
+        uint8_t addressFamily = (properties["Type"].get<std::string>() ==
+            "xyz.openbmc_project.Network.IP.Protocol.IPv4") ?
+                AF_INET : AF_INET6;
+
+        addrSize = (addressFamily == AF_INET) ? IPV4_ADDRESS_SIZE_BYTE :
+                                                IPV6_ADDRESS_SIZE_BYTE;
 
         // ipaddress and gateway would be in IPv4 format
 
-        inet_pton(AF_INET, properties["Address"].get<std::string>().c_str(),
+        inet_pton(addressFamily,
+                  properties["Address"].get<std::string>().c_str(),
                   (respptr->data + IPADDR_OFFSET));
 
         uint8_t prefix = properties["PrefixLength"].get<uint8_t>();
-        memcpy(respptr->data + PREFIX_OFFSET, &prefix, sizeof(prefix));
 
-        inet_pton(AF_INET, properties["Gateway"].get<std::string>().c_str(),
-                  (respptr->data + GATEWAY_OFFSET));
+        uint8_t prefixOffset = IPADDR_OFFSET + addrSize;
+
+        memcpy(respptr->data + prefixOffset, &prefix, sizeof(prefix));
+
+        uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix));
+
+        inet_pton(addressFamily,
+                  properties["Gateway"].get<std::string>().c_str(),
+                  (respptr->data + gatewayOffset));
 
     }
     catch (InternalFailure& e)
@@ -512,11 +529,11 @@
 
     //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));
 
+    memcpy(respptr->data + ADDR_SIZE_OFFSET, &addrSize, sizeof(addrSize));
+
 #ifdef _IPMI_DEBUG_
     printf("\n===Printing the IPMI Formatted Data========\n");
 
@@ -526,22 +543,68 @@
     }
 #endif
 
-
     return rc;
 }
 
+/** @brief convert IPv4 and IPv6 addresses from binary to text form.
+ *  @param[in] family - IPv4/Ipv6
+ *  @param[in] data - req data pointer.
+ *  @param[in] offset - offset in the data.
+ *  @param[in] addrSize - size of the data which needs to be read from offset.
+ *  @returns address in text form.
+ */
+
+std::string getAddrStr(uint8_t family, uint8_t* data,
+                       uint8_t offset, uint8_t addrSize)
+{
+    char ipAddr[INET6_ADDRSTRLEN] = {};
+
+    switch(family)
+    {
+        case AF_INET:
+        {
+            struct sockaddr_in addr4 {};
+            memcpy(&addr4.sin_addr.s_addr, &data[offset], addrSize);
+
+            inet_ntop(AF_INET, &addr4.sin_addr,
+                      ipAddr, INET_ADDRSTRLEN);
+
+            break;
+        }
+        case AF_INET6:
+        {
+            struct sockaddr_in6 addr6 {};
+            memcpy(&addr6.sin6_addr.s6_addr, &data[offset], addrSize);
+
+            inet_ntop(AF_INET6, &addr6.sin6_addr,
+                      ipAddr, INET6_ADDRSTRLEN);
+
+            break;
+        }
+        default:
+        {
+            return {};
+        }
+    }
+
+    return ipAddr;
+}
+
 int setHostNetworkData(set_sys_boot_options_t* reqptr)
 {
     using namespace std::string_literals;
     std::string host_network_config;
     char mac[SIZE_MAC] = {0};
-    char ipAddress[INET_ADDRSTRLEN] = {0};
-    char gateway[INET_ADDRSTRLEN] = {0};
-    char dhcp {0};
+    std::string ipAddress, gateway;
+    char addrOrigin {0};
+    uint8_t addrSize {0};
     std::string addressOrigin =
-        "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
+        "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
+    std::string addressType =
+        "xyz.openbmc_project.Network.IP.Protocol.IPv4";
     uint8_t prefix {0};
     uint32_t zeroCookie = 0;
+    uint8_t family = AF_INET;
 
     //cookie starts from second byte
     // version starts from sixth byte
@@ -586,30 +649,33 @@
                      reqptr->data[MAC_OFFSET + 4],
                      reqptr->data[MAC_OFFSET + 5]);
 
-            memcpy(&dhcp, &(reqptr->data[ADDRTYPE_OFFSET]),
-                   sizeof(decltype(dhcp)));
+            memcpy(&addrOrigin, &(reqptr->data[ADDRTYPE_OFFSET]),
+                   sizeof(decltype(addrOrigin)));
 
-            if (dhcp)
+            if (addrOrigin)
             {
                 addressOrigin =
-                    "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
+                    "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
             }
 
-            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]);
+            // Get the address size
+            memcpy(&addrSize ,&reqptr->data[ADDR_SIZE_OFFSET], sizeof(addrSize));
 
+            uint8_t prefixOffset = IPADDR_OFFSET + addrSize;
 
-            memcpy(&prefix, &(reqptr->data[PREFIX_OFFSET]),
-                   sizeof(decltype(prefix)));
+            memcpy(&prefix, &(reqptr->data[prefixOffset]), sizeof(decltype(prefix)));
 
-            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]);
+            uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix));
+
+            if (addrSize != IPV4_ADDRESS_SIZE_BYTE)
+            {
+                addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
+                family = AF_INET6;
+            }
+
+            ipAddress = getAddrStr(family, reqptr->data, IPADDR_OFFSET, addrSize);
+            gateway = getAddrStr(family, reqptr->data, gatewayOffset, addrSize);
+
         } while(0);
 
         //Cookie == 0 or it is a valid cookie