Add XFRM-I support to XfrmController

This patch adds support for creating and managing XFRM interfaces,
adding xfrm_if_id parameters to all relevant netlink calls.

This is part of a patch set to enable XFRM-I support, with automatic
fallbacks to VTI in XfrmController (2/3)

Bug: 77856928
Test: Xfrm, Binder tests updated, passing
Change-Id: I09869e6a0000384c9c4d0aef1de4d5434c33374a
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 18181e0..297a4b0 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -469,7 +469,7 @@
 
     XfrmSaInfo saInfo{};
     netdutils::Status ret = fillXfrmCommonInfo(sourceAddress, destinationAddress, INVALID_SPI, 0, 0,
-                                               transformId, &saInfo);
+                                               transformId, 0, &saInfo);
     if (!isOk(ret)) {
         return ret;
     }
@@ -497,12 +497,13 @@
 }
 
 netdutils::Status XfrmController::ipSecAddSecurityAssociation(
-    int32_t transformId, int32_t mode, const std::string& sourceAddress,
-    const std::string& destinationAddress, int32_t underlyingNetId, int32_t spi, int32_t markValue,
-    int32_t markMask, const std::string& authAlgo, const std::vector<uint8_t>& authKey,
-    int32_t authTruncBits, const std::string& cryptAlgo, const std::vector<uint8_t>& cryptKey,
-    int32_t cryptTruncBits, const std::string& aeadAlgo, const std::vector<uint8_t>& aeadKey,
-    int32_t aeadIcvBits, int32_t encapType, int32_t encapLocalPort, int32_t encapRemotePort) {
+        int32_t transformId, int32_t mode, const std::string& sourceAddress,
+        const std::string& destinationAddress, int32_t underlyingNetId, int32_t spi,
+        int32_t markValue, int32_t markMask, const std::string& authAlgo,
+        const std::vector<uint8_t>& authKey, int32_t authTruncBits, const std::string& cryptAlgo,
+        const std::vector<uint8_t>& cryptKey, int32_t cryptTruncBits, const std::string& aeadAlgo,
+        const std::vector<uint8_t>& aeadKey, int32_t aeadIcvBits, int32_t encapType,
+        int32_t encapLocalPort, int32_t encapRemotePort, int32_t xfrmInterfaceId) {
     ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
     ALOGD("transformId=%d", transformId);
     ALOGD("mode=%d", mode);
@@ -521,10 +522,11 @@
     ALOGD("encapType=%d", encapType);
     ALOGD("encapLocalPort=%d", encapLocalPort);
     ALOGD("encapRemotePort=%d", encapRemotePort);
+    ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
 
     XfrmSaInfo saInfo{};
     netdutils::Status ret = fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, markValue,
-                                               markMask, transformId, &saInfo);
+                                               markMask, transformId, xfrmInterfaceId, &saInfo);
     if (!isOk(ret)) {
         return ret;
     }
@@ -583,8 +585,9 @@
 }
 
 netdutils::Status XfrmController::ipSecDeleteSecurityAssociation(
-    int32_t transformId, const std::string& sourceAddress, const std::string& destinationAddress,
-    int32_t spi, int32_t markValue, int32_t markMask) {
+        int32_t transformId, const std::string& sourceAddress,
+        const std::string& destinationAddress, int32_t spi, int32_t markValue, int32_t markMask,
+        int32_t xfrmInterfaceId) {
     ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
     ALOGD("transformId=%d", transformId);
     ALOGD("sourceAddress=%s", sourceAddress.c_str());
@@ -592,10 +595,11 @@
     ALOGD("spi=%0.8x", spi);
     ALOGD("markValue=%x", markValue);
     ALOGD("markMask=%x", markMask);
+    ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
 
     XfrmSaInfo saInfo{};
     netdutils::Status ret = fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, markValue,
-                                               markMask, transformId, &saInfo);
+                                               markMask, transformId, xfrmInterfaceId, &saInfo);
     if (!isOk(ret)) {
         return ret;
     }
@@ -619,6 +623,7 @@
                                                      const std::string& destinationAddress,
                                                      int32_t spi, int32_t markValue,
                                                      int32_t markMask, int32_t transformId,
+                                                     int32_t xfrmInterfaceId,
                                                      XfrmCommonInfo* info) {
     // Use the addresses to determine the address family and do validation
     xfrm_address_t sourceXfrmAddr{}, destXfrmAddr{};
@@ -642,16 +647,18 @@
     info->dstAddr = destXfrmAddr;
     info->srcAddr = sourceXfrmAddr;
 
-    return fillXfrmCommonInfo(spi, markValue, markMask, transformId, info);
+    return fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId, info);
 }
 
 netdutils::Status XfrmController::fillXfrmCommonInfo(int32_t spi, int32_t markValue,
                                                      int32_t markMask, int32_t transformId,
+                                                     int32_t xfrmInterfaceId,
                                                      XfrmCommonInfo* info) {
     info->transformId = transformId;
     info->spi = htonl(spi);
     info->mark.v = markValue;
     info->mark.m = markMask;
+    info->xfrm_if_id = xfrmInterfaceId;
 
     return netdutils::status::ok;
 }
@@ -674,8 +681,8 @@
     struct sockaddr_storage saddr = ret.value();
 
     XfrmSpInfo spInfo{};
-    netdutils::Status status =
-            fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, 0, 0, transformId, &spInfo);
+    netdutils::Status status = fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, 0, 0,
+                                                  transformId, 0, &spInfo);
     if (!isOk(status)) {
         ALOGE("Couldn't build SA ID %s", __FUNCTION__);
         return status;
@@ -760,38 +767,37 @@
     return status;
 }
 
-netdutils::Status XfrmController::ipSecAddSecurityPolicy(int32_t transformId, int32_t selAddrFamily,
-                                                         int32_t direction,
-                                                         const std::string& tmplSrcAddress,
-                                                         const std::string& tmplDstAddress,
-                                                         int32_t spi, int32_t markValue,
-                                                         int32_t markMask) {
+netdutils::Status XfrmController::ipSecAddSecurityPolicy(
+        int32_t transformId, int32_t selAddrFamily, int32_t direction,
+        const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi,
+        int32_t markValue, int32_t markMask, int32_t xfrmInterfaceId) {
     return processSecurityPolicy(transformId, selAddrFamily, direction, tmplSrcAddress,
-                                 tmplDstAddress, spi, markValue, markMask, XFRM_MSG_NEWPOLICY);
+                                 tmplDstAddress, spi, markValue, markMask, xfrmInterfaceId,
+                                 XFRM_MSG_NEWPOLICY);
 }
 
 netdutils::Status XfrmController::ipSecUpdateSecurityPolicy(
         int32_t transformId, int32_t selAddrFamily, int32_t direction,
         const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi,
-        int32_t markValue, int32_t markMask) {
+        int32_t markValue, int32_t markMask, int32_t xfrmInterfaceId) {
     return processSecurityPolicy(transformId, selAddrFamily, direction, tmplSrcAddress,
-                                 tmplDstAddress, spi, markValue, markMask, XFRM_MSG_UPDPOLICY);
+                                 tmplDstAddress, spi, markValue, markMask, xfrmInterfaceId,
+                                 XFRM_MSG_UPDPOLICY);
 }
 
 netdutils::Status XfrmController::ipSecDeleteSecurityPolicy(int32_t transformId,
                                                             int32_t selAddrFamily,
                                                             int32_t direction, int32_t markValue,
-                                                            int32_t markMask) {
+                                                            int32_t markMask,
+                                                            int32_t xfrmInterfaceId) {
     return processSecurityPolicy(transformId, selAddrFamily, direction, "", "", 0, markValue,
-                                 markMask, XFRM_MSG_DELPOLICY);
+                                 markMask, xfrmInterfaceId, XFRM_MSG_DELPOLICY);
 }
 
-netdutils::Status XfrmController::processSecurityPolicy(int32_t transformId, int32_t selAddrFamily,
-                                                        int32_t direction,
-                                                        const std::string& tmplSrcAddress,
-                                                        const std::string& tmplDstAddress,
-                                                        int32_t spi, int32_t markValue,
-                                                        int32_t markMask, int32_t msgType) {
+netdutils::Status XfrmController::processSecurityPolicy(
+        int32_t transformId, int32_t selAddrFamily, int32_t direction,
+        const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi,
+        int32_t markValue, int32_t markMask, int32_t xfrmInterfaceId, int32_t msgType) {
     ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
     ALOGD("selAddrFamily=%s", selAddrFamily == AF_INET6 ? "AF_INET6" : "AF_INET");
     ALOGD("transformId=%d", transformId);
@@ -802,6 +808,7 @@
     ALOGD("markValue=%d", markValue);
     ALOGD("markMask=%d", markMask);
     ALOGD("msgType=%d", msgType);
+    ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
 
     XfrmSpInfo spInfo{};
     spInfo.mode = XfrmMode::TUNNEL;
@@ -816,12 +823,13 @@
     spInfo.selAddrFamily = selAddrFamily;
 
     if (msgType == XFRM_MSG_DELPOLICY) {
-        RETURN_IF_NOT_OK(fillXfrmCommonInfo(spi, markValue, markMask, transformId, &spInfo));
+        RETURN_IF_NOT_OK(fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId,
+                                            &spInfo));
 
         return deleteTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction));
     } else {
         RETURN_IF_NOT_OK(fillXfrmCommonInfo(tmplSrcAddress, tmplDstAddress, spi, markValue,
-                                            markMask, transformId, &spInfo));
+                                            markMask, transformId, xfrmInterfaceId, &spInfo));
 
         return updateTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction),
                                               msgType);
@@ -843,6 +851,7 @@
     nlattr_xfrm_mark xfrmmark{};
     nlattr_xfrm_output_mark xfrmoutputmark{};
     nlattr_encap_tmpl encap{};
+    nlattr_xfrm_interface_id xfrm_if_id{};
 
     enum {
         NLMSG_HDR,
@@ -860,24 +869,28 @@
         OUTPUT_MARK_PAD,
         ENCAP,
         ENCAP_PAD,
+        INTF_ID,
+        INTF_ID_PAD,
     };
 
     std::vector<iovec> iov = {
-        {nullptr, 0},            // reserved for the eventual addition of a NLMSG_HDR
-        {&usersa, 0},         // main usersa_info struct
-        {kPadBytes, 0},       // up to NLMSG_ALIGNTO pad bytes of padding
-        {&crypt, 0},          // adjust size if crypt algo is present
-        {kPadBytes, 0},       // up to NLATTR_ALIGNTO pad bytes
-        {&auth, 0},           // adjust size if auth algo is present
-        {kPadBytes, 0},       // up to NLATTR_ALIGNTO pad bytes
-        {&aead, 0},           // adjust size if aead algo is present
-        {kPadBytes, 0},       // up to NLATTR_ALIGNTO pad bytes
-        {&xfrmmark, 0},       // adjust size if xfrm mark is present
-        {kPadBytes, 0},       // up to NLATTR_ALIGNTO pad bytes
-        {&xfrmoutputmark, 0}, // adjust size if xfrm output mark is present
-        {kPadBytes, 0},       // up to NLATTR_ALIGNTO pad bytes
-        {&encap, 0},          // adjust size if encapsulating
-        {kPadBytes, 0},       // up to NLATTR_ALIGNTO pad bytes
+            {nullptr, 0},          // reserved for the eventual addition of a NLMSG_HDR
+            {&usersa, 0},          // main usersa_info struct
+            {kPadBytes, 0},        // up to NLMSG_ALIGNTO pad bytes of padding
+            {&crypt, 0},           // adjust size if crypt algo is present
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
+            {&auth, 0},            // adjust size if auth algo is present
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
+            {&aead, 0},            // adjust size if aead algo is present
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
+            {&xfrmmark, 0},        // adjust size if xfrm mark is present
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
+            {&xfrmoutputmark, 0},  // adjust size if xfrm output mark is present
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
+            {&encap, 0},           // adjust size if encapsulating
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
+            {&xfrm_if_id, 0},      // adjust size if interface ID is present
+            {kPadBytes, 0},        // up to NLATTR_ALIGNTO pad bytes
     };
 
     if (!record.aead.name.empty() && (!record.auth.name.empty() || !record.crypt.name.empty())) {
@@ -891,6 +904,13 @@
         return netdutils::statusFromErrno(EINVAL, "Key length invalid; exceeds MAX_KEY_LENGTH");
     }
 
+    if (record.mode != XfrmMode::TUNNEL && record.xfrm_if_id != 0) {
+        // TODO: Also throw errors if output mark or mark supplied
+        return netdutils::statusFromErrno(EINVAL,
+                                          "xfrm_if_id parameter invalid for non "
+                                          "tunnel-mode transform");
+    }
+
     int len;
     len = iov[USERSA].iov_len = fillUserSaInfo(record, &usersa);
     iov[USERSA_PAD].iov_len = NLMSG_ALIGN(len) - len;
@@ -913,6 +933,9 @@
     len = iov[ENCAP].iov_len = fillNlAttrXfrmEncapTmpl(record, &encap);
     iov[ENCAP_PAD].iov_len = NLA_ALIGN(len) - len;
 
+    len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
+    iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
+
     return sock.sendMessage(XFRM_MSG_UPDSA, NETLINK_REQUEST_FLAGS, 0, &iov);
 }
 
@@ -1026,15 +1049,18 @@
                                                             const XfrmSocket& sock) {
     xfrm_usersa_id said{};
     nlattr_xfrm_mark xfrmmark{};
+    nlattr_xfrm_interface_id xfrm_if_id{};
 
-    enum { NLMSG_HDR, USERSAID, USERSAID_PAD, MARK, MARK_PAD };
+    enum { NLMSG_HDR, USERSAID, USERSAID_PAD, MARK, MARK_PAD, INTF_ID, INTF_ID_PAD };
 
     std::vector<iovec> iov = {
-        {nullptr, 0},      // reserved for the eventual addition of a NLMSG_HDR
-        {&said, 0},     // main usersa_info struct
-        {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
-        {&xfrmmark, 0}, // adjust size if xfrm mark is present
-        {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+            {nullptr, 0},      // reserved for the eventual addition of a NLMSG_HDR
+            {&said, 0},        // main usersa_info struct
+            {kPadBytes, 0},    // up to NLMSG_ALIGNTO pad bytes of padding
+            {&xfrmmark, 0},    // adjust size if xfrm mark is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
+            {&xfrm_if_id, 0},  // adjust size if interface ID is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
     };
 
     int len;
@@ -1044,6 +1070,9 @@
     len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
     iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
 
+    len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
+    iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
+
     return sock.sendMessage(XFRM_MSG_DELSA, NETLINK_REQUEST_FLAGS, 0, &iov);
 }
 
@@ -1102,6 +1131,7 @@
     xfrm_userpolicy_info userpolicy{};
     nlattr_user_tmpl usertmpl{};
     nlattr_xfrm_mark xfrmmark{};
+    nlattr_xfrm_interface_id xfrm_if_id{};
 
     enum {
         NLMSG_HDR,
@@ -1111,16 +1141,20 @@
         USERTMPL_PAD,
         MARK,
         MARK_PAD,
+        INTF_ID,
+        INTF_ID_PAD,
     };
 
     std::vector<iovec> iov = {
-        {nullptr, 0},        // reserved for the eventual addition of a NLMSG_HDR
-        {&userpolicy, 0}, // main xfrm_userpolicy_info struct
-        {kPadBytes, 0},   // up to NLMSG_ALIGNTO pad bytes of padding
-        {&usertmpl, 0},   // adjust size if xfrm_user_tmpl struct is present
-        {kPadBytes, 0},   // up to NLATTR_ALIGNTO pad bytes
-        {&xfrmmark, 0},   // adjust size if xfrm mark is present
-        {kPadBytes, 0},   // up to NLATTR_ALIGNTO pad bytes
+            {nullptr, 0},      // reserved for the eventual addition of a NLMSG_HDR
+            {&userpolicy, 0},  // main xfrm_userpolicy_info struct
+            {kPadBytes, 0},    // up to NLMSG_ALIGNTO pad bytes of padding
+            {&usertmpl, 0},    // adjust size if xfrm_user_tmpl struct is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
+            {&xfrmmark, 0},    // adjust size if xfrm mark is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
+            {&xfrm_if_id, 0},  // adjust size if interface ID is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
     };
 
     int len;
@@ -1133,6 +1167,9 @@
     len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
     iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
 
+    len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
+    iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
+
     return sock.sendMessage(msgType, NETLINK_REQUEST_FLAGS, 0, &iov);
 }
 
@@ -1141,6 +1178,7 @@
                                                                  XfrmDirection direction) {
     xfrm_userpolicy_id policyid{};
     nlattr_xfrm_mark xfrmmark{};
+    nlattr_xfrm_interface_id xfrm_if_id{};
 
     enum {
         NLMSG_HDR,
@@ -1148,14 +1186,18 @@
         USERPOLICYID_PAD,
         MARK,
         MARK_PAD,
+        INTF_ID,
+        INTF_ID_PAD,
     };
 
     std::vector<iovec> iov = {
-        {nullptr, 0},      // reserved for the eventual addition of a NLMSG_HDR
-        {&policyid, 0}, // main xfrm_userpolicy_id struct
-        {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
-        {&xfrmmark, 0}, // adjust size if xfrm mark is present
-        {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+            {nullptr, 0},      // reserved for the eventual addition of a NLMSG_HDR
+            {&policyid, 0},    // main xfrm_userpolicy_id struct
+            {kPadBytes, 0},    // up to NLMSG_ALIGNTO pad bytes of padding
+            {&xfrmmark, 0},    // adjust size if xfrm mark is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
+            {&xfrm_if_id, 0},  // adjust size if interface ID is present
+            {kPadBytes, 0},    // up to NLATTR_ALIGNTO pad bytes
     };
 
     int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, direction, &policyid);
@@ -1164,6 +1206,9 @@
     len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
     iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
 
+    len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
+    iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
+
     return sock.sendMessage(XFRM_MSG_DELPOLICY, NETLINK_REQUEST_FLAGS, 0, &iov);
 }
 
@@ -1268,13 +1313,14 @@
                                                           const std::string& localAddress,
                                                           const std::string& remoteAddress,
                                                           int32_t ikey, int32_t okey,
-                                                          bool isUpdate) {
+                                                          int32_t interfaceId, bool isUpdate) {
     ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
     ALOGD("deviceName=%s", deviceName.c_str());
     ALOGD("localAddress=%s", localAddress.c_str());
     ALOGD("remoteAddress=%s", remoteAddress.c_str());
     ALOGD("ikey=%0.8x", ikey);
     ALOGD("okey=%0.8x", okey);
+    ALOGD("interfaceId=%0.8x", interfaceId);
     ALOGD("isUpdate=%d", isUpdate);
 
     uint16_t flags = isUpdate ? NETLINK_REQUEST_FLAGS : NETLINK_ROUTE_CREATE_FLAGS;