Index: trunk/src/VBox/Runtime/common/net/netaddrstr2.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/net/netaddrstr2.cpp	(revision 87471)
+++ trunk/src/VBox/Runtime/common/net/netaddrstr2.cpp	(revision 87524)
@@ -679,2 +679,49 @@
 }
 RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv6);
+
+
+RTDECL(int) RTNetStrToIPv6Cidr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, int *piPrefix)
+{
+    RTNETADDRIPV6 Addr;
+    uint8_t u8Prefix;
+    char *pszZone, *pszNext;
+    int rc;
+
+    AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(piPrefix, VERR_INVALID_PARAMETER);
+
+    pcszAddr = RTStrStripL(pcszAddr);
+    rc = rtNetStrToIPv6AddrEx(pcszAddr, &Addr, &pszZone, &pszNext);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    RT_NOREF(pszZone);
+
+    /*
+     * If the prefix is missing, treat is as exact (/128) address
+     * specification.
+     */
+    if (*pszNext == '\0' || rc == VWRN_TRAILING_SPACES)
+    {
+        *pAddr = Addr;
+        *piPrefix = 128;
+        return VINF_SUCCESS;
+    }
+
+    if (*pszNext != '/')
+        return VERR_INVALID_PARAMETER;
+
+    ++pszNext;
+    rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &u8Prefix);
+    if (RT_FAILURE(rc) || rc == VWRN_TRAILING_CHARS)
+        return VERR_INVALID_PARAMETER;
+
+    if (u8Prefix == 0 || u8Prefix > 128)
+        return VERR_INVALID_PARAMETER;
+
+    *pAddr = Addr;
+    *piPrefix = u8Prefix;
+    return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTNetStrToIPv6Cidr);
Index: trunk/src/VBox/Runtime/testcase/tstRTNetIPv6.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstRTNetIPv6.cpp	(revision 87471)
+++ trunk/src/VBox/Runtime/testcase/tstRTNetIPv6.cpp	(revision 87524)
@@ -73,4 +73,39 @@
 
 
+#define CHECKCIDR(String, rcExpected, u32_0, u32_1, u32_2, u32_3, iExpectedPrefix)    \
+    do {                                                                \
+        RTNETADDRIPV6 Addr;                                             \
+        uint32_t ExpectedAddr[4] = {                                    \
+            RT_H2N_U32_C(u32_0), RT_H2N_U32_C(u32_1),                   \
+            RT_H2N_U32_C(u32_2), RT_H2N_U32_C(u32_3)                    \
+        };                                                              \
+        int iPrefix;                                                    \
+                                                                        \
+        int rc2 = RTNetStrToIPv6Cidr(String, &Addr, &iPrefix);          \
+        if ((rcExpected) && !rc2)                                       \
+        {                                                               \
+            RTTestIFailed("at line %d: '%s': expected %Rrc got %Rrc\n", \
+                          __LINE__, String, (rcExpected), rc2);         \
+        }                                                               \
+        else if (   (rcExpected) != rc2                                 \
+                 || (   rc2 == VINF_SUCCESS                             \
+                     && (   memcmp(ExpectedAddr, &Addr, sizeof(Addr)) != 0 \
+                         || iExpectedPrefix != iPrefix)))               \
+        {                                                               \
+            RTTestIFailed("at line %d: '%s': expected %Rrc got %Rrc,"   \
+                          " expected address %RTnaipv6/%d got %RTnaipv6/%d\n",\
+                          __LINE__, String, rcExpected, rc2,            \
+                          ExpectedAddr, iExpectedPrefix,                \
+                          &Addr, iPrefix);                              \
+        }                                                               \
+    } while (0)
+
+#define GOODCIDR(String, u32_0, u32_1, u32_2, u32_3, iExpectedPrefix) \
+    CHECKCIDR(String, VINF_SUCCESS, u32_0, u32_1, u32_2, u32_3, iExpectedPrefix)
+
+#define BADCIDR(String) \
+    CHECKCIDR(String, VERR_INVALID_PARAMETER, 0, 0, 0, 0, 0)
+
+
 #define CHECKANY(String, fExpected)                                     \
     do {                                                                \
@@ -204,4 +239,18 @@
     GOODADDR(" ff01::1%net1.1\t", 0xff010000, 0, 0, 1);
 
+    /* just some light testing */
+    GOODCIDR("1:2:3:4:5:6:7:8", 0x00010002, 0x00030004, 0x00050006, 0x00070008, 128);
+    GOODCIDR("1:2:3:4::/64",    0x00010002, 0x00030004,          0,          0,  64);
+    GOODCIDR(" 1:2:3:4::/64 ",  0x00010002, 0x00030004,          0,          0,  64);
+
+    /* we currently ignore the zone */
+    GOODCIDR("1:2:3:4::%if/64", 0x00010002, 0x00030004,          0,          0,  64);
+
+    BADCIDR("1:2:3:4:: 64");
+    BADCIDR("1:2:3:4::/64x");
+    BADCIDR("1:2:3:4::/0");
+    BADCIDR("1:2:3:4::/-1");
+    BADCIDR("1:2:3:4::/129");
+    BADCIDR("1:2:3:4::/256");
 
     IS_ANY("::");
