supla-device
Loading...
Searching...
No Matches
netif_config.h
1// SPDX-FileCopyrightText: AC SOFTWARE SP. Z O.O.
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#ifndef SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
5#define SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
6
7#include <stddef.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <string.h>
11
12namespace Supla {
13
14enum class NetifIpMode : uint8_t {
15 DHCP = 0,
16 Static = 1,
17};
18
19constexpr uint8_t NETIF_CONFIG_BLOB_VERSION = 1;
20
21#pragma pack(push, 1)
23 uint8_t version = NETIF_CONFIG_BLOB_VERSION;
24 uint8_t ipMode = static_cast<uint8_t>(NetifIpMode::DHCP);
25 uint8_t reserved[2] = {};
26 uint32_t ip = 0; // Stored in network byte order.
27 uint32_t netmask = 0; // Stored in network byte order.
28 uint32_t gateway = 0; // Stored in network byte order.
29 uint32_t dns1 = 0; // Stored in network byte order.
30 uint32_t dns2 = 0; // Stored in network byte order.
31};
32#pragma pack(pop)
33
34static_assert(sizeof(NetifConfigBlob) == 24,
35 "Unexpected NetifConfigBlob size");
36
37inline bool parseUnsignedDecimal(const char* text,
38 uint32_t* result,
39 uint32_t maxValue) {
40 if (text == nullptr || result == nullptr || text[0] == '\0') {
41 return false;
42 }
43
44 uint32_t value = 0;
45 for (const char* ptr = text; *ptr; ++ptr) {
46 if (*ptr < '0' || *ptr > '9') {
47 return false;
48 }
49 uint32_t digit = static_cast<uint32_t>(*ptr - '0');
50 if (value > (UINT32_MAX - digit) / 10) {
51 return false;
52 }
53 value = value * 10 + digit;
54 if (value > maxValue) {
55 return false;
56 }
57 }
58
59 *result = value;
60 return true;
61}
62
63inline bool parseUnsignedDecimalRange(const char* begin,
64 const char* end,
65 uint32_t* result,
66 uint32_t maxValue) {
67 if (begin == nullptr || end == nullptr || result == nullptr ||
68 begin >= end) {
69 return false;
70 }
71
72 uint32_t value = 0;
73 for (const char* ptr = begin; ptr < end; ++ptr) {
74 if (*ptr < '0' || *ptr > '9') {
75 return false;
76 }
77 uint32_t digit = static_cast<uint32_t>(*ptr - '0');
78 if (value > (UINT32_MAX - digit) / 10) {
79 return false;
80 }
81 value = value * 10 + digit;
82 if (value > maxValue) {
83 return false;
84 }
85 }
86
87 *result = value;
88 return true;
89}
90
91inline bool parseIpv4Address(const char* text, uint32_t* result) {
92 if (text == nullptr || result == nullptr) {
93 return false;
94 }
95
96 uint32_t ip = 0;
97 const char* ptr = text;
98 for (int i = 0; i < 4; i++) {
99 const char* end = (i < 3) ? strchr(ptr, '.') : ptr + strlen(ptr);
100 if (end == nullptr) {
101 return false;
102 }
103 uint32_t value = 0;
104 if (!parseUnsignedDecimalRange(ptr, end, &value, 255)) {
105 return false;
106 }
107 if (i < 3) {
108 if (*end != '.') {
109 return false;
110 }
111 ptr = end + 1;
112 if (*ptr == '\0') {
113 return false;
114 }
115 } else if (*end != '\0') {
116 return false;
117 }
118 if (i == 0) {
119 ip = value << 24;
120 } else if (i == 1) {
121 ip |= value << 16;
122 } else if (i == 2) {
123 ip |= value << 8;
124 } else {
125 ip |= value;
126 }
127 }
128 *result = ip;
129 return true;
130}
131
132inline bool formatIpv4Address(uint32_t ip, char* out, size_t outSize) {
133 if (out == nullptr || outSize == 0) {
134 return false;
135 }
136
137 int size = snprintf(out,
138 outSize,
139 "%u.%u.%u.%u",
140 static_cast<unsigned int>((ip >> 24) & 0xFF),
141 static_cast<unsigned int>((ip >> 16) & 0xFF),
142 static_cast<unsigned int>((ip >> 8) & 0xFF),
143 static_cast<unsigned int>(ip & 0xFF));
144 return size > 0 && static_cast<size_t>(size) < outSize;
145}
146
147inline bool isValidNetmask(uint32_t netmask) {
148 if (netmask == 0) {
149 return false;
150 }
151
152 uint32_t inverted = ~netmask;
153 return (inverted & (inverted + 1)) == 0;
154}
155
156inline bool isValidIpv4Address(uint32_t ip) {
157 uint8_t firstOctet = static_cast<uint8_t>((ip >> 24) & 0xFF);
158 if (ip == 0 || ip == 0xFFFFFFFFu) {
159 return false;
160 }
161 if (firstOctet == 127) {
162 return false;
163 }
164 if (firstOctet >= 224) {
165 return false;
166 }
167 return true;
168}
169
170inline bool isSameSubnet(uint32_t ip, uint32_t netmask, uint32_t gateway) {
171 return (ip & netmask) == (gateway & netmask);
172}
173
174inline bool isUsableSubnetHostAddress(uint32_t ip, uint32_t netmask) {
175 uint32_t hostMask = ~netmask;
176 if (hostMask == 0) {
177 return true;
178 }
179
180 uint32_t hostPart = ip & hostMask;
181 return hostPart != 0 && hostPart != hostMask;
182}
183
184inline bool parseNetmaskOrPrefix(const char* text, uint32_t* result) {
185 if (text == nullptr || result == nullptr) {
186 return false;
187 }
188
189 if (text[0] == '/') {
190 ++text;
191 }
192
193 if (strchr(text, '.') != nullptr) {
194 if (!parseIpv4Address(text, result)) {
195 return false;
196 }
197 return isValidNetmask(*result);
198 }
199
200 uint32_t prefix = 0;
201 if (!parseUnsignedDecimal(text, &prefix, 32)) {
202 return false;
203 }
204 if (prefix == 0 || prefix > 32) {
205 return false;
206 }
207
208 if (prefix == 32) {
209 *result = 0xFFFFFFFFu;
210 } else {
211 *result = 0xFFFFFFFFu << (32 - prefix);
212 }
213 return isValidNetmask(*result);
214}
215
216inline void normalizeDhcpNetifConfig(NetifConfigBlob* cfg) {
217 if (cfg == nullptr) {
218 return;
219 }
220
221 cfg->version = NETIF_CONFIG_BLOB_VERSION;
222 cfg->ipMode = static_cast<uint8_t>(NetifIpMode::DHCP);
223 cfg->reserved[0] = 0;
224 cfg->reserved[1] = 0;
225 cfg->ip = 0;
226 cfg->netmask = 0;
227 cfg->gateway = 0;
228 cfg->dns1 = 0;
229 cfg->dns2 = 0;
230}
231
232inline bool isValidStaticNetifConfig(const NetifConfigBlob& cfg) {
233 if (cfg.version != NETIF_CONFIG_BLOB_VERSION) {
234 return false;
235 }
236 if (cfg.ipMode != static_cast<uint8_t>(NetifIpMode::Static)) {
237 return false;
238 }
239
240 if (!isValidIpv4Address(cfg.ip) || !isValidNetmask(cfg.netmask) ||
241 !isUsableSubnetHostAddress(cfg.ip, cfg.netmask) ||
242 !isValidIpv4Address(cfg.gateway) ||
243 !isUsableSubnetHostAddress(cfg.gateway, cfg.netmask) ||
244 !isSameSubnet(cfg.ip, cfg.netmask, cfg.gateway) ||
245 cfg.ip == cfg.gateway ||
246 !isValidIpv4Address(cfg.dns1)) {
247 return false;
248 }
249
250 if (cfg.dns2 != 0 && !isValidIpv4Address(cfg.dns2)) {
251 return false;
252 }
253
254 return true;
255}
256
257inline bool isValidNetifConfigBlob(const NetifConfigBlob& cfg) {
258 if (cfg.version != NETIF_CONFIG_BLOB_VERSION) {
259 return false;
260 }
261 if (cfg.ipMode == static_cast<uint8_t>(NetifIpMode::DHCP)) {
262 return true;
263 }
264 if (cfg.ipMode == static_cast<uint8_t>(NetifIpMode::Static)) {
265 return isValidStaticNetifConfig(cfg);
266 }
267 return false;
268}
269
270} // namespace Supla
271
272#endif // SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
Definition netif_config.h:22