19#ifndef SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
20#define SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
29enum class NetifIpMode : uint8_t {
34constexpr uint8_t NETIF_CONFIG_BLOB_VERSION = 1;
38 uint8_t version = NETIF_CONFIG_BLOB_VERSION;
39 uint8_t ipMode =
static_cast<uint8_t
>(NetifIpMode::DHCP);
40 uint8_t reserved[2] = {};
50 "Unexpected NetifConfigBlob size");
52inline bool parseUnsignedDecimal(
const char* text,
55 if (text ==
nullptr || result ==
nullptr || text[0] ==
'\0') {
60 for (
const char* ptr = text; *ptr; ++ptr) {
61 if (*ptr <
'0' || *ptr >
'9') {
64 uint32_t digit =
static_cast<uint32_t
>(*ptr -
'0');
65 if (value > (UINT32_MAX - digit) / 10) {
68 value = value * 10 + digit;
69 if (value > maxValue) {
78inline bool parseUnsignedDecimalRange(
const char* begin,
82 if (begin ==
nullptr || end ==
nullptr || result ==
nullptr ||
88 for (
const char* ptr = begin; ptr < end; ++ptr) {
89 if (*ptr <
'0' || *ptr >
'9') {
92 uint32_t digit =
static_cast<uint32_t
>(*ptr -
'0');
93 if (value > (UINT32_MAX - digit) / 10) {
96 value = value * 10 + digit;
97 if (value > maxValue) {
106inline bool parseIpv4Address(
const char* text, uint32_t* result) {
107 if (text ==
nullptr || result ==
nullptr) {
112 const char* ptr = text;
113 for (
int i = 0; i < 4; i++) {
114 const char* end = (i < 3) ? strchr(ptr,
'.') : ptr + strlen(ptr);
115 if (end ==
nullptr) {
119 if (!parseUnsignedDecimalRange(ptr, end, &value, 255)) {
130 }
else if (*end !=
'\0') {
147inline bool formatIpv4Address(uint32_t ip,
char* out,
size_t outSize) {
148 if (out ==
nullptr || outSize == 0) {
152 int size = snprintf(out,
155 static_cast<unsigned int>((ip >> 24) & 0xFF),
156 static_cast<unsigned int>((ip >> 16) & 0xFF),
157 static_cast<unsigned int>((ip >> 8) & 0xFF),
158 static_cast<unsigned int>(ip & 0xFF));
159 return size > 0 &&
static_cast<size_t>(size) < outSize;
162inline bool isValidNetmask(uint32_t netmask) {
167 uint32_t inverted = ~netmask;
168 return (inverted & (inverted + 1)) == 0;
171inline bool isValidIpv4Address(uint32_t ip) {
172 uint8_t firstOctet =
static_cast<uint8_t
>((ip >> 24) & 0xFF);
173 if (ip == 0 || ip == 0xFFFFFFFFu) {
176 if (firstOctet == 127) {
179 if (firstOctet >= 224) {
185inline bool isSameSubnet(uint32_t ip, uint32_t netmask, uint32_t gateway) {
186 return (ip & netmask) == (gateway & netmask);
189inline bool isUsableSubnetHostAddress(uint32_t ip, uint32_t netmask) {
190 uint32_t hostMask = ~netmask;
195 uint32_t hostPart = ip & hostMask;
196 return hostPart != 0 && hostPart != hostMask;
199inline bool parseNetmaskOrPrefix(
const char* text, uint32_t* result) {
200 if (text ==
nullptr || result ==
nullptr) {
204 if (text[0] ==
'/') {
208 if (strchr(text,
'.') !=
nullptr) {
209 if (!parseIpv4Address(text, result)) {
212 return isValidNetmask(*result);
216 if (!parseUnsignedDecimal(text, &prefix, 32)) {
219 if (prefix == 0 || prefix > 32) {
224 *result = 0xFFFFFFFFu;
226 *result = 0xFFFFFFFFu << (32 - prefix);
228 return isValidNetmask(*result);
232 if (cfg ==
nullptr) {
236 cfg->version = NETIF_CONFIG_BLOB_VERSION;
237 cfg->ipMode =
static_cast<uint8_t
>(NetifIpMode::DHCP);
238 cfg->reserved[0] = 0;
239 cfg->reserved[1] = 0;
248 if (cfg.version != NETIF_CONFIG_BLOB_VERSION) {
251 if (cfg.ipMode !=
static_cast<uint8_t
>(NetifIpMode::Static)) {
255 if (!isValidIpv4Address(cfg.ip) || !isValidNetmask(cfg.netmask) ||
256 !isUsableSubnetHostAddress(cfg.ip, cfg.netmask) ||
257 !isValidIpv4Address(cfg.gateway) ||
258 !isUsableSubnetHostAddress(cfg.gateway, cfg.netmask) ||
259 !isSameSubnet(cfg.ip, cfg.netmask, cfg.gateway) ||
260 cfg.ip == cfg.gateway ||
261 !isValidIpv4Address(cfg.dns1)) {
265 if (cfg.dns2 != 0 && !isValidIpv4Address(cfg.dns2)) {
273 if (cfg.version != NETIF_CONFIG_BLOB_VERSION) {
276 if (cfg.ipMode ==
static_cast<uint8_t
>(NetifIpMode::DHCP)) {
279 if (cfg.ipMode ==
static_cast<uint8_t
>(NetifIpMode::Static)) {
280 return isValidStaticNetifConfig(cfg);
Definition netif_config.h:37