summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Improved-IPv6-netmask-parsing.patch
blob: d0ba59ccd910e884e303b6a538f5c26219f3fb2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
From 371fb36e7a92b4139022b568a278e7624727bbaf Mon Sep 17 00:00:00 2001
From: Johnathan Mantey <johnathanx.mantey@intel.com>
Date: Tue, 26 Jan 2021 15:02:54 -0800
Subject: [PATCH] Improved IPv6 netmask parsing

The subnet mask parsing in toV6CIDR only worked for very well behaved
subnet strings. This became apparent after the BMC received a DHCP
assigned IPv6 address with an Address Prefix equal to /128. Any
netmask values trailing the final ":" character were ignored. In
addition it assumed all subnet entries would be submitted in shorthand
form.

The changes here handle mask values supplied following the final ":"
character. It also does more sanity checking on the incoming subnet
string.

Tested:
Supplied the function with the following test patterns, and confirmed
the function returns accurate address prefix values.
   ffff:ffff::
   ffff:fc00::
   ffff:0:0:0:0:0:0:0
   ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
   ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc
   ffff:0:0:6:0:0:0:0
   :
   ::

Change-Id: Ib2c73fe07a6a3f1c7a5f0e8f231dfef21badb3af
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>

%% original patch: 0004-Improved-IPv6-netmask-parsing.patch
---
 util.cpp | 67 ++++++++++++++++++++------------------------------------
 1 file changed, 24 insertions(+), 43 deletions(-)

diff --git a/util.cpp b/util.cpp
index 0c5dbff..c230221 100644
--- a/util.cpp
+++ b/util.cpp
@@ -37,59 +37,40 @@ namespace fs = std::filesystem;
 
 uint8_t toV6Cidr(const std::string& subnetMask)
 {
-    uint8_t pos = 0;
-    uint8_t prevPos = 0;
-    uint8_t cidr = 0;
-    uint16_t buff{};
-    do
+    struct in6_addr subnet;
+    int ret = inet_pton(AF_INET6, subnetMask.c_str(), &subnet);
+    if (ret != 1)
     {
-        // subnet mask look like ffff:ffff::
-        // or ffff:c000::
-        pos = subnetMask.find(":", prevPos);
-        if (pos == std::string::npos)
-        {
-            break;
-        }
-
-        auto str = subnetMask.substr(prevPos, (pos - prevPos));
-        prevPos = pos + 1;
+        log<level::ERR>("Invalid Mask",
+                        entry("SUBNETMASK=%s", subnetMask.c_str()));
+        return 0;
+    }
 
-        // String length is 0
-        if (!str.length())
-        {
-            return cidr;
-        }
-        // converts it into number.
-        if (sscanf(str.c_str(), "%hx", &buff) <= 0)
+    uint8_t cidr = 0;
+    bool zeroesFound = false;
+    int bitsSet, trailingZeroes;
+    for (int lv = 0; lv < 4; lv++)
+    {
+        subnet.s6_addr32[lv] = be32toh(subnet.s6_addr32[lv]);
+        bitsSet = __builtin_popcount(subnet.s6_addr32[lv]);
+        if (zeroesFound && bitsSet)
         {
             log<level::ERR>("Invalid Mask",
                             entry("SUBNETMASK=%s", subnetMask.c_str()));
-
             return 0;
         }
+        trailingZeroes = __builtin_ctz(subnet.s6_addr32[lv]);
+        zeroesFound |= trailingZeroes;
 
-        // convert the number into bitset
-        // and check for how many ones are there.
-        // if we don't have all the ones then make
-        // sure that all the ones should be left justify.
-
-        if (__builtin_popcount(buff) != 16)
+        if (bitsSet + trailingZeroes != 32)
         {
-            if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
-                __builtin_popcount(buff))
-            {
-                log<level::ERR>("Invalid Mask",
-                                entry("SUBNETMASK=%s", subnetMask.c_str()));
-
-                return 0;
-            }
-            cidr += __builtin_popcount(buff);
-            return cidr;
+            // There are '1' bits interspersed with '0' bits
+            log<level::ERR>("Invalid Mask",
+                            entry("SUBNETMASK=%s", subnetMask.c_str()));
+            return 0;
         }
-
-        cidr += 16;
-    } while (1);
-
+        cidr += bitsSet;
+    }
     return cidr;
 }
 } // anonymous namespace
-- 
2.26.2