diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 9f8b164..b5c2d72 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -1,4 +1,4 @@ -name: Build, release, update +name: Build, release, push permissions: contents: write @@ -7,10 +7,10 @@ on: workflow_dispatch: push: tags: - - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + - '*' # Push events to matching *, any jobs: - build_firmware: + build_release_push: runs-on: ubuntu-latest steps: - name: Clone repository @@ -20,58 +20,79 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 + - uses: actions/cache@v3 with: path: | ~/.cache/pip ~/.platformio/.cache key: ${{ runner.os }}-pio + - name: Install Python uses: actions/setup-python@v4 with: python-version: '3.9' + - name: Install PlatformIO Core run: pip install --upgrade platformio==6.1.11 - name: Build PlatformIO Project run: pio run + - name: Get Release Version id: get_version shell: bash run: | - value=`cat tools/version` + value=$(grep '#define VERSION' src/version.h | awk -F '"' '{print $2}') echo "version=$value" >> $GITHUB_OUTPUT - - name: Get current date - id: date - run: echo "date=$(date +'%d%m%y')" >> $GITHUB_OUTPUT + - name: Get last commit message id: get_commit_message run: | commitMessage=$(git log -1 --pretty=%B | tail -n +3) - echo "::set-output name=message::${commitMessage}" + echo "commitMessage<> $GITHUB_ENV + echo "$commitMessage" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Calculate SHA-256 hash of the firmware + id: sha256_hash + run: | + echo "sha256=$(sha256sum bin/XZG_${{ steps.get_version.outputs.version }}.full.bin | awk '{print $1}')" >> $GITHUB_OUTPUT + + - name: Get size of the firmware + id: firmware_size + run: | + echo "size=$(stat -c %s bin/XZG_${{ steps.get_version.outputs.version }}.full.bin)" >> $GITHUB_OUTPUT + + - name: Create manifest.json for ESP Web Tools + run: | + cat << EOF > manifest.json + { + "name": "XZG Firmware", + "version": "${{ steps.get_version.outputs.version }}", + "files": [ + { + "path": "XZG_${{ steps.get_version.outputs.version }}.full.bin", + "type": "app", + "lzma": false, + "address": "0x0", + "sha256": "${{ steps.sha256_hash.outputs.sha256 }}", + "size": ${{ steps.firmware_size.outputs.size }}, + "url": "https://github.com/${{ github.repository }}/releases/download/${{ steps.get_version.outputs.version }}/XZG_${{ steps.get_version.outputs.version }}.full.bin" + } + ], + "chipFamily": "ESP32" + } + EOF + echo "Manifest file created." + - name: Release uses: softprops/action-gh-release@v1 with: generate_release_notes: false - name: "v${{ steps.get_version.outputs.version }} (${{ steps.date.outputs.date }})" - body: ${{ steps.get_commit_message.outputs.message }} + name: "${{ steps.get_version.outputs.version }}" + body: ${{ env.commitMessage }} files: | - bin/XZG.bin - bin/XZG_v${{ steps.get_version.outputs.version }}.full.bin - - - name: Updare version in manifest.json - run: | - sed -r 's/v[0-9]{1,4}\.[0-9]{1,4}\.[0-9]{1,4}/v${{ steps.get_version.outputs.version }}/g' manifest.json > new.manifest.json - - name: Move file - shell: bash - run: | - echo "old" - cat manifest.json - mv -f new.manifest.json manifest.json - echo "new" - cat manifest.json - - name: Commit & Push changes - uses: actions-js/push@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - message: 'Release v${{ steps.get_version.outputs.version }} (${{ steps.date.outputs.date }})' \ No newline at end of file + bin/XZG_${{ steps.get_version.outputs.version }}.ota.bin + bin/XZG_${{ steps.get_version.outputs.version }}.full.bin + manifest.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..60850d2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "lib/WireGuard"] + path = lib/WireGuard + url = https://github.com/Tinkerforge/WireGuard-ESP32-Arduino + branch = main diff --git a/README.md b/README.md index 6c4d794..0695a9b 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,15 @@ Firmware is opensource, so feel free to improve it
by making a commit to th ### Previous versions: -| [ZigStarGW-FW](https://github.com/xyzroe/ZigStarGW-FW/releases/latest) | [UZG-01](https://github.com/mercenaruss/uzg-firmware/releases/latest) | [SLZB-06](https://github.com/smlight-dev/slzb-06-firmware/releases/) | +| [ZigStarGW-FW](https://github.com/xyzroe/ZigStarGW-FW/releases/latest) | [XZG](https://github.com/mercenaruss/uzg-firmware/releases/latest) | [SLZB-06](https://github.com/smlight-dev/slzb-06-firmware/releases/) | | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [![ZigStarGW-FW's download](https://img.shields.io/github/downloads/xyzroe/ZigStarGW-FW/total.svg)](https://github.com/xyzroe/ZigStarGW-FW/releases/latest) | [![UZG-01 Firmware's download](https://img.shields.io/github/downloads/mercenaruss/uzg-firmware/total.svg)](https://github.com/mercenaruss/uzg-firmware/releases/latest) | [![UZG-01 Firmware's download](https://img.shields.io/github/downloads/smlight-dev/slzb-06-firmware/total.svg)](https://github.com/smlight-dev/slzb-06-firmware/releases/latest) | +| [![ZigStarGW-FW's download](https://img.shields.io/github/downloads/xyzroe/ZigStarGW-FW/total.svg)](https://github.com/xyzroe/ZigStarGW-FW/releases/latest) | [![XZG Firmware's download](https://img.shields.io/github/downloads/mercenaruss/uzg-firmware/total.svg)](https://github.com/mercenaruss/uzg-firmware/releases/latest) | [![XZG Firmware's download](https://img.shields.io/github/downloads/smlight-dev/slzb-06-firmware/total.svg)](https://github.com/smlight-dev/slzb-06-firmware/releases/latest) | ## KEY FIRMWARE FEATURES - Change Ethernet/USB adapter mode through firmware or by physical button short press (Red LED On = USB mode, RED LED Off = Ethernet mode); -- Adapter mode selector through web-interface: `Zigbee-to-Ethernet`, `Zigbee-to-USB` and `Zigbee-to-WiFI`; +- Adapter mode selector through web-interface: `Zigbee-to-Network` or `Zigbee-to-USB`; - Support mDNS autodiscovery in your network (go in the browser to `uzg-01.local`), in Zigbee2MQTT (set `port: mdns://uzg-01`), and in ZHA; - Secure login through username and password; - Zigbee2MQTT and ZHA config helper; @@ -75,7 +75,7 @@ You can contribute to XZG Firmware by People helping to keep the show on the road - **developers and contributors**: -- [@mercenaruss](https://github.com/mercenaruss/) for **Zig Star devices development**, for initial firmware release of UZG-01 version and giving me motivation and energy to implement new functions. +- [@mercenaruss](https://github.com/mercenaruss/) for **Zig Star devices development**, for initial firmware release of XZG version and giving me motivation and energy to implement new functions. - [@Tarik2142](https://github.com/Tarik2142) for refactoring, code optimizations done under [smlight-dev](https://github.com/smlight-dev/) diff --git a/bin/XZG_20240330.full.bin b/bin/XZG_20240330.full.bin new file mode 100644 index 0000000..0ee3977 Binary files /dev/null and b/bin/XZG_20240330.full.bin differ diff --git a/bin/XZG_20240330.ota.bin b/bin/XZG_20240330.ota.bin new file mode 100644 index 0000000..923e5a7 Binary files /dev/null and b/bin/XZG_20240330.ota.bin differ diff --git a/lib/CCTools/src/CCTools.cpp b/lib/CCTools/src/CCTools.cpp index 4871bd4..07ff4c4 100644 --- a/lib/CCTools/src/CCTools.cpp +++ b/lib/CCTools/src/CCTools.cpp @@ -310,14 +310,14 @@ void CCTools::enterBSL() { digitalWrite(_CC_RST_PIN, LOW); digitalWrite(_CC_BSL_PIN, LOW); - DEBUG_PRINTLN(F("Zigbee RST pin ON")); - DEBUG_PRINTLN(F("Zigbee BSL pin ON")); + //DEBUG_PRINTLN(F("Zigbee RST pin ON")); + //DEBUG_PRINTLN(F("Zigbee BSL pin ON")); delay(250); digitalWrite(_CC_RST_PIN, HIGH); - DEBUG_PRINTLN(F("Zigbee RST pin OFF")); + //DEBUG_PRINTLN(F("Zigbee RST pin OFF")); delay(1000); digitalWrite(_CC_BSL_PIN, HIGH); - DEBUG_PRINTLN(F("Zigbee BSL pin OFF")); + //DEBUG_PRINTLN(F("Zigbee BSL pin OFF")); delay(1000); } // Other modes BSL_MODE can be added later @@ -326,20 +326,20 @@ void CCTools::enterBSL() void CCTools::restart() { digitalWrite(_CC_RST_PIN, LOW); - DEBUG_PRINTLN(F("Zigbee RST pin ON")); + //DEBUG_PRINTLN(F("Zigbee RST pin ON")); delay(250); digitalWrite(_CC_RST_PIN, HIGH); - DEBUG_PRINTLN(F("Zigbee RST pin OFF")); + //DEBUG_PRINTLN(F("Zigbee RST pin OFF")); delay(1000); } void CCTools::routerRejoin() { digitalWrite(_CC_BSL_PIN, LOW); - DEBUG_PRINTLN(F("ZB BSL pin ON")); + //DEBUG_PRINTLN(F("ZB BSL pin ON")); delay(250); digitalWrite(_CC_BSL_PIN, HIGH); - DEBUG_PRINTLN(F("ZB BSL pin OFF")); + //DEBUG_PRINTLN(F("ZB BSL pin OFF")); delay(500); } String CCTools::detectChipInfo() diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..9fe6205 --- /dev/null +++ b/lib/README.md @@ -0,0 +1 @@ +git submodule update --recursive --remote \ No newline at end of file diff --git a/lib/WireGuard b/lib/WireGuard new file mode 160000 index 0000000..58de5da --- /dev/null +++ b/lib/WireGuard @@ -0,0 +1 @@ +Subproject commit 58de5da725bf11720439306496d8962dcb26af61 diff --git a/lib/WireGuard-ESP32/.gitignore b/lib/WireGuard-ESP32/.gitignore deleted file mode 100644 index c07a74d..0000000 --- a/lib/WireGuard-ESP32/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build.sh \ No newline at end of file diff --git a/lib/WireGuard-ESP32/.piopm b/lib/WireGuard-ESP32/.piopm deleted file mode 100644 index 648150c..0000000 --- a/lib/WireGuard-ESP32/.piopm +++ /dev/null @@ -1 +0,0 @@ -{"type": "library", "name": "WireGuard-ESP32", "version": "0.1.5", "spec": {"owner": "ciniml", "id": 12571, "name": "WireGuard-ESP32", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/lib/WireGuard-ESP32/LICENSE b/lib/WireGuard-ESP32/LICENSE deleted file mode 100644 index 3856ceb..0000000 --- a/lib/WireGuard-ESP32/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2021 Kenta Ida (fuga@fugafuga.org) -Copyright (c) 2021 Daniel Hope (www.floorsense.nz) -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. -* Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - its contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Author: Daniel Hope - diff --git a/lib/WireGuard-ESP32/README.md b/lib/WireGuard-ESP32/README.md deleted file mode 100644 index 25424fa..0000000 --- a/lib/WireGuard-ESP32/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# WireGuard Implementation for ESP32 Arduino - -This is an implementation of the [WireGuard®](https://www.wireguard.com/) for ESP32 Arduino. - -Almost all of this code is based on the [WireGuard Implementation for lwIP](https://github.com/smartalock/wireguard-lwip), but some potion of the code is adjusted to build with ESP32 Arduino. - -## How to use - -1. Include `WireGuard-ESP32.h` at the early part of the sketch. - -```c++ -#include -``` - -2. Define the instance of the `WireGuard` class at module level. - -```c++ -static WireGuard wg; -``` - -3. Connect to WiFi AP by using `WiFi` class. - -```c++ -WiFi.begin(ssid, password); -while( !WiFi.isConnected() ) { - delay(1000); -} -``` - -4. Sync the system time via NTP. - -```c++ -configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); -``` - -5. Start the WireGuard interface. - -```c++ -wg.begin( - local_ip, // IP address of the local interface - private_key, // Private key of the local interface - endpoint_address, // Address of the endpoint peer. - public_key, // Public key of the endpoint peer. - endpoint_port); // Port pf the endpoint peer. -``` - -You can see an example sketch `uptime_post.ino`, which connects SORACOM Arc WireGuard endpoint and post uptime to SORACOM Harvest via WireGuard connection. - -## License - -The original WireGuard implementation for lwIP is licensed under BSD 3 clause license so the code in this repository also licensed under the same license. - -Original license is below: - -The code is copyrighted under BSD 3 clause Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - -See LICENSE for details diff --git a/lib/WireGuard-ESP32/examples/disconnect/disconnect.ino b/lib/WireGuard-ESP32/examples/disconnect/disconnect.ino deleted file mode 100644 index b94ea06..0000000 --- a/lib/WireGuard-ESP32/examples/disconnect/disconnect.ino +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include - -// WiFi configuration --- UPDATE this configuration for your WiFi AP -char ssid[] = "ssid"; -char password[] = "password"; - -// WireGuard configuration --- UPDATE this configuration from JSON -char private_key[] = "(Private Key) "; // [Interface] PrivateKey -IPAddress local_ip(1,2,3,4); // [Interface] Address -char public_key[] = "(Public Key)"; // [Peer] PublicKey -char endpoint_address[] = "link.arc.soracom.io"; // [Peer] Endpoint -int endpoint_port = 11010; // [Peer] Endpoint - -const char host_inside_vpn[] = "10.0.0.1"; -const char host_outside_vpn[] = "192.168.2.1"; - -static constexpr const uint32_t UPDATE_INTERVAL_MS = 5000; - -static WireGuard wg; - -void setup() -{ - esp_log_level_set("*", ESP_LOG_DEBUG); - - Serial.begin(115200); - Serial.println("Connecting to the AP..."); - WiFi.begin(ssid, password); - while( !WiFi.isConnected() ) { - delay(1000); - } - - Serial.println("Adjusting system time..."); - configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); - - Serial.println("WiFi Connected."); -} - -void loop() -{ - static uint64_t send_count = 0; - static uint64_t loop_count = 0; - if( loop_count % 5 == 0) { - if( !wg.is_initialized() ) { - Serial.println("Initializing WG interface..."); - if( !wg.begin( - local_ip, - private_key, - endpoint_address, - public_key, - endpoint_port) ) { - Serial.println("Failed to initialize WG interface."); - } - } - else { - Serial.println("Shutting down WG interface..."); - wg.end(); - } - } - loop_count++; - - WiFiUDP client; - const char* host = wg.is_initialized() ? host_inside_vpn : host_outside_vpn; - if( !client.beginPacket(host, 23080) ) { - Serial.println("Failed to begin packet..."); - delay(5000); - return; - } - - uint64_t uptime_msec = millis(); - uint8_t buffer[16]; - buffer[ 0] = (uptime_msec >> 0) & 0xff; - buffer[ 1] = (uptime_msec >> 8) & 0xff; - buffer[ 2] = (uptime_msec >> 16) & 0xff; - buffer[ 3] = (uptime_msec >> 24) & 0xff; - buffer[ 4] = (uptime_msec >> 32) & 0xff; - buffer[ 5] = (uptime_msec >> 40) & 0xff; - buffer[ 6] = (uptime_msec >> 48) & 0xff; - buffer[ 7] = (uptime_msec >> 56) & 0xff; - buffer[ 8] = (send_count >> 0) & 0xff; - buffer[ 9] = (send_count >> 8) & 0xff; - buffer[10] = (send_count >> 16) & 0xff; - buffer[11] = (send_count >> 24) & 0xff; - buffer[12] = (send_count >> 32) & 0xff; - buffer[13] = (send_count >> 40) & 0xff; - buffer[14] = (send_count >> 48) & 0xff; - buffer[15] = (send_count >> 56) & 0xff; - - Serial.printf("Sending uptime %lu [ms], count=%d\r\n", uptime_msec, send_count); - client.write(buffer, sizeof(buffer)); - client.endPacket(); - - send_count++; - - IPAddress result; - if( WiFi.hostByName("www.google.com", result) ) { - Serial.printf("hostByName: %s\r\n", result.toString().c_str()); - } - else { - Serial.printf("hostByName failed\r\n"); - } - - delay(UPDATE_INTERVAL_MS); -} diff --git a/lib/WireGuard-ESP32/examples/uptime_post/uptime_post.ino b/lib/WireGuard-ESP32/examples/uptime_post/uptime_post.ino deleted file mode 100644 index f16c41d..0000000 --- a/lib/WireGuard-ESP32/examples/uptime_post/uptime_post.ino +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include - -// WiFi configuration --- UPDATE this configuration for your WiFi AP -char ssid[] = "ssid"; -char password[] = "password"; - -// WireGuard configuration --- UPDATE this configuration from JSON -char private_key[] = "(Private Key) "; // [Interface] PrivateKey -IPAddress local_ip(1,2,3,4); // [Interface] Address -char public_key[] = "(Public Key)"; // [Peer] PublicKey -char endpoint_address[] = "link.arc.soracom.io"; // [Peer] Endpoint -int endpoint_port = 11010; // [Peer] Endpoint - -static constexpr const uint32_t UPDATE_INTERVAL_MS = 5000; - -static WireGuard wg; -static HTTPClient httpClient; - -void setup() -{ - Serial.begin(115200); - Serial.println("Connecting to the AP..."); - WiFi.begin(ssid, password); - while( !WiFi.isConnected() ) { - delay(1000); - } - Serial.println("Adjusting system time..."); - configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); - - Serial.println("Connected. Initializing WireGuard..."); - wg.begin( - local_ip, - private_key, - endpoint_address, - public_key, - endpoint_port); -} - -void loop() -{ - WiFiClient client; - - if( !client.connect("uni.soracom.io", 80) ) { - Serial.println("Failed to connect..."); - delay(5000); - return; - } - - uint64_t uptime_msec = millis(); - Serial.printf("Sending uptime %lu [ms]\r\n", uptime_msec); - String json; - json += "{\"uptime_msec\":"; - json.concat(static_cast(uptime_msec)); - json += "}"; - Serial.printf("payload: %s\r\n", json.c_str()); - - client.write("POST / HTTP/1.1\r\n"); - client.write("Host: harvest.soracom.io\r\n"); - client.write("Connection: Keep-Alive\r\n"); - client.write("Keep-Alive: timeout=5, max=2\r\n"); - client.write("Content-Type: application/json\r\n"); - client.write("Content-Length: "); - client.write(String(json.length(), 10).c_str()); - client.write("\r\n\r\n"); - client.write(json.c_str()); - - while(client.connected()) { - auto line = client.readStringUntil('\n'); - Serial.write(line.c_str()); - Serial.write("\n"); - if( line == "\r" ) break; - } - if(client.connected()) { - uint8_t buffer[256]; - size_t bytesToRead = 0; - while((bytesToRead = client.available()) > 0) { - bytesToRead = bytesToRead > sizeof(buffer) ? sizeof(buffer) : bytesToRead; - auto bytesRead = client.readBytes(buffer, bytesToRead); - Serial.write(buffer, bytesRead); - } - } - delay(UPDATE_INTERVAL_MS); -} diff --git a/lib/WireGuard-ESP32/examples/uptime_udp/uptime_udp.ino b/lib/WireGuard-ESP32/examples/uptime_udp/uptime_udp.ino deleted file mode 100644 index a1acd28..0000000 --- a/lib/WireGuard-ESP32/examples/uptime_udp/uptime_udp.ino +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include - -// WiFi configuration --- UPDATE this configuration for your WiFi AP -char ssid[] = "ssid"; -char password[] = "password"; - -// WireGuard configuration --- UPDATE this configuration from JSON -char private_key[] = "(Private Key) "; // [Interface] PrivateKey -IPAddress local_ip(1,2,3,4); // [Interface] Address -char public_key[] = "(Public Key)"; // [Peer] PublicKey -char endpoint_address[] = "link.arc.soracom.io"; // [Peer] Endpoint -int endpoint_port = 11010; // [Peer] Endpoint - -static constexpr const uint32_t UPDATE_INTERVAL_MS = 5000; - -static WireGuard wg; - -void setup() -{ - Serial.begin(115200); - Serial.println("Connecting to the AP..."); - WiFi.begin(ssid, password); - while( !WiFi.isConnected() ) { - delay(1000); - } - Serial.println("Adjusting system time..."); - configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); - - Serial.println("Connected. Initializing WireGuard..."); - wg.begin( - local_ip, - private_key, - endpoint_address, - public_key, - endpoint_port); -} - -void loop() -{ - static uint64_t send_count = 0; - WiFiUDP client; - if( !client.beginPacket("uni.soracom.io", 23080) ) { - Serial.println("Failed to begin packet..."); - delay(5000); - return; - } - - uint64_t uptime_msec = millis(); - uint8_t buffer[16]; - buffer[ 0] = (uptime_msec >> 0) & 0xff; - buffer[ 1] = (uptime_msec >> 8) & 0xff; - buffer[ 2] = (uptime_msec >> 16) & 0xff; - buffer[ 3] = (uptime_msec >> 24) & 0xff; - buffer[ 4] = (uptime_msec >> 32) & 0xff; - buffer[ 5] = (uptime_msec >> 40) & 0xff; - buffer[ 6] = (uptime_msec >> 48) & 0xff; - buffer[ 7] = (uptime_msec >> 56) & 0xff; - buffer[ 8] = (send_count >> 0) & 0xff; - buffer[ 9] = (send_count >> 8) & 0xff; - buffer[10] = (send_count >> 16) & 0xff; - buffer[11] = (send_count >> 24) & 0xff; - buffer[12] = (send_count >> 32) & 0xff; - buffer[13] = (send_count >> 40) & 0xff; - buffer[14] = (send_count >> 48) & 0xff; - buffer[15] = (send_count >> 56) & 0xff; - - Serial.printf("Sending uptime %lu [ms], count=%d\r\n", uptime_msec, send_count); - client.write(buffer, sizeof(buffer)); - client.endPacket(); - - send_count++; - delay(UPDATE_INTERVAL_MS); -} diff --git a/lib/WireGuard-ESP32/library.properties b/lib/WireGuard-ESP32/library.properties deleted file mode 100644 index d51576d..0000000 --- a/lib/WireGuard-ESP32/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=WireGuard-ESP32 -version=0.1.5 -author=Kenta Ida -maintainer=Kenta Ida -sentence=WireGuard implementation for Arduino ESP32 -paragraph= -category=Communication -url=https://github.com/ciniml/WireGuard-ESP32-Arduino -includes=WireGuard-ESP32.h -architectures=esp32,Inkplate diff --git a/lib/WireGuard-ESP32/src/WireGuard-ESP32.h b/lib/WireGuard-ESP32/src/WireGuard-ESP32.h deleted file mode 100644 index 29820a4..0000000 --- a/lib/WireGuard-ESP32/src/WireGuard-ESP32.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * SPDX-License-Identifier: BSD-3-Clause - */ -#pragma once -#include - -class WireGuard -{ -private: - bool _is_initialized = false; -public: - bool begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort); - void end(); - bool is_initialized() const { return this->_is_initialized; } -}; diff --git a/lib/WireGuard-ESP32/src/WireGuard.cpp b/lib/WireGuard-ESP32/src/WireGuard.cpp deleted file mode 100644 index 15d5c4e..0000000 --- a/lib/WireGuard-ESP32/src/WireGuard.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * SPDX-License-Identifier: BSD-3-Clause - */ -#include "WireGuard-ESP32.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include "esp_system.h" - -#include "lwip/err.h" -#include "lwip/sys.h" -#include "lwip/ip.h" -#include "lwip/netdb.h" - -#include "esp32-hal-log.h" - -extern "C" { -#include "wireguardif.h" -#include "wireguard-platform.h" -} - -// Wireguard instance -static struct netif wg_netif_struct = {0}; -static struct netif *wg_netif = NULL; -static struct netif *previous_default_netif = NULL; -static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX; - -#define TAG "[WireGuard] " - -bool WireGuard::begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) { - struct wireguardif_init_data wg; - struct wireguardif_peer peer; - ip_addr_t ipaddr = IPADDR4_INIT(static_cast(localIP)); - ip_addr_t netmask = IPADDR4_INIT_BYTES(255, 255, 255, 255); - ip_addr_t gateway = IPADDR4_INIT_BYTES(0, 0, 0, 0); - - assert(privateKey != NULL); - assert(remotePeerAddress != NULL); - assert(remotePeerPublicKey != NULL); - assert(remotePeerPort != 0); - - // Setup the WireGuard device structure - wg.private_key = privateKey; - wg.listen_port = remotePeerPort; - - wg.bind_netif = NULL; - - // Initialise the first WireGuard peer structure - wireguardif_peer_init(&peer); - // If we know the endpoint's address can add here - bool success_get_endpoint_ip = false; - for(int retry = 0; retry < 5; retry++) { - ip_addr_t endpoint_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); - struct addrinfo *res = NULL; - struct addrinfo hint; - memset(&hint, 0, sizeof(hint)); - memset(&endpoint_ip, 0, sizeof(endpoint_ip)); - if( lwip_getaddrinfo(remotePeerAddress, NULL, &hint, &res) != 0 ) { - vTaskDelay(pdMS_TO_TICKS(2000)); - continue; - } - success_get_endpoint_ip = true; - struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr; - inet_addr_to_ip4addr(ip_2_ip4(&endpoint_ip), &addr4); - lwip_freeaddrinfo(res); - - peer.endpoint_ip = endpoint_ip; - log_i(TAG "%s is %3d.%3d.%3d.%3d" - , remotePeerAddress - , (endpoint_ip.u_addr.ip4.addr >> 0) & 0xff - , (endpoint_ip.u_addr.ip4.addr >> 8) & 0xff - , (endpoint_ip.u_addr.ip4.addr >> 16) & 0xff - , (endpoint_ip.u_addr.ip4.addr >> 24) & 0xff - ); - break; - } - if( !success_get_endpoint_ip ) { - log_e(TAG "failed to get endpoint ip."); - return false; - } - // Register the new WireGuard network interface with lwIP - wg_netif = netif_add(&wg_netif_struct, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gateway), &wg, &wireguardif_init, &ip_input); - if( wg_netif == nullptr ) { - log_e(TAG "failed to initialize WG netif."); - return false; - } - // Mark the interface as administratively up, link up flag is set automatically when peer connects - netif_set_up(wg_netif); - - peer.public_key = remotePeerPublicKey; - peer.preshared_key = NULL; - // Allow all IPs through tunnel - { - ip_addr_t allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); - peer.allowed_ip = allowed_ip; - ip_addr_t allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0); - peer.allowed_mask = allowed_mask; - } - - peer.endport_port = remotePeerPort; - - // Initialize the platform - wireguard_platform_init(); - // Register the new WireGuard peer with the netwok interface - wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index); - if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) { - // Start outbound connection to peer - log_i(TAG "connecting wireguard..."); - wireguardif_connect(wg_netif, wireguard_peer_index); - // Save the current default interface for restoring when shutting down the WG interface. - previous_default_netif = netif_default; - // Set default interface to WG device. - netif_set_default(wg_netif); - } - - this->_is_initialized = true; - return true; -} - -void WireGuard::end() { - if( !this->_is_initialized ) return; - - // Restore the default interface. - netif_set_default(previous_default_netif); - previous_default_netif = nullptr; - // Disconnect the WG interface. - wireguardif_disconnect(wg_netif, wireguard_peer_index); - // Remove peer from the WG interface - wireguardif_remove_peer(wg_netif, wireguard_peer_index); - wireguard_peer_index = WIREGUARDIF_INVALID_INDEX; - // Shutdown the wireguard interface. - wireguardif_shutdown(wg_netif); - // Remove the WG interface; - netif_remove(wg_netif); - wg_netif = nullptr; - - this->_is_initialized = false; -} \ No newline at end of file diff --git a/lib/WireGuard-ESP32/src/crypto.c b/lib/WireGuard-ESP32/src/crypto.c deleted file mode 100644 index 3597b86..0000000 --- a/lib/WireGuard-ESP32/src/crypto.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "crypto.h" - -#include -#include -#include - -void crypto_zero(void *dest, size_t len) { - volatile uint8_t *p = (uint8_t *)dest; - while (len--) { - *p++ = 0; - } -} - -bool crypto_equal(const void *a, const void *b, size_t size) { - uint8_t neq = 0; - while (size > 0) { - neq |= *(uint8_t *)a ^ *(uint8_t *)b; - a += 1; - b += 1; - size -= 1; - } - return (neq) ? false : true; -} diff --git a/lib/WireGuard-ESP32/src/crypto.h b/lib/WireGuard-ESP32/src/crypto.h deleted file mode 100644 index c5d640d..0000000 --- a/lib/WireGuard-ESP32/src/crypto.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _CRYPTO_H_ -#define _CRYPTO_H_ - -#include -#include -#include - -// BLAKE2S IMPLEMENTATION -#include "crypto/refc/blake2s.h" -#define wireguard_blake2s_ctx blake2s_ctx -#define wireguard_blake2s_init(ctx,outlen,key,keylen) blake2s_init(ctx,outlen,key,keylen) -#define wireguard_blake2s_update(ctx,in,inlen) blake2s_update(ctx,in,inlen) -#define wireguard_blake2s_final(ctx,out) blake2s_final(ctx,out) -#define wireguard_blake2s(out,outlen,key,keylen,in,inlen) blake2s(out,outlen,key,keylen,in,inlen) - -// X25519 IMPLEMENTATION -#include "crypto/refc/x25519.h" -#define wireguard_x25519(a,b,c) x25519(a,b,c,1) - -// CHACHA20POLY1305 IMPLEMENTATION -#include "crypto/refc/chacha20poly1305.h" -#define wireguard_aead_encrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key) -#define wireguard_aead_decrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key) -#define wireguard_xaead_encrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key) -#define wireguard_xaead_decrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key) - - -// Endian / unaligned helper macros -#define U8C(v) (v##U) -#define U32C(v) (v##U) - -#define U8V(v) ((uint8_t)(v) & U8C(0xFF)) -#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF)) - -#define U8TO32_LITTLE(p) \ - (((uint32_t)((p)[0]) ) | \ - ((uint32_t)((p)[1]) << 8) | \ - ((uint32_t)((p)[2]) << 16) | \ - ((uint32_t)((p)[3]) << 24)) - -#define U8TO64_LITTLE(p) \ - (((uint64_t)((p)[0]) ) | \ - ((uint64_t)((p)[1]) << 8) | \ - ((uint64_t)((p)[2]) << 16) | \ - ((uint64_t)((p)[3]) << 24) | \ - ((uint64_t)((p)[4]) << 32) | \ - ((uint64_t)((p)[5]) << 40) | \ - ((uint64_t)((p)[6]) << 48) | \ - ((uint64_t)((p)[7]) << 56)) - -#define U16TO8_BIG(p, v) \ - do { \ - (p)[1] = U8V((v) ); \ - (p)[0] = U8V((v) >> 8); \ - } while (0) - -#define U32TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - (p)[2] = U8V((v) >> 16); \ - (p)[3] = U8V((v) >> 24); \ - } while (0) - -#define U32TO8_BIG(p, v) \ - do { \ - (p)[3] = U8V((v) ); \ - (p)[2] = U8V((v) >> 8); \ - (p)[1] = U8V((v) >> 16); \ - (p)[0] = U8V((v) >> 24); \ - } while (0) - -#define U64TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - (p)[2] = U8V((v) >> 16); \ - (p)[3] = U8V((v) >> 24); \ - (p)[4] = U8V((v) >> 32); \ - (p)[5] = U8V((v) >> 40); \ - (p)[6] = U8V((v) >> 48); \ - (p)[7] = U8V((v) >> 56); \ -} while (0) - -#define U64TO8_BIG(p, v) \ - do { \ - (p)[7] = U8V((v) ); \ - (p)[6] = U8V((v) >> 8); \ - (p)[5] = U8V((v) >> 16); \ - (p)[4] = U8V((v) >> 24); \ - (p)[3] = U8V((v) >> 32); \ - (p)[2] = U8V((v) >> 40); \ - (p)[1] = U8V((v) >> 48); \ - (p)[0] = U8V((v) >> 56); \ -} while (0) - - -void crypto_zero(void *dest, size_t len); -bool crypto_equal(const void *a, const void *b, size_t size); - -#endif /* _CRYPTO_H_ */ - diff --git a/lib/WireGuard-ESP32/src/crypto/refc/blake2s.c b/lib/WireGuard-ESP32/src/crypto/refc/blake2s.c deleted file mode 100644 index ae5e14c..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/blake2s.c +++ /dev/null @@ -1,156 +0,0 @@ -// Taken from RFC7693 - https://tools.ietf.org/html/rfc7693 - -#include "blake2s.h" -#include "../../crypto.h" - -// Cyclic right rotation. - -#ifndef ROTR32 -#define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y)))) -#endif - -// Mixing function G. -#define B2S_G(a, b, c, d, x, y) { \ - v[a] = v[a] + v[b] + x; \ - v[d] = ROTR32(v[d] ^ v[a], 16); \ - v[c] = v[c] + v[d]; \ - v[b] = ROTR32(v[b] ^ v[c], 12); \ - v[a] = v[a] + v[b] + y; \ - v[d] = ROTR32(v[d] ^ v[a], 8); \ - v[c] = v[c] + v[d]; \ - v[b] = ROTR32(v[b] ^ v[c], 7); } - -// Initialization Vector. -static const uint32_t blake2s_iv[8] = -{ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 -}; - -// Compression function. "last" flag indicates last block. -static void blake2s_compress(blake2s_ctx *ctx, int last) -{ - const uint8_t sigma[10][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } - }; - int i; - uint32_t v[16], m[16]; - - for (i = 0; i < 8; i++) { // init work variables - v[i] = ctx->h[i]; - v[i + 8] = blake2s_iv[i]; - } - - v[12] ^= ctx->t[0]; // low 32 bits of offset - v[13] ^= ctx->t[1]; // high 32 bits - if (last) // last block flag set ? - v[14] = ~v[14]; - for (i = 0; i < 16; i++) // get little-endian words - m[i] = U8TO32_LITTLE(&ctx->b[4 * i]); - - for (i = 0; i < 10; i++) { // ten rounds - B2S_G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]); - B2S_G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]); - B2S_G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]); - B2S_G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]); - B2S_G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]); - B2S_G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]); - B2S_G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]); - B2S_G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]); - } - - for( i = 0; i < 8; ++i ) - ctx->h[i] ^= v[i] ^ v[i + 8]; -} - -// Initialize the hashing context "ctx" with optional key "key". -// 1 <= outlen <= 32 gives the digest size in bytes. -// Secret key (also <= 32 bytes) is optional (keylen = 0). -int blake2s_init(blake2s_ctx *ctx, size_t outlen, - const void *key, size_t keylen) // (keylen=0: no key) -{ - size_t i; - - if (outlen == 0 || outlen > 32 || keylen > 32) - return -1; // illegal parameters - - for (i = 0; i < 8; i++) // state, "param block" - ctx->h[i] = blake2s_iv[i]; - ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; - - ctx->t[0] = 0; // input count low word - ctx->t[1] = 0; // input count high word - ctx->c = 0; // pointer within buffer - ctx->outlen = outlen; - - for (i = keylen; i < 64; i++) // zero input block - ctx->b[i] = 0; - if (keylen > 0) { - blake2s_update(ctx, key, keylen); - ctx->c = 64; // at the end - } - - return 0; -} - -// Add "inlen" bytes from "in" into the hash. -void blake2s_update(blake2s_ctx *ctx, - const void *in, size_t inlen) // data bytes -{ - size_t i; - - for (i = 0; i < inlen; i++) { - if (ctx->c == 64) { // buffer full ? - ctx->t[0] += ctx->c; // add counters - if (ctx->t[0] < ctx->c) // carry overflow ? - ctx->t[1]++; // high word - blake2s_compress(ctx, 0); // compress (not last) - ctx->c = 0; // counter to zero - } - ctx->b[ctx->c++] = ((const uint8_t *) in)[i]; - } -} - -// Generate the message digest (size given in init). -// Result placed in "out". -void blake2s_final(blake2s_ctx *ctx, void *out) -{ - size_t i; - - ctx->t[0] += ctx->c; // mark last block offset - if (ctx->t[0] < ctx->c) // carry overflow - ctx->t[1]++; // high word - - while (ctx->c < 64) // fill up with zeros - ctx->b[ctx->c++] = 0; - blake2s_compress(ctx, 1); // final block flag = 1 - - // little endian convert and store - for (i = 0; i < ctx->outlen; i++) { - ((uint8_t *) out)[i] = - (ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF; - } -} - -// Convenience function for all-in-one computation. -int blake2s(void *out, size_t outlen, - const void *key, size_t keylen, - const void *in, size_t inlen) -{ - blake2s_ctx ctx; - if (blake2s_init(&ctx, outlen, key, keylen)) - return -1; - blake2s_update(&ctx, in, inlen); - blake2s_final(&ctx, out); - - return 0; -} diff --git a/lib/WireGuard-ESP32/src/crypto/refc/blake2s.h b/lib/WireGuard-ESP32/src/crypto/refc/blake2s.h deleted file mode 100644 index 4b05646..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/blake2s.h +++ /dev/null @@ -1,39 +0,0 @@ -// Taken from RFC7693 - https://tools.ietf.org/html/rfc7693 -// BLAKE2s Hashing Context and API Prototypes -#ifndef _BLAKE2S_H -#define _BLAKE2S_H - -#define BLAKE2S_BLOCK_SIZE 64 - -#include -#include - -// state context -typedef struct { - uint8_t b[64]; // input buffer - uint32_t h[8]; // chained state - uint32_t t[2]; // total number of bytes - size_t c; // pointer for b[] - size_t outlen; // digest size -} blake2s_ctx; - -// Initialize the hashing context "ctx" with optional key "key". -// 1 <= outlen <= 32 gives the digest size in bytes. -// Secret key (also <= 32 bytes) is optional (keylen = 0). -int blake2s_init(blake2s_ctx *ctx, size_t outlen, - const void *key, size_t keylen); // secret key - -// Add "inlen" bytes from "in" into the hash. -void blake2s_update(blake2s_ctx *ctx, // context - const void *in, size_t inlen); // data to be hashed - -// Generate the message digest (size given in init). -// Result placed in "out". -void blake2s_final(blake2s_ctx *ctx, void *out); - -// All-in-one convenience function. -int blake2s(void *out, size_t outlen, // return buffer for digest - const void *key, size_t keylen, // optional secret key - const void *in, size_t inlen); // data to be hashed - -#endif diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20.c b/lib/WireGuard-ESP32/src/crypto/refc/chacha20.c deleted file mode 100644 index 52c4dd6..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/chacha20.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -// RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard -// https://tools.ietf.org/html/rfc7539 -// Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain) -// HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html - -#include "chacha20.h" - -#include -#include -#include "../../crypto.h" - -// 2.3. The ChaCha20 Block Function -// The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 -static const uint32_t CHACHA20_CONSTANT_1 = 0x61707865; -static const uint32_t CHACHA20_CONSTANT_2 = 0x3320646e; -static const uint32_t CHACHA20_CONSTANT_3 = 0x79622d32; -static const uint32_t CHACHA20_CONSTANT_4 = 0x6b206574; - -#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n)))) - -#define PLUS(v,w) (U32V((v) + (w))) -#define PLUSONE(v) (PLUS((v),1)) - -// 2.1. The ChaCha Quarter Round -// 1. a += b; d ^= a; d <<<= 16; -// 2. c += d; b ^= c; b <<<= 12; -// 3. a += b; d ^= a; d <<<= 8; -// 4. c += d; b ^= c; b <<<= 7; - -#define QUARTERROUND(a, b, c, d) \ - a += b; d ^= a; d = ROTL32(d, 16); \ - c += d; b ^= c; b = ROTL32(b, 12); \ - a += b; d ^= a; d = ROTL32(d, 8); \ - c += d; b ^= c; b = ROTL32(b, 7) - -static inline void INNER_BLOCK(uint32_t *block) { - QUARTERROUND(block[0], block[4], block[ 8], block[12]); // column 0 - QUARTERROUND(block[1], block[5], block[ 9], block[13]); // column 1 - QUARTERROUND(block[2], block[6], block[10], block[14]); // column 2 - QUARTERROUND(block[3], block[7], block[11], block[15]); // column 3 - QUARTERROUND(block[0], block[5], block[10], block[15]); // diagonal 1 - QUARTERROUND(block[1], block[6], block[11], block[12]); // diagonal 2 - QUARTERROUND(block[2], block[7], block[ 8], block[13]); // diagonal 3 - QUARTERROUND(block[3], block[4], block[ 9], block[14]); // diagonal 4 -} - -#define TWENTY_ROUNDS(x) ( \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x), \ - INNER_BLOCK(x) \ -) - -// 2.3. The ChaCha20 Block Function -// chacha20_block(key, counter, nonce): -// state = constants | key | counter | nonce -// working_state = state -// for i=1 upto 10 -// inner_block(working_state) -// end -// state += working_state -// return serialize(state) -// end -static void chacha20_block(struct chacha20_ctx *ctx, uint8_t *stream) { - uint32_t working_state[16]; - int i; - - for (i = 0; i < 16; ++i) { - working_state[i] = ctx->state[i]; - } - - TWENTY_ROUNDS(working_state); - - for (i = 0; i < 16; ++i) { - U32TO8_LITTLE(stream + (4 * i), PLUS(working_state[i], ctx->state[i])); - } -} - -void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len) { - uint8_t output[CHACHA20_BLOCK_SIZE]; - int i; - - if (len) { - for (;;) { - chacha20_block(ctx, output); - // Word 12 is a block counter - ctx->state[12] = PLUSONE(ctx->state[12]); - if (len <= 64) { - for (i = 0;i < len;++i) { - out[i] = in[i] ^ output[i]; - } - return; - } - for (i = 0;i < 64;++i) { - out[i] = in[i] ^ output[i]; - } - len -= 64; - out += 64; - in += 64; - } - } -} - - -// 2.3. The ChaCha20 Block Function -// The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 -// The next eight words (4-11) are taken from the 256-bit key by reading the bytes in little-endian order, in 4-byte chunks. -// Word 12 is a block counter. Since each block is 64-byte, a 32-bit word is enough for 256 gigabytes of data. -// Words 13-15 are a nonce, which should not be repeated for the same key. -// For wireguard: "nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter." where counter comes from the Wireguard layer and is separate from the block counter in word 12 -void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce) { - ctx->state[0] = CHACHA20_CONSTANT_1; - ctx->state[1] = CHACHA20_CONSTANT_2; - ctx->state[2] = CHACHA20_CONSTANT_3; - ctx->state[3] = CHACHA20_CONSTANT_4; - ctx->state[4] = U8TO32_LITTLE(key + 0); - ctx->state[5] = U8TO32_LITTLE(key + 4); - ctx->state[6] = U8TO32_LITTLE(key + 8); - ctx->state[7] = U8TO32_LITTLE(key + 12); - ctx->state[8] = U8TO32_LITTLE(key + 16); - ctx->state[9] = U8TO32_LITTLE(key + 20); - ctx->state[10] = U8TO32_LITTLE(key + 24); - ctx->state[11] = U8TO32_LITTLE(key + 28); - ctx->state[12] = 0; - ctx->state[13] = 0; - ctx->state[14] = nonce & 0xFFFFFFFF; - ctx->state[15] = nonce >> 32; -} - -// 2.2. HChaCha20 -// HChaCha20 is initialized the same way as the ChaCha cipher, except that HChaCha20 uses a 128-bit nonce and has no counter. -// After initialization, proceed through the ChaCha rounds as usual. -// Once the 20 ChaCha rounds have been completed, the first 128 bits and last 128 bits of the ChaCha state (both little-endian) are concatenated, and this 256-bit subkey is returned. -void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key) { - uint32_t state[16]; - state[0] = CHACHA20_CONSTANT_1; - state[1] = CHACHA20_CONSTANT_2; - state[2] = CHACHA20_CONSTANT_3; - state[3] = CHACHA20_CONSTANT_4; - state[4] = U8TO32_LITTLE(key + 0); - state[5] = U8TO32_LITTLE(key + 4); - state[6] = U8TO32_LITTLE(key + 8); - state[7] = U8TO32_LITTLE(key + 12); - state[8] = U8TO32_LITTLE(key + 16); - state[9] = U8TO32_LITTLE(key + 20); - state[10] = U8TO32_LITTLE(key + 24); - state[11] = U8TO32_LITTLE(key + 28); - state[12] = U8TO32_LITTLE(nonce + 0); - state[13] = U8TO32_LITTLE(nonce + 4); - state[14] = U8TO32_LITTLE(nonce + 8); - state[15] = U8TO32_LITTLE(nonce + 12); - - TWENTY_ROUNDS(state); - - // Concatenate first/last 128 bits into 256bit output (as little endian) - U32TO8_LITTLE(out + 0, state[0]); - U32TO8_LITTLE(out + 4, state[1]); - U32TO8_LITTLE(out + 8, state[2]); - U32TO8_LITTLE(out + 12, state[3]); - U32TO8_LITTLE(out + 16, state[12]); - U32TO8_LITTLE(out + 20, state[13]); - U32TO8_LITTLE(out + 24, state[14]); - U32TO8_LITTLE(out + 28, state[15]); -} diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20.h b/lib/WireGuard-ESP32/src/crypto/refc/chacha20.h deleted file mode 100644 index aaa8022..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/chacha20.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -// RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard -// https://tools.ietf.org/html/rfc7539 -// Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain) -// HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html -#ifndef _CHACHA20_H_ -#define _CHACHA20_H_ - -#include - -#define CHACHA20_BLOCK_SIZE (64) -#define CHACHA20_KEY_SIZE (32) - -struct chacha20_ctx { - uint32_t state[16]; -}; - -void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce); -void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len); -void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key); - -#endif /* _CHACHA20_H_ */ diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.c b/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.c deleted file mode 100644 index 972e8b1..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -// AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539 -// AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html -#include "chacha20poly1305.h" -#include "chacha20.h" -#include "poly1305-donna.h" - -#include -#include -#include "../../crypto.h" - -#define POLY1305_KEY_SIZE 32 -#define POLY1305_MAC_SIZE 16 - -static const uint8_t zero[CHACHA20_BLOCK_SIZE] = { 0 }; - -// 2.6. Generating the Poly1305 Key Using ChaCha20 -static void generate_poly1305_key(struct poly1305_context *poly1305_state, struct chacha20_ctx *chacha20_state, const uint8_t *key, uint64_t nonce) { - uint8_t block[POLY1305_KEY_SIZE] = {0}; - - // The method is to call the block function with the following parameters: - // - The 256-bit session integrity key is used as the ChaCha20 key. - // - The block counter is set to zero. - // - The protocol will specify a 96-bit or 64-bit nonce - chacha20_init(chacha20_state, key, nonce); - - // We take the first 256 bits or the serialized state, and use those as the one-time Poly1305 key - chacha20(chacha20_state, block, block, sizeof(block)); - - poly1305_init(poly1305_state, block); - - crypto_zero(&block, sizeof(block)); -} - -// 2.8. AEAD Construction (Encryption) -void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) { - struct poly1305_context poly1305_state; - struct chacha20_ctx chacha20_state; - uint8_t block[8]; - size_t padded_len; - - // First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6. - generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce); - - // Next, the ChaCha20 encryption function is called to encrypt the plaintext, using the same key and nonce, and with the initial counter set to 1. - chacha20(&chacha20_state, dst, src, src_len); - - // Finally, the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following: - // - The AAD - poly1305_update(&poly1305_state, ad, ad_len); - // - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16 - padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes - poly1305_update(&poly1305_state, zero, padded_len - ad_len); - // - The ciphertext - poly1305_update(&poly1305_state, dst, src_len); - // - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16. - padded_len = (src_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes - poly1305_update(&poly1305_state, zero, padded_len - src_len); - // - The length of the additional data in octets (as a 64-bit little-endian integer) - U64TO8_LITTLE(block, (uint64_t)ad_len); - poly1305_update(&poly1305_state, block, sizeof(block)); - // - The length of the ciphertext in octets (as a 64-bit little-endian integer). - U64TO8_LITTLE(block, (uint64_t)src_len); - poly1305_update(&poly1305_state, block, sizeof(block)); - - // The output from the AEAD is twofold: - // - A ciphertext of the same length as the plaintext. (above, output of chacha20 into dst) - // - A 128-bit tag, which is the output of the Poly1305 function. (append to dst) - poly1305_finish(&poly1305_state, dst + src_len); - - // Make sure we leave nothing sensitive on the stack - crypto_zero(&chacha20_state, sizeof(chacha20_state)); - crypto_zero(&block, sizeof(block)); -} - -// 2.8. AEAD Construction (Decryption) -bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) { - struct poly1305_context poly1305_state; - struct chacha20_ctx chacha20_state; - uint8_t block[8]; - uint8_t mac[POLY1305_MAC_SIZE]; - size_t padded_len; - int dst_len; - bool result = false; - - // Decryption is similar [to encryption] with the following differences: - // - The roles of ciphertext and plaintext are reversed, so the ChaCha20 encryption function is applied to the ciphertext, producing the plaintext. - // - The Poly1305 function is still run on the AAD and the ciphertext, not the plaintext. - // - The calculated tag is bitwise compared to the received tag. The message is authenticated if and only if the tags match. - - if (src_len >= POLY1305_MAC_SIZE) { - dst_len = src_len - POLY1305_MAC_SIZE; - - // First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6. - generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce); - - // Calculate the MAC before attempting decryption - - // the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following: - // - The AAD - poly1305_update(&poly1305_state, ad, ad_len); - // - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16 - padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes - poly1305_update(&poly1305_state, zero, padded_len - ad_len); - // - The ciphertext (note the Poly1305 function is still run on the AAD and the ciphertext, not the plaintext) - poly1305_update(&poly1305_state, src, dst_len); - // - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16. - padded_len = (dst_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes - poly1305_update(&poly1305_state, zero, padded_len - dst_len); - // - The length of the additional data in octets (as a 64-bit little-endian integer) - U64TO8_LITTLE(block, (uint64_t)ad_len); - poly1305_update(&poly1305_state, block, sizeof(block)); - // - The length of the ciphertext in octets (as a 64-bit little-endian integer). - U64TO8_LITTLE(block, (uint64_t)dst_len); - poly1305_update(&poly1305_state, block, sizeof(block)); - - // The output from the AEAD is twofold: - // - A plaintext of the same length as the ciphertext. (below, output of chacha20 into dst) - // - A 128-bit tag, which is the output of the Poly1305 function. (into mac for checking against passed mac) - poly1305_finish(&poly1305_state, mac); - - - if (crypto_equal(mac, src + dst_len, POLY1305_MAC_SIZE)) { - // mac is correct - do the decryption - // Next, the ChaCha20 encryption function is called to decrypt the ciphertext, using the same key and nonce, and with the initial counter set to 1. - chacha20(&chacha20_state, dst, src, dst_len); - result = true; - } - } - return result; -} - -// AEAD_XChaCha20_Poly1305 -// XChaCha20-Poly1305 is a variant of the ChaCha20-Poly1305 AEAD construction as defined in [RFC7539] that uses a 192-bit nonce instead of a 96-bit nonce. -// The algorithm for XChaCha20-Poly1305 is as follows: -// 1. Calculate a subkey from the first 16 bytes of the nonce and the key, using HChaCha20 (Section 2.2). -// 2. Use the subkey and remaining 8 bytes of the nonce (prefixed with 4 NUL bytes) with AEAD_CHACHA20_POLY1305 from [RFC7539] as normal. The definition for XChaCha20 is given in Section 2.3. -void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) { - uint8_t subkey[CHACHA20_KEY_SIZE]; - uint64_t new_nonce; - - new_nonce = U8TO64_LITTLE(nonce + 16); - - hchacha20(subkey, nonce, key); - chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey); - - crypto_zero(subkey, sizeof(subkey)); -} - -bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) { - uint8_t subkey[CHACHA20_KEY_SIZE]; - uint64_t new_nonce; - bool result; - - new_nonce = U8TO64_LITTLE(nonce + 16); - - hchacha20(subkey, nonce, key); - result = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey); - - crypto_zero(subkey, sizeof(subkey)); - return result; -} diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.h b/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.h deleted file mode 100644 index 83fab07..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -#ifndef _CHACHA20POLY1305_H_ -#define _CHACHA20POLY1305_H_ - -#include -#include -#include - -// Aead(key, counter, plain text, auth text) ChaCha20Poly1305 AEAD, as specified in RFC7539 [17], with its nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter. -// AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539 -void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key); -bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key); - -// Xaead(key, nonce, plain text, auth text) XChaCha20Poly1305 AEAD, with a 24-byte random nonce, instantiated using HChaCha20 [6] and ChaCha20Poly1305. -// AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html -void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key); -bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key); - -#endif /* _CHACHA20POLY1305_H_ */ diff --git a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna-32.h b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna-32.h deleted file mode 100644 index dbcec77..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna-32.h +++ /dev/null @@ -1,220 +0,0 @@ -// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT -/* - poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition -*/ - -#if defined(_MSC_VER) - #define POLY1305_NOINLINE __declspec(noinline) -#elif defined(__GNUC__) - #define POLY1305_NOINLINE __attribute__((noinline)) -#else - #define POLY1305_NOINLINE -#endif - -#define poly1305_block_size 16 - -/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ -typedef struct poly1305_state_internal_t { - unsigned long r[5]; - unsigned long h[5]; - unsigned long pad[4]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; -} poly1305_state_internal_t; - -/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ -static unsigned long -U8TO32(const unsigned char *p) { - return - (((unsigned long)(p[0] & 0xff) ) | - ((unsigned long)(p[1] & 0xff) << 8) | - ((unsigned long)(p[2] & 0xff) << 16) | - ((unsigned long)(p[3] & 0xff) << 24)); -} - -/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ -static void -U32TO8(unsigned char *p, unsigned long v) { - p[0] = (v ) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; - p[3] = (v >> 24) & 0xff; -} - -void -poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; - st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; - st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; - st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; - st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; - - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - - /* save pad for later */ - st->pad[0] = U8TO32(&key[16]); - st->pad[1] = U8TO32(&key[20]); - st->pad[2] = U8TO32(&key[24]); - st->pad[3] = U8TO32(&key[28]); - - st->leftover = 0; - st->final = 0; -} - -static void -poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { - const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ - unsigned long r0,r1,r2,r3,r4; - unsigned long s1,s2,s3,s4; - unsigned long h0,h1,h2,h3,h4; - unsigned long long d0,d1,d2,d3,d4; - unsigned long c; - - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; - r3 = st->r[3]; - r4 = st->r[4]; - - s1 = r1 * 5; - s2 = r2 * 5; - s3 = r3 * 5; - s4 = r4 * 5; - - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - while (bytes >= poly1305_block_size) { - /* h += m[i] */ - h0 += (U8TO32(m+ 0) ) & 0x3ffffff; - h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; - h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; - h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; - h4 += (U8TO32(m+12) >> 8) | hibit; - - /* h *= r */ - d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); - d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); - d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); - d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); - d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); - - /* (partial) h %= p */ - c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; - d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; - d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; - d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; - d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; - h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; - h1 += c; - - m += poly1305_block_size; - bytes -= poly1305_block_size; - } - - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; - st->h[3] = h3; - st->h[4] = h4; -} - -POLY1305_NOINLINE void -poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long h0,h1,h2,h3,h4,c; - unsigned long g0,g1,g2,g3,g4; - unsigned long long f; - unsigned long mask; - - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i++] = 1; - for (; i < poly1305_block_size; i++) - st->buffer[i] = 0; - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } - - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - c = h1 >> 26; h1 = h1 & 0x3ffffff; - h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; - h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; - h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; - h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; - h1 += c; - - /* compute h + -p */ - g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; - g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; - g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; - g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; - g4 = h4 + c - (1UL << 26); - - /* select h if h < p, or h + -p if h >= p */ - mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; - g0 &= mask; - g1 &= mask; - g2 &= mask; - g3 &= mask; - g4 &= mask; - mask = ~mask; - h0 = (h0 & mask) | g0; - h1 = (h1 & mask) | g1; - h2 = (h2 & mask) | g2; - h3 = (h3 & mask) | g3; - h4 = (h4 & mask) | g4; - - /* h = h % (2^128) */ - h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; - h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; - h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; - h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; - - /* mac = (h + pad) % (2^128) */ - f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; - f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; - f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; - f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; - - U32TO8(mac + 0, h0); - U32TO8(mac + 4, h1); - U32TO8(mac + 8, h2); - U32TO8(mac + 12, h3); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->r[3] = 0; - st->r[4] = 0; - st->pad[0] = 0; - st->pad[1] = 0; - st->pad[2] = 0; - st->pad[3] = 0; -} - diff --git a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.c b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.c deleted file mode 100644 index 31ad7c5..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.c +++ /dev/null @@ -1,41 +0,0 @@ -// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT - -#include "poly1305-donna.h" -#include "poly1305-donna-32.h" - -void -poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - size_t i; - - /* handle leftover */ - if (st->leftover) { - size_t want = (poly1305_block_size - st->leftover); - if (want > bytes) - want = bytes; - for (i = 0; i < want; i++) - st->buffer[st->leftover + i] = m[i]; - bytes -= want; - m += want; - st->leftover += want; - if (st->leftover < poly1305_block_size) - return; - poly1305_blocks(st, st->buffer, poly1305_block_size); - st->leftover = 0; - } - - /* process full blocks */ - if (bytes >= poly1305_block_size) { - size_t want = (bytes & ~(poly1305_block_size - 1)); - poly1305_blocks(st, m, want); - m += want; - bytes -= want; - } - - /* store leftover */ - if (bytes) { - for (i = 0; i < bytes; i++) - st->buffer[st->leftover + i] = m[i]; - st->leftover += bytes; - } -} diff --git a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.h b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.h deleted file mode 100644 index 955bca9..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.h +++ /dev/null @@ -1,16 +0,0 @@ -// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT -#ifndef POLY1305_DONNA_H -#define POLY1305_DONNA_H - -#include - -typedef struct poly1305_context { - size_t aligner; - unsigned char opaque[136]; -} poly1305_context; - -void poly1305_init(poly1305_context *ctx, const unsigned char key[32]); -void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes); -void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]); - -#endif /* POLY1305_DONNA_H */ diff --git a/lib/WireGuard-ESP32/src/crypto/refc/x25519-license.txt b/lib/WireGuard-ESP32/src/crypto/refc/x25519-license.txt deleted file mode 100644 index 81e4862..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/x25519-license.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2016 Cryptography Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lib/WireGuard-ESP32/src/crypto/refc/x25519.c b/lib/WireGuard-ESP32/src/crypto/refc/x25519.c deleted file mode 100644 index 3b5ebe3..0000000 --- a/lib/WireGuard-ESP32/src/crypto/refc/x25519.c +++ /dev/null @@ -1,448 +0,0 @@ -// Taken from https://sourceforge.net/p/strobe (MIT Licence) -/** - * @cond internal - * @file x25519.c - * @copyright - * Copyright (c) 2015-2016 Cryptography Research, Inc. \n - * Released under the MIT License. See LICENSE.txt for license information. - * @author Mike Hamburg - * @brief Key exchange and signatures based on X25519. - */ -#include -#include "x25519.h" -//#include "strobe.h" -//#include "strobe_config.h" -// STROBE header replacement -#include -#define X25519_WBITS 32 -#define X25519_SUPPORT_SIGN 0 -#define X25519_MEMCPY_PARAMS 1 -#define X25519_USE_POWER_CHAIN 1 -#if BYTE_ORDER == LITTLE_ENDIAN -static inline uint32_t eswap_letoh_32(uint32_t w) { return w; } -#else -#error "Fix eswap() on non-little-endian machine" -#endif - -#if X25519_WBITS == 64 - typedef uint64_t limb_t; - typedef __uint128_t dlimb_t; - typedef __int128_t sdlimb_t; - #define eswap_limb eswap_letoh_64 - #define LIMB(x) x##ull -#elif X25519_WBITS == 32 - typedef uint32_t limb_t; - typedef uint64_t dlimb_t; - typedef int64_t sdlimb_t; - #define eswap_limb eswap_letoh_32 - #define LIMB(x) (uint32_t)(x##ull),(uint32_t)((x##ull)>>32) -#else - #error "Need to know X25519_WBITS" -#endif - -#define NLIMBS (256/X25519_WBITS) -typedef limb_t fe[NLIMBS]; - -#if X25519_SUPPORT_SIGN -typedef limb_t scalar_t[NLIMBS]; -static const limb_t MONTGOMERY_FACTOR = (limb_t)0xd2b51da312547e1bull; -static const scalar_t sc_p = { - LIMB(0x5812631a5cf5d3ed), LIMB(0x14def9dea2f79cd6), - LIMB(0x0000000000000000), LIMB(0x1000000000000000) -}, sc_r2 = { - LIMB(0xa40611e3449c0f01), LIMB(0xd00e1ba768859347), - LIMB(0xceec73d217f5be65), LIMB(0x0399411b7c309a3d) -}; -#endif - -static inline limb_t umaal( - limb_t *carry, limb_t acc, limb_t mand, limb_t mier -) { - dlimb_t tmp = (dlimb_t) mand * mier + acc + *carry; - *carry = tmp >> X25519_WBITS; - return tmp; -} - -/* These functions are implemented in terms of umaal on ARM */ -static inline limb_t adc(limb_t *carry, limb_t acc, limb_t mand) { - dlimb_t total = (dlimb_t)*carry + acc + mand; - *carry = total>>X25519_WBITS; - return total; -} - -static inline limb_t adc0(limb_t *carry, limb_t acc) { - dlimb_t total = (dlimb_t)*carry + acc; - *carry = total>>X25519_WBITS; - return total; -} - -/* Precondition: carry is small. - * Invariant: result of propagate is < 2^255 + 1 word - * In particular, always less than 2p. - * Also, output x >= min(x,19) - */ -static void propagate(fe x, limb_t over) { - unsigned i; - over = x[NLIMBS-1]>>(X25519_WBITS-1) | over<<1; - x[NLIMBS-1] &= ~((limb_t)1<<(X25519_WBITS-1)); - - limb_t carry = over * 19; - for (i=0; i>= X25519_WBITS; - } - propagate(out,1+carry); -} - -static void __attribute__((unused)) -swapin(limb_t *x, const uint8_t *in) { - memcpy(x,in,sizeof(fe)); - unsigned i; - for (i=0; i>= X25519_WBITS; - } - return ((dlimb_t)res - 1) >> X25519_WBITS; -} - -static const limb_t a24[1]={121665}; - -static void ladder_part1(fe xs[5]) { - limb_t *x2 = xs[0], *z2=xs[1],*x3=xs[2],*z3=xs[3],*t1=xs[4]; - add(t1,x2,z2); // t1 = A - sub(z2,x2,z2); // z2 = B - add(x2,x3,z3); // x2 = C - sub(z3,x3,z3); // z3 = D - mul1(z3,t1); // z3 = DA - mul1(x2,z2); // x3 = BC - add(x3,z3,x2); // x3 = DA+CB - sub(z3,z3,x2); // z3 = DA-CB - sqr1(t1); // t1 = AA - sqr1(z2); // z2 = BB - sub(x2,t1,z2); // x2 = E = AA-BB - mul(z2,x2,a24,sizeof(a24)/sizeof(a24[0])); // z2 = E*a24 - add(z2,z2,t1); // z2 = E*a24 + AA -} -static void ladder_part2(fe xs[5], const fe x1) { - limb_t *x2 = xs[0], *z2=xs[1],*x3=xs[2],*z3=xs[3],*t1=xs[4]; - sqr1(z3); // z3 = (DA-CB)^2 - mul1(z3,x1); // z3 = x1 * (DA-CB)^2 - sqr1(x3); // x3 = (DA+CB)^2 - mul1(z2,x2); // z2 = AA*(E*a24+AA) - sub(x2,t1,x2); // x2 = BB again - mul1(x2,t1); // x2 = AA*BB -} - -static void x25519_core(fe xs[5], const uint8_t scalar[X25519_BYTES], const uint8_t *x1, int clamp) { - int i; -#if X25519_MEMCPY_PARAMS - fe x1i; - swapin(x1i,x1); - x1 = (const uint8_t *)x1; -#endif - limb_t swap = 0; - limb_t *x2 = xs[0],*x3=xs[2],*z3=xs[3]; - memset(xs,0,4*sizeof(fe)); - x2[0] = z3[0] = 1; - memcpy(x3,x1,sizeof(fe)); - - for (i=255; i>=0; i--) { - uint8_t bytei = scalar[i/8]; - if (clamp) { - if (i/8 == 0) { - bytei &= ~7; - } else if (i/8 == X25519_BYTES-1) { - bytei &= 0x7F; - bytei |= 0x40; - } - } - limb_t doswap = -(limb_t)((bytei>>(i%8)) & 1); - condswap(x2,x3,swap^doswap); - swap = doswap; - - ladder_part1(xs); - ladder_part2(xs,(const limb_t *)x1); - } - condswap(x2,x3,swap); -} - -int x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES], const uint8_t x1[X25519_BYTES], int clamp) { - fe xs[5]; - x25519_core(xs,scalar,x1,clamp); - - /* Precomputed inversion chain */ - limb_t *x2 = xs[0], *z2=xs[1], *z3=xs[3]; - int i; - - limb_t *prev = z2; -#if X25519_USE_POWER_CHAIN - static const struct { uint8_t a,c,n; } steps[13] = { - {2,1,1 }, - {2,1,1 }, - {4,2,3 }, - {2,4,6 }, - {3,1,1 }, - {3,2,12 }, - {4,3,25 }, - {2,3,25 }, - {2,4,50 }, - {3,2,125}, - {3,1,2 }, - {3,1,2 }, - {3,1,1 } - }; - for (i=0; i<13; i++) { - int j; - limb_t *a = xs[steps[i].a]; - for (j=steps[i].n; j>0; j--) { - sqr(a, prev); - prev = a; - } - mul1(a,xs[steps[i].c]); - } -#else - /* Raise to the p-2 = 0x7f..ffeb */ - for (i=253; i>=0; i--) { - sqr(z3,prev); - prev = z3; - if (i>=8 || (0xeb>>i & 1)) { - mul1(z3,z2); - } - } -#endif - - /* Here prev = z3 */ - /* x2 /= z2 */ -#if X25519_MEMCPY_PARAMS - mul1(x2,z3); - int ret = canon(x2); - swapout(out,x2); -#else - mul((limb_t *)out, x2, z3, NLIMBS); - int ret = canon((limb_t*)out); -#endif - if (clamp) return ret; - else return 0; -} - -const uint8_t X25519_BASE_POINT[X25519_BYTES] = {9}; - -#if X25519_SUPPORT_VERIFY -static limb_t x25519_verify_core( - fe xs[5], - const limb_t *other1, - const uint8_t other2[X25519_BYTES] -) { - limb_t *z2=xs[1],*x3=xs[2],*z3=xs[3]; -#if X25519_MEMCPY_PARAMS - fe xo2; - swapin(xo2,other2); -#else - const limb_t *xo2 = (const limb_t *)other2; -#endif - - memcpy(x3, other1, 2*sizeof(fe)); - - ladder_part1(xs); - - /* Here z2 = t2^2 */ - mul1(z2,other1); - mul1(z2,other1+NLIMBS); - mul1(z2,xo2); - const limb_t sixteen = 16; - mul (z2,z2,&sixteen,1); - - mul1(z3,xo2); - sub(z3,z3,x3); - sqr1(z3); - - /* check equality */ - sub(z3,z3,z2); - - /* If canon(z2) then both sides are zero. - * If canon(z3) then the two sides are equal. - * - * Reject sigs where both sides are zero, because - * that can happen if an input causes the ladder to - * return 0/0. - */ - return canon(z2) | ~canon(z3); -} - -int x25519_verify_p2 ( - const uint8_t response[X25519_BYTES], - const uint8_t challenge[X25519_BYTES], - const uint8_t eph[X25519_BYTES], - const uint8_t pub[X25519_BYTES] -) { - fe xs[7]; - x25519_core(&xs[0],challenge,pub,0); - x25519_core(&xs[2],response,X25519_BASE_POINT,0); - return x25519_verify_core(&xs[2],xs[0],eph); -} -#endif // X25519_SUPPORT_VERIFY - -#if X25519_SUPPORT_SIGN -static void sc_montmul ( - scalar_t out, - const scalar_t a, - const scalar_t b -) { - /** - * OK, so carry bounding. We're using a high carry, so that the - * inputs don't have to be reduced. - * - * First montmul: output < (M^2 + Mp)/M = M+p, subtract p, < M. This gets rid of high carry. - * Second montmul, by r^2 mod p < p: output < (Mp + Mp)/M = 2p, subtract p, < p, done. - */ - unsigned i,j; - limb_t hic = 0; - for (i=0; i0) out[j-1] = acc; - } - - /* Add two carry registers and high carry */ - out[NLIMBS-1] = adc(&hic, carry, carry2); - } - - /* Reduce */ - sdlimb_t scarry = 0; - for (i=0; i>= X25519_WBITS; - } - limb_t need_add = -(scarry + hic); - - limb_t carry = 0; - for (i=0; i -#include "crypto.h" -#include "lwip/sys.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "esp_system.h" - -static struct mbedtls_ctr_drbg_context random_context; -static struct mbedtls_entropy_context entropy_context; -static bool is_platform_initialized = false; - -static int entropy_hw_random_source( void *data, unsigned char *output, size_t len, size_t *olen ) { - esp_fill_random(output, len); - *olen = len; - return 0; -} - -void wireguard_platform_init() { - if( is_platform_initialized ) return; - - mbedtls_entropy_init(&entropy_context); - mbedtls_ctr_drbg_init(&random_context); - mbedtls_entropy_add_source(&entropy_context, entropy_hw_random_source, NULL, 134, MBEDTLS_ENTROPY_SOURCE_STRONG); - mbedtls_ctr_drbg_seed(&random_context, mbedtls_entropy_func, &entropy_context, NULL, 0); - - is_platform_initialized = true; -} - -void wireguard_random_bytes(void *bytes, size_t size) { - uint8_t *out = (uint8_t *)bytes; - mbedtls_ctr_drbg_random(&random_context, bytes, size); -} - -uint32_t wireguard_sys_now() { - // Default to the LwIP system time - return sys_now(); -} - -void wireguard_tai64n_now(uint8_t *output) { - // See https://cr.yp.to/libtai/tai64.html - // 64 bit seconds from 1970 = 8 bytes - // 32 bit nano seconds from current second - - // Get timestamp. Note that the timestamp must be synced by NTP, - // or at least preserved in NVS, not to go back after reset. - // Otherwise, the WireGuard remote peer rejects handshake. - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t millis = (tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL)); - - // Split into seconds offset + nanos - uint64_t seconds = 0x400000000000000aULL + (millis / 1000); - uint32_t nanos = (millis % 1000) * 1000; - U64TO8_BIG(output + 0, seconds); - U32TO8_BIG(output + 8, nanos); -} - -bool wireguard_is_under_load() { - return false; -} - diff --git a/lib/WireGuard-ESP32/src/wireguard-platform.h b/lib/WireGuard-ESP32/src/wireguard-platform.h deleted file mode 100644 index f54ec4a..0000000 --- a/lib/WireGuard-ESP32/src/wireguard-platform.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * The original license is below: - * - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -#ifndef _WIREGUARD_PLATFORM_H_ -#define _WIREGUARD_PLATFORM_H_ - -#include -#include -#include - -// Peers are allocated statically inside the device structure to avoid malloc -#define WIREGUARD_MAX_PEERS 1 -#define WIREGUARD_MAX_SRC_IPS 2 - -// Per device limit on accepting (valid) initiation requests - per peer -#define MAX_INITIATIONS_PER_SECOND (2) - -// -// Your platform integration needs to provide implementations of these functions -// - -void wireguard_platform_init(); - -// The number of milliseconds since system boot - for LwIP systems this could be sys_now() -uint32_t wireguard_sys_now(); - -// Fill the supplied buffer with random data - random data is used for generating new session keys periodically -void wireguard_random_bytes(void *bytes, size_t size); - -// Get the current time in tai64n format - 8 byte seconds, 4 byte nano sub-second - see https://cr.yp.to/libtai/tai64.html for details -// Output buffer passed is 12 bytes -// The Wireguard implementation doesn't strictly need this to be a time, but instead an increasing value -// The remote end of the Wireguard tunnel will use this value in handshake replay detection -void wireguard_tai64n_now(uint8_t *output); - -// Is the system under load - i.e. should we generate cookie reply message in response to initiation messages -bool wireguard_is_under_load(); - -#endif /* _WIREGUARD_PLATFORM_H_ */ diff --git a/lib/WireGuard-ESP32/src/wireguard.c b/lib/WireGuard-ESP32/src/wireguard.c deleted file mode 100644 index ca86e9b..0000000 --- a/lib/WireGuard-ESP32/src/wireguard.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* - * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * The original license is below: - * - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -#include "wireguard.h" - -#include -#include -#include - -#include "crypto.h" - -// For HMAC calculation -#define WIREGUARD_BLAKE2S_BLOCK_SIZE (64) - -// 5.4 Messages -// Constants -static const uint8_t CONSTRUCTION[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; // The UTF-8 string literal "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s", 37 bytes of output -static const uint8_t IDENTIFIER[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; // The UTF-8 string literal "WireGuard v1 zx2c4 Jason@zx2c4.com", 34 bytes of output -static const uint8_t LABEL_MAC1[8] = "mac1----"; // Label-Mac1 The UTF-8 string literal "mac1----", 8 bytes of output. -static const uint8_t LABEL_COOKIE[8] = "cookie--"; // Label-Cookie The UTF-8 string literal "cookie--", 8 bytes of output - -static const char *base64_lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static const uint8_t zero_key[WIREGUARD_PUBLIC_KEY_LEN] = { 0 }; - -// Calculated in wireguard_init -static uint8_t construction_hash[WIREGUARD_HASH_LEN]; -static uint8_t identifier_hash[WIREGUARD_HASH_LEN]; - - -void wireguard_init() { - wireguard_blake2s_ctx ctx; - // Pre-calculate chaining key hash - wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); - wireguard_blake2s_update(&ctx, CONSTRUCTION, sizeof(CONSTRUCTION)); - wireguard_blake2s_final(&ctx, construction_hash); - // Pre-calculate initial handshake hash - uses construction_hash calculated above - wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); - wireguard_blake2s_update(&ctx, construction_hash, sizeof(construction_hash)); - wireguard_blake2s_update(&ctx, IDENTIFIER, sizeof(IDENTIFIER)); - wireguard_blake2s_final(&ctx, identifier_hash); -} - -struct wireguard_peer *peer_alloc(struct wireguard_device *device) { - struct wireguard_peer *result = NULL; - struct wireguard_peer *tmp; - int x; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - tmp = &device->peers[x]; - if (!tmp->valid) { - result = tmp; - break; - } - } - return result; -} - -struct wireguard_peer *peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key) { - struct wireguard_peer *result = NULL; - struct wireguard_peer *tmp; - int x; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - tmp = &device->peers[x]; - if (tmp->valid) { - if (memcmp(tmp->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN) == 0) { - result = tmp; - break; - } - } - } - return result; -} - -uint8_t wireguard_peer_index(struct wireguard_device *device, struct wireguard_peer *peer) { - uint8_t result = 0xFF; - uint8_t x; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - if (peer == &device->peers[x]) { - result = x; - break; - } - } - return result; -} - -struct wireguard_peer *peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index) { - struct wireguard_peer *result = NULL; - if (peer_index < WIREGUARD_MAX_PEERS) { - if (device->peers[peer_index].valid) { - result = &device->peers[peer_index]; - } - } - return result; -} - -struct wireguard_peer *peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver) { - struct wireguard_peer *result = NULL; - struct wireguard_peer *tmp; - int x; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - tmp = &device->peers[x]; - if (tmp->valid) { - if ((tmp->curr_keypair.valid && (tmp->curr_keypair.local_index == receiver)) || - (tmp->next_keypair.valid && (tmp->next_keypair.local_index == receiver)) || - (tmp->prev_keypair.valid && (tmp->prev_keypair.local_index == receiver)) - ) { - result = tmp; - break; - } - } - } - return result; -} - -struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver) { - struct wireguard_peer *result = NULL; - struct wireguard_peer *tmp; - int x; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - tmp = &device->peers[x]; - if (tmp->valid) { - if (tmp->handshake.valid && tmp->handshake.initiator && (tmp->handshake.local_index == receiver)) { - result = tmp; - break; - } - } - } - return result; -} - -bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds) { - uint32_t diff = wireguard_sys_now() - created_millis; - return (diff >= (valid_seconds * 1000)); -} - - -static void generate_cookie_secret(struct wireguard_device *device) { - wireguard_random_bytes(device->cookie_secret, WIREGUARD_HASH_LEN); - device->cookie_secret_millis = wireguard_sys_now(); -} - -static void generate_peer_cookie(struct wireguard_device *device, uint8_t *cookie, uint8_t *source_addr_port, size_t source_length) { - wireguard_blake2s_ctx ctx; - - if (wireguard_expired(device->cookie_secret_millis, COOKIE_SECRET_MAX_AGE)) { - // Generate new random bytes - generate_cookie_secret(device); - } - - // Mac(key, input) Keyed-Blake2s(key, input, 16), the keyed MAC variant of the BLAKE2s hash function, returning 16 bytes of output - wireguard_blake2s_init(&ctx, WIREGUARD_COOKIE_LEN, device->cookie_secret, WIREGUARD_HASH_LEN); - // 5.4.7 Under Load: Cookie Reply Message - // Mix in the IP address and port - have the IP layer pass this in as byte array to avoid using Lwip specific APIs in this module - if ((source_addr_port) && (source_length > 0)) { - wireguard_blake2s_update(&ctx, source_addr_port, source_length); - } - wireguard_blake2s_final(&ctx, cookie); -} - -static void wireguard_mac(uint8_t *dst, const void *message, size_t len, const uint8_t *key, size_t keylen) { - wireguard_blake2s(dst, WIREGUARD_COOKIE_LEN, key, keylen, message, len); -} - -static void wireguard_mac_key(uint8_t *key, const uint8_t *public_key, const uint8_t *label, size_t label_len) { - blake2s_ctx ctx; - blake2s_init(&ctx, WIREGUARD_SESSION_KEY_LEN, NULL, 0); - blake2s_update(&ctx, label, label_len); - blake2s_update(&ctx, public_key, WIREGUARD_PUBLIC_KEY_LEN); - blake2s_final(&ctx, key); -} - -static void wireguard_mix_hash(uint8_t *hash, const uint8_t *src, size_t src_len) { - wireguard_blake2s_ctx ctx; - wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); - wireguard_blake2s_update(&ctx, hash, WIREGUARD_HASH_LEN); - wireguard_blake2s_update(&ctx, src, src_len); - wireguard_blake2s_final(&ctx, hash); -} - -static void wireguard_hmac(uint8_t *digest, const uint8_t *key, size_t key_len, const uint8_t *text, size_t text_len) { - // Adapted from appendix example in RFC2104 to use BLAKE2S instead of MD5 - https://tools.ietf.org/html/rfc2104 - wireguard_blake2s_ctx ctx; - uint8_t k_ipad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // inner padding - key XORd with ipad - uint8_t k_opad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // outer padding - key XORd with opad - - uint8_t tk[WIREGUARD_HASH_LEN]; - int i; - // if key is longer than BLAKE2S_BLOCK_SIZE bytes reset it to key=BLAKE2S(key) - if (key_len > WIREGUARD_BLAKE2S_BLOCK_SIZE) { - wireguard_blake2s_ctx tctx; - wireguard_blake2s_init(&tctx, WIREGUARD_HASH_LEN, NULL, 0); - wireguard_blake2s_update(&tctx, key, key_len); - wireguard_blake2s_final(&tctx, tk); - key = tk; - key_len = WIREGUARD_HASH_LEN; - } - - // the HMAC transform looks like: - // HASH(K XOR opad, HASH(K XOR ipad, text)) - // where K is an n byte key - // ipad is the byte 0x36 repeated BLAKE2S_BLOCK_SIZE times - // opad is the byte 0x5c repeated BLAKE2S_BLOCK_SIZE times - // and text is the data being protected - memset(k_ipad, 0, sizeof(k_ipad)); - memset(k_opad, 0, sizeof(k_opad)); - memcpy(k_ipad, key, key_len); - memcpy(k_opad, key, key_len); - - // XOR key with ipad and opad values - for (i=0; i < WIREGUARD_BLAKE2S_BLOCK_SIZE; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - // perform inner HASH - wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 1st pass - wireguard_blake2s_update(&ctx, k_ipad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with inner pad - wireguard_blake2s_update(&ctx, text, text_len); // then text of datagram - wireguard_blake2s_final(&ctx, digest); // finish up 1st pass - - // perform outer HASH - wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 2nd pass - wireguard_blake2s_update(&ctx, k_opad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with outer pad - wireguard_blake2s_update(&ctx, digest, WIREGUARD_HASH_LEN); // then results of 1st hash - wireguard_blake2s_final(&ctx, digest); // finish up 2nd pass -} - -static void wireguard_kdf1(uint8_t *tau1, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) { - uint8_t tau0[WIREGUARD_HASH_LEN]; - uint8_t output[WIREGUARD_HASH_LEN + 1]; - - // tau0 = Hmac(key, input) - wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len); - // tau1 := Hmac(tau0, 0x1) - output[0] = 1; - wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1); - memcpy(tau1, output, WIREGUARD_HASH_LEN); - - // Wipe intermediates - crypto_zero(tau0, sizeof(tau0)); - crypto_zero(output, sizeof(output)); -} - -static void wireguard_kdf2(uint8_t *tau1, uint8_t *tau2, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) { - uint8_t tau0[WIREGUARD_HASH_LEN]; - uint8_t output[WIREGUARD_HASH_LEN + 1]; - - // tau0 = Hmac(key, input) - wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len); - // tau1 := Hmac(tau0, 0x1) - output[0] = 1; - wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1); - memcpy(tau1, output, WIREGUARD_HASH_LEN); - - // tau2 := Hmac(tau0,tau1 || 0x2) - output[WIREGUARD_HASH_LEN] = 2; - wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1); - memcpy(tau2, output, WIREGUARD_HASH_LEN); - - // Wipe intermediates - crypto_zero(tau0, sizeof(tau0)); - crypto_zero(output, sizeof(output)); -} - -static void wireguard_kdf3(uint8_t *tau1, uint8_t *tau2, uint8_t *tau3, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) { - uint8_t tau0[WIREGUARD_HASH_LEN]; - uint8_t output[WIREGUARD_HASH_LEN + 1]; - - // tau0 = Hmac(key, input) - wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len); - // tau1 := Hmac(tau0, 0x1) - output[0] = 1; - wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1); - memcpy(tau1, output, WIREGUARD_HASH_LEN); - - // tau2 := Hmac(tau0,tau1 || 0x2) - output[WIREGUARD_HASH_LEN] = 2; - wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1); - memcpy(tau2, output, WIREGUARD_HASH_LEN); - - // tau3 := Hmac(tau0,tau1,tau2 || 0x3) - output[WIREGUARD_HASH_LEN] = 3; - wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1); - memcpy(tau3, output, WIREGUARD_HASH_LEN); - - // Wipe intermediates - crypto_zero(tau0, sizeof(tau0)); - crypto_zero(output, sizeof(output)); -} - -bool wireguard_check_replay(struct wireguard_keypair *keypair, uint64_t seq) { - // Implementation of packet replay window - as per RFC2401 - // Adapted from code in Appendix C at https://tools.ietf.org/html/rfc2401 - uint32_t diff; - bool result = false; - size_t ReplayWindowSize = sizeof(keypair->replay_bitmap); // 32 bits - - if (seq != 0) { - if (seq > keypair->replay_counter) { - // new larger sequence number - diff = seq - keypair->replay_counter; - if (diff < ReplayWindowSize) { - // In window - keypair->replay_bitmap <<= diff; - // set bit for this packet - keypair->replay_bitmap |= 1; - } else { - // This packet has a "way larger" - keypair->replay_bitmap = 1; - } - keypair->replay_counter = seq; - // larger is good - result = true; - } else { - diff = keypair->replay_counter - seq; - if (diff < ReplayWindowSize) { - if (keypair->replay_bitmap & ((uint32_t)1 << diff)) { - // already seen - } else { - // mark as seen - keypair->replay_bitmap |= ((uint32_t)1 << diff); - // out of order but good - result = true; - } - } else { - // too old or wrapped - } - } - } else { - // first == 0 or wrapped - } - return result; -} - -struct wireguard_keypair *get_peer_keypair_for_idx(struct wireguard_peer *peer, uint32_t idx) { - if (peer->curr_keypair.valid && peer->curr_keypair.local_index == idx) { - return &peer->curr_keypair; - } else if (peer->next_keypair.valid && peer->next_keypair.local_index == idx) { - return &peer->next_keypair; - } else if (peer->prev_keypair.valid && peer->prev_keypair.local_index == idx) { - return &peer->prev_keypair; - } - return NULL; -} - -static uint32_t wireguard_generate_unique_index(struct wireguard_device *device) { - // We need a random 32-bit number but make sure it's not already been used in the context of this device - uint32_t result; - uint8_t buf[4]; - int x; - struct wireguard_peer *peer; - bool existing; - do { - do { - wireguard_random_bytes(buf, 4); - result = U8TO32_LITTLE(buf); - } while ((result == 0) || (result == 0xFFFFFFFF)); // Don't allow 0 or 0xFFFFFFFF as valid values - - existing = false; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - peer = &device->peers[x]; - existing = (result == peer->curr_keypair.local_index) || - (result == peer->prev_keypair.local_index) || - (result == peer->next_keypair.local_index) || - (result == peer->handshake.local_index); - - } - } while (existing); - - return result; -} - -static void wireguard_clamp_private_key(uint8_t *key) { - key[0] &= 248; - key[31] = (key[31] & 127) | 64; -} - -static void wireguard_generate_private_key(uint8_t *key) { - wireguard_random_bytes(key, WIREGUARD_PRIVATE_KEY_LEN); - wireguard_clamp_private_key(key); -} - -static bool wireguard_generate_public_key(uint8_t *public_key, const uint8_t *private_key) { - static const uint8_t basepoint[WIREGUARD_PUBLIC_KEY_LEN] = { 9 }; - bool result = false; - if (memcmp(private_key, zero_key, WIREGUARD_PUBLIC_KEY_LEN) != 0) { - result = (wireguard_x25519(public_key, private_key, basepoint) == 0); - } - return result; -} - -bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1) { - bool result = false; - uint8_t calculated[WIREGUARD_COOKIE_LEN]; - wireguard_mac(calculated, data, len, device->label_mac1_key, WIREGUARD_SESSION_KEY_LEN); - if (crypto_equal(calculated, mac1, WIREGUARD_COOKIE_LEN)) { - result = true; - } - return result; -} - -bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2) { - bool result = false; - uint8_t cookie[WIREGUARD_COOKIE_LEN]; - uint8_t calculated[WIREGUARD_COOKIE_LEN]; - - generate_peer_cookie(device, cookie, source_addr_port, source_length); - - wireguard_mac(calculated, data, len, cookie, WIREGUARD_COOKIE_LEN); - if (crypto_equal(calculated, mac2, WIREGUARD_COOKIE_LEN)) { - result = true; - } - return result; -} - -void handshake_destroy(struct wireguard_handshake *handshake) { - crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN); - crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - crypto_zero(handshake->hash, WIREGUARD_HASH_LEN); - crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN); - handshake->remote_index = 0; - handshake->local_index = 0; - handshake->valid = false; -} - -void keypair_destroy(struct wireguard_keypair *keypair) { - crypto_zero(keypair, sizeof(struct wireguard_keypair)); - keypair->valid = false; -} - -void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair) { - bool key_is_next = (received_keypair == &peer->next_keypair); - if (key_is_next) { - peer->prev_keypair = peer->curr_keypair; - peer->curr_keypair = peer->next_keypair; - keypair_destroy(&peer->next_keypair); - } -} - -static void add_new_keypair(struct wireguard_peer *peer, struct wireguard_keypair new_keypair) { - if (new_keypair.initiator) { - if (peer->next_keypair.valid) { - peer->prev_keypair = peer->next_keypair; - keypair_destroy(&peer->next_keypair); - } else { - peer->prev_keypair = peer->curr_keypair; - } - peer->curr_keypair = new_keypair; - } else { - peer->next_keypair = new_keypair; - keypair_destroy(&peer->prev_keypair); - } -} - -void wireguard_start_session(struct wireguard_peer *peer, bool initiator) { - struct wireguard_handshake *handshake = &peer->handshake; - struct wireguard_keypair new_keypair; - - crypto_zero(&new_keypair, sizeof(struct wireguard_keypair)); - new_keypair.initiator = initiator; - new_keypair.local_index = handshake->local_index; - new_keypair.remote_index = handshake->remote_index; - - new_keypair.keypair_millis = wireguard_sys_now(); - new_keypair.sending_valid = true; - new_keypair.receiving_valid = true; - - // 5.4.5 Transport Data Key Derivation - // (Tsendi = Trecvr, Trecvi = Tsendr) := Kdf2(Ci = Cr,E) - if (new_keypair.initiator) { - wireguard_kdf2(new_keypair.sending_key, new_keypair.receiving_key, handshake->chaining_key, NULL, 0); - } else { - wireguard_kdf2(new_keypair.receiving_key, new_keypair.sending_key, handshake->chaining_key, NULL, 0); - } - - new_keypair.replay_bitmap = 0; - new_keypair.replay_counter = 0; - - new_keypair.last_tx = 0; - new_keypair.last_rx = 0; // No packets received yet - - new_keypair.valid = true; - - // Eprivi = Epubi = Eprivr = Epubr = Ci = Cr := E - crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN); - crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - crypto_zero(handshake->hash, WIREGUARD_HASH_LEN); - crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN); - handshake->remote_index = 0; - handshake->local_index = 0; - handshake->valid = false; - - add_new_keypair(peer, new_keypair); -} - -uint8_t wireguard_get_message_type(const uint8_t *data, size_t len) { - uint8_t result = MESSAGE_INVALID; - if (len >= 4) { - if ((data[1] == 0) && (data[2] == 0) && (data[3] == 0)) { - switch (data[0]) { - case MESSAGE_HANDSHAKE_INITIATION: - if (len == sizeof(struct message_handshake_initiation)) { - result = MESSAGE_HANDSHAKE_INITIATION; - } - break; - case MESSAGE_HANDSHAKE_RESPONSE: - if (len == sizeof(struct message_handshake_response)) { - result = MESSAGE_HANDSHAKE_RESPONSE; - } - break; - case MESSAGE_COOKIE_REPLY: - if (len == sizeof(struct message_cookie_reply)) { - result = MESSAGE_COOKIE_REPLY; - } - break; - case MESSAGE_TRANSPORT_DATA: - if (len >= sizeof(struct message_transport_data) + WIREGUARD_AUTHTAG_LEN) { - result = MESSAGE_TRANSPORT_DATA; - } - break; - default: - break; - } - } - } - return result; -} - -struct wireguard_peer *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg) { - struct wireguard_peer *ret_peer = NULL; - struct wireguard_peer *peer = NULL; - struct wireguard_handshake *handshake; - uint8_t key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t chaining_key[WIREGUARD_HASH_LEN]; - uint8_t hash[WIREGUARD_HASH_LEN]; - uint8_t s[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t e[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t t[WIREGUARD_TAI64N_LEN]; - uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; - uint32_t now; - bool rate_limit; - bool replay; - - // We are the responder, other end is the initiator - - // Ci := Hash(Construction) (precalculated hash) - memcpy(chaining_key, construction_hash, WIREGUARD_HASH_LEN); - - // Hi := Hash(Ci || Identifier - memcpy(hash, identifier_hash, WIREGUARD_HASH_LEN); - - // Hi := Hash(Hi || Spubr) - wireguard_mix_hash(hash, device->public_key, WIREGUARD_PUBLIC_KEY_LEN); - - // Ci := Kdf1(Ci, Epubi) - wireguard_kdf1(chaining_key, chaining_key, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.ephemeral := Epubi - memcpy(e, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // Hi := Hash(Hi || msg.ephemeral) - wireguard_mix_hash(hash, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // Calculate DH(Eprivi,Spubr) - wireguard_x25519(dh_calculation, device->private_key, e); - if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { - - // (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr)) - wireguard_kdf2(chaining_key, key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.static := AEAD(k, 0, Spubi, Hi) - if (wireguard_aead_decrypt(s, msg->enc_static, sizeof(msg->enc_static), hash, WIREGUARD_HASH_LEN, 0, key)) { - // Hi := Hash(Hi || msg.static) - wireguard_mix_hash(hash, msg->enc_static, sizeof(msg->enc_static)); - - peer = peer_lookup_by_pubkey(device, s); - if (peer) { - handshake = &peer->handshake; - - // (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr)) - wireguard_kdf2(chaining_key, key, chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.timestamp := AEAD(k, 0, Timestamp(), Hi) - if (wireguard_aead_decrypt(t, msg->enc_timestamp, sizeof(msg->enc_timestamp), hash, WIREGUARD_HASH_LEN, 0, key)) { - // Hi := Hash(Hi || msg.timestamp) - wireguard_mix_hash(hash, msg->enc_timestamp, sizeof(msg->enc_timestamp)); - - now = wireguard_sys_now(); - - // Check that timestamp is increasing and we haven't had too many initiations (should only get one per peer every 5 seconds max?) - replay = (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) <= 0); // tai64n is big endian so we can use memcmp to compare - rate_limit = (peer->last_initiation_rx - now) < (1000 / MAX_INITIATIONS_PER_SECOND); - - if (!replay && !rate_limit) { - // Success! Copy everything to peer - peer->last_initiation_rx = now; - if (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) > 0) { - memcpy(peer->greatest_timestamp, t, WIREGUARD_TAI64N_LEN); - // TODO: Need to notify if the higher layers want to persist latest timestamp/nonce somewhere - } - memcpy(handshake->remote_ephemeral, e, WIREGUARD_PUBLIC_KEY_LEN); - memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN); - memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN); - handshake->remote_index = msg->sender; - handshake->valid = true; - handshake->initiator = false; - ret_peer = peer; - - } else { - // Ignore - } - } else { - // Failed to decrypt - } - } else { - // peer not found - } - } else { - // Failed to decrypt - } - } else { - // Bad X25519 - } - - crypto_zero(key, sizeof(key)); - crypto_zero(hash, sizeof(hash)); - crypto_zero(chaining_key, sizeof(chaining_key)); - crypto_zero(dh_calculation, sizeof(dh_calculation)); - - return ret_peer; -} - -bool wireguard_process_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *src) { - struct wireguard_handshake *handshake = &peer->handshake; - - bool result = false; - uint8_t key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t hash[WIREGUARD_HASH_LEN]; - uint8_t chaining_key[WIREGUARD_HASH_LEN]; - uint8_t e[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t ephemeral_private[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t static_private[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t tau[WIREGUARD_PUBLIC_KEY_LEN]; - - if (handshake->valid && handshake->initiator) { - - memcpy(hash, handshake->hash, WIREGUARD_HASH_LEN); - memcpy(chaining_key, handshake->chaining_key, WIREGUARD_HASH_LEN); - memcpy(ephemeral_private, handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN); - memcpy(preshared_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); - - // (Eprivr, Epubr) := DH-Generate() - // Not required - - // Cr := Kdf1(Cr,Epubr) - wireguard_kdf1(chaining_key, chaining_key, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.ephemeral := Epubr - memcpy(e, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // Hr := Hash(Hr || msg.ephemeral) - wireguard_mix_hash(hash, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // Cr := Kdf1(Cr, DH(Eprivr, Epubi)) - // Calculate DH(Eprivr, Epubi) - wireguard_x25519(dh_calculation, ephemeral_private, e); - if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { - wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); - - // Cr := Kdf1(Cr, DH(Eprivr, Spubi)) - // CalculateDH(Eprivr, Spubi) - wireguard_x25519(dh_calculation, device->private_key, e); - if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { - wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); - - // (Cr, t, k) := Kdf3(Cr, Q) - wireguard_kdf3(chaining_key, tau, key, chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); - - // Hr := Hash(Hr | t) - wireguard_mix_hash(hash, tau, WIREGUARD_HASH_LEN); - - // msg.empty := AEAD(k, 0, E, Hr) - if (wireguard_aead_decrypt(NULL, src->enc_empty, sizeof(src->enc_empty), hash, WIREGUARD_HASH_LEN, 0, key)) { - // Hr := Hash(Hr | msg.empty) - // Not required as discarded - - //Copy details to handshake - memcpy(handshake->remote_ephemeral, e, WIREGUARD_HASH_LEN); - memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN); - memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN); - handshake->remote_index = src->sender; - - result = true; - } else { - // Decrypt failed - } - - } else { - // X25519 fail - } - - } else { - // X25519 fail - } - - } - crypto_zero(key, sizeof(key)); - crypto_zero(hash, sizeof(hash)); - crypto_zero(chaining_key, sizeof(chaining_key)); - crypto_zero(ephemeral_private, sizeof(ephemeral_private)); - crypto_zero(static_private, sizeof(static_private)); - crypto_zero(preshared_key, sizeof(preshared_key)); - crypto_zero(tau, sizeof(tau)); - - return result; -} - -bool wireguard_process_cookie_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_cookie_reply *src) { - uint8_t cookie[WIREGUARD_COOKIE_LEN]; - bool result = false; - - if (peer->handshake_mac1_valid) { - - result = wireguard_xaead_decrypt(cookie, src->enc_cookie, sizeof(src->enc_cookie), peer->handshake_mac1, WIREGUARD_COOKIE_LEN, src->nonce, peer->label_cookie_key); - - if (result) { - // 5.4.7 Under Load: Cookie Reply Message - // Upon receiving this message, if it is valid, the only thing the recipient of this message should do is store the cookie along with the time at which it was received - memcpy(peer->cookie, cookie, WIREGUARD_COOKIE_LEN); - peer->cookie_millis = wireguard_sys_now(); - peer->handshake_mac1_valid = false; - } - } else { - // We didn't send any initiation packet so we shouldn't be getting a cookie reply! - } - return result; -} - -bool wireguard_create_handshake_initiation(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *dst) { - uint8_t timestamp[WIREGUARD_TAI64N_LEN]; - uint8_t key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; - bool result = false; - - struct wireguard_handshake *handshake = &peer->handshake; - - memset(dst, 0, sizeof(struct message_handshake_initiation)); - - // Ci := Hash(Construction) (precalculated hash) - memcpy(handshake->chaining_key, construction_hash, WIREGUARD_HASH_LEN); - - // Hi := Hash(Ci || Identifier) - memcpy(handshake->hash, identifier_hash, WIREGUARD_HASH_LEN); - - // Hi := Hash(Hi || Spubr) - wireguard_mix_hash(handshake->hash, peer->public_key, WIREGUARD_PUBLIC_KEY_LEN); - - // (Eprivi, Epubi) := DH-Generate() - wireguard_generate_private_key(handshake->ephemeral_private); - if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) { - - // Ci := Kdf1(Ci, Epubi) - wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.ephemeral := Epubi - // Done above - public keys is calculated into dst->ephemeral - - // Hi := Hash(Hi || msg.ephemeral) - wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // Calculate DH(Eprivi,Spubr) - wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key); - if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { - - // (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr)) - wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.static := AEAD(k,0,Spubi, Hi) - wireguard_aead_encrypt(dst->enc_static, device->public_key, WIREGUARD_PUBLIC_KEY_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key); - - // Hi := Hash(Hi || msg.static) - wireguard_mix_hash(handshake->hash, dst->enc_static, sizeof(dst->enc_static)); - - // (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr)) - // note DH(Sprivi,Spubr) is precomputed per peer - wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.timestamp := AEAD(k, 0, Timestamp(), Hi) - wireguard_tai64n_now(timestamp); - wireguard_aead_encrypt(dst->enc_timestamp, timestamp, WIREGUARD_TAI64N_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key); - - // Hi := Hash(Hi || msg.timestamp) - wireguard_mix_hash(handshake->hash, dst->enc_timestamp, sizeof(dst->enc_timestamp)); - - dst->type = MESSAGE_HANDSHAKE_INITIATION; - dst->sender = wireguard_generate_unique_index(device); - - handshake->valid = true; - handshake->initiator = true; - handshake->local_index = dst->sender; - - result = true; - } - } - - if (result) { - // 5.4.4 Cookie MACs - // msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA) - // The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed - wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_initiation)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN); - - // if Lm = E or Lm ≥ 120: - if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) { - // msg.mac2 := 0 - crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN); - } else { - // msg.mac2 := Mac(Lm, msgB) - wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_initiation)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN); - - } - } - - crypto_zero(key, sizeof(key)); - crypto_zero(dh_calculation, sizeof(dh_calculation)); - return result; -} - -bool wireguard_create_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *dst) { - struct wireguard_handshake *handshake = &peer->handshake; - uint8_t key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t tau[WIREGUARD_HASH_LEN]; - bool result = false; - - memset(dst, 0, sizeof(struct message_handshake_response)); - - if (handshake->valid && !handshake->initiator) { - - // (Eprivr, Epubr) := DH-Generate() - wireguard_generate_private_key(handshake->ephemeral_private); - if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) { - - // Cr := Kdf1(Cr,Epubr) - wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // msg.ephemeral := Epubr - // Copied above when generated - - // Hr := Hash(Hr || msg.ephemeral) - wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); - - // Cr := Kdf1(Cr, DH(Eprivr, Epubi)) - // Calculate DH(Eprivi,Spubr) - wireguard_x25519(dh_calculation, handshake->ephemeral_private, handshake->remote_ephemeral); - if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { - wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); - - // Cr := Kdf1(Cr, DH(Eprivr, Spubi)) - // Calculate DH(Eprivi,Spubr) - wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key); - if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { - wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); - - // (Cr, t, k) := Kdf3(Cr, Q) - wireguard_kdf3(handshake->chaining_key, tau, key, handshake->chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); - - // Hr := Hash(Hr | t) - wireguard_mix_hash(handshake->hash, tau, WIREGUARD_HASH_LEN); - - // msg.empty := AEAD(k, 0, E, Hr) - wireguard_aead_encrypt(dst->enc_empty, NULL, 0, handshake->hash, WIREGUARD_HASH_LEN, 0, key); - - // Hr := Hash(Hr | msg.empty) - wireguard_mix_hash(handshake->hash, dst->enc_empty, sizeof(dst->enc_empty)); - - dst->type = MESSAGE_HANDSHAKE_RESPONSE; - dst->receiver = handshake->remote_index; - dst->sender = wireguard_generate_unique_index(device); - // Update handshake object too - handshake->local_index = dst->sender; - - result = true; - } else { - // Bad x25519 - } - } else { - // Bad x25519 - } - - } else { - // Failed to generate DH - } - } - - if (result) { - // 5.4.4 Cookie MACs - // msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA) - // The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed - wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_response)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN); - - // if Lm = E or Lm ≥ 120: - if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) { - // msg.mac2 := 0 - crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN); - } else { - // msg.mac2 := Mac(Lm, msgB) - wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_response)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN); - } - } - - crypto_zero(key, sizeof(key)); - crypto_zero(dh_calculation, sizeof(dh_calculation)); - crypto_zero(tau, sizeof(tau)); - return result; -} - -void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length) { - uint8_t cookie[WIREGUARD_COOKIE_LEN]; - crypto_zero(dst, sizeof(struct message_cookie_reply)); - dst->type = MESSAGE_COOKIE_REPLY; - dst->receiver = index; - wireguard_random_bytes(dst->nonce, COOKIE_NONCE_LEN); - generate_peer_cookie(device, cookie, source_addr_port, source_length); - wireguard_xaead_encrypt(dst->enc_cookie, cookie, WIREGUARD_COOKIE_LEN, mac1, WIREGUARD_COOKIE_LEN, dst->nonce, device->label_cookie_key); -} - -bool wireguard_peer_init(struct wireguard_device *device, struct wireguard_peer *peer, const uint8_t *public_key, const uint8_t *preshared_key) { - // Clear out structure - memset(peer, 0, sizeof(struct wireguard_peer)); - - if (device->valid) { - // Copy across the public key into our peer structure - memcpy(peer->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN); - if (preshared_key) { - memcpy(peer->preshared_key, preshared_key, WIREGUARD_SESSION_KEY_LEN); - } else { - crypto_zero(peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); - } - - if (wireguard_x25519(peer->public_key_dh, device->private_key, peer->public_key) == 0) { - // Zero out handshake - memset(&peer->handshake, 0, sizeof(struct wireguard_handshake)); - peer->handshake.valid = false; - - // Zero out any cookie info - we haven't received one yet - peer->cookie_millis = 0; - memset(&peer->cookie, 0, WIREGUARD_COOKIE_LEN); - - // Precompute keys to deal with mac1/2 calculation - wireguard_mac_key(peer->label_mac1_key, peer->public_key, LABEL_MAC1, sizeof(LABEL_MAC1)); - wireguard_mac_key(peer->label_cookie_key, peer->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE)); - - peer->valid = true; - } else { - crypto_zero(peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN); - } - } - return peer->valid; -} - -bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key) { - // Set the private key and calculate public key from it - memcpy(device->private_key, private_key, WIREGUARD_PRIVATE_KEY_LEN); - // Ensure private key is correctly "clamped" - wireguard_clamp_private_key(device->private_key); - device->valid = wireguard_generate_public_key(device->public_key, private_key); - if (device->valid) { - generate_cookie_secret(device); - // 5.4.4 Cookie MACs - The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed. - wireguard_mac_key(device->label_mac1_key, device->public_key, LABEL_MAC1, sizeof(LABEL_MAC1)); - // 5.4.7 Under Load: Cookie Reply Message - The value Hash(Label-Cookie || Spubm) above can be pre-computed. - wireguard_mac_key(device->label_cookie_key, device->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE)); - - } else { - crypto_zero(device->private_key, WIREGUARD_PRIVATE_KEY_LEN); - } - return device->valid; -} - -void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, struct wireguard_keypair *keypair) { - wireguard_aead_encrypt(dst, src, src_len, NULL, 0, keypair->sending_counter, keypair->sending_key); - keypair->sending_counter++; -} - -bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, struct wireguard_keypair *keypair) { - return wireguard_aead_decrypt(dst, src, src_len, NULL, 0, counter, keypair->receiving_key); -} - -bool wireguard_base64_decode(const char *str, uint8_t *out, size_t *outlen) { - uint32_t accum = 0; // We accumulate upto four blocks of 6 bits into this to form 3 bytes output - uint8_t char_count = 0; // How many characters have we processed in this block - int byte_count = 3; // How many bytes are we expecting in current 4 char block - int len = 0; // result length in bytes - bool result = true; - uint8_t bits; - char c; - char *ptr; - int x; - size_t inlen; - - if (!str) { - return false; - } - - inlen = strlen(str); - - for (x = 0; x < inlen; x++) { - c = str[x]; - if (c == '=') { - // This is '=' padding at end of string - decrease the number of bytes to write - bits = 0; - byte_count--; - if (byte_count < 0) { - // Too much padding! - result = false; - break; - } - } else { - if (byte_count != 3) { - // Padding only allowed at end - this is a valid byte and we have already seen padding - result = false; - break; - } - ptr = strchr(base64_lookup, c); - if (ptr) { - bits = (uint8_t)((ptr - base64_lookup) & 0x3F); - } else { - // invalid character in input string - result = false; - break; - } - } - - accum = (accum << 6) | bits; - char_count++; - - if (char_count == 4) { - if (len + byte_count > *outlen) { - // Output buffer overflow - result = false; - break; - } - out[len++] = (uint8_t)((accum >> 16) & 0xFF); - if (byte_count > 1) { - out[len++] = (uint8_t)((accum >> 8) & 0xFF); - } - if (byte_count > 2) { - out[len++] = (uint8_t)(accum & 0xFF); - } - char_count = 0; - accum = 0; - } - } - if (char_count != 0) { - // We require padding to multiple of 3 input length - bytes are missing from output! - result = false; - } - *outlen = len; - return result; -} - -bool wireguard_base64_encode(const uint8_t *in, size_t inlen, char *out, size_t *outlen) { - bool result = false; - int read_offset = 0; - int write_offset = 0; - uint8_t byte1, byte2, byte3; - uint32_t tmp; - char c; - size_t len = 4 * ((inlen + 2) / 3); - int padding = (3 - (inlen % 3)); - if (padding > 2) padding = 0; - if (*outlen > len) { - - while (read_offset < inlen) { - // Read three bytes - byte1 = (read_offset < inlen) ? in[read_offset++] : 0; - byte2 = (read_offset < inlen) ? in[read_offset++] : 0; - byte3 = (read_offset < inlen) ? in[read_offset++] : 0; - // Turn into 24 bit intermediate - tmp = (byte1 << 16) | (byte2 << 8) | (byte3); - // Write out 4 characters each representing 6 bits of input - out[write_offset++] = base64_lookup[(tmp >> 18) & 0x3F]; - out[write_offset++] = base64_lookup[(tmp >> 12) & 0x3F]; - c = (write_offset < len - padding) ? base64_lookup[(tmp >> 6) & 0x3F] : '='; - out[write_offset++] = c; - c = (write_offset < len - padding) ? base64_lookup[(tmp) & 0x3F] : '='; - out[write_offset++] = c; - } - out[len] = '\0'; - *outlen = len; - result = true; - } else { - // Not enough data to put in base64 and null terminate - } - return result; -} diff --git a/lib/WireGuard-ESP32/src/wireguard.h b/lib/WireGuard-ESP32/src/wireguard.h deleted file mode 100644 index 961792a..0000000 --- a/lib/WireGuard-ESP32/src/wireguard.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * The original license is below: - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -#ifndef _WIREGUARD_H_ -#define _WIREGUARD_H_ - -#include -#include -#include - -// Note: these are only required for definitions in device/peer for netif, udp_pcb, ip_addr_t and u16_t -#include "lwip/netif.h" -#include "lwip/udp.h" -#include "lwip/ip_addr.h" -#include "lwip/arch.h" - -// Platform-specific functions that need to be implemented per-platform -#include "wireguard-platform.h" - -// tai64n contains 64-bit seconds and 32-bit nano offset (12 bytes) -#define WIREGUARD_TAI64N_LEN (12) -// Auth algorithm is chacha20pol1305 which is 128bit (16 byte) authenticator -#define WIREGUARD_AUTHTAG_LEN (16) -// Hash algorithm is blake2s which makes 32 byte hashes -#define WIREGUARD_HASH_LEN (32) -// Public key algo is curve22519 which uses 32 byte keys -#define WIREGUARD_PUBLIC_KEY_LEN (32) -// Public key algo is curve22519 which uses 32 byte keys -#define WIREGUARD_PRIVATE_KEY_LEN (32) -// Symmetric session keys are chacha20/poly1305 which uses 32 byte keys -#define WIREGUARD_SESSION_KEY_LEN (32) - -// Timers / Limits -#define WIREGUARD_COOKIE_LEN (16) -#define COOKIE_SECRET_MAX_AGE (2 * 60) -#define COOKIE_NONCE_LEN (24) - -#define REKEY_AFTER_MESSAGES (1ULL << 60) -#define REJECT_AFTER_MESSAGES (0xFFFFFFFFFFFFFFFFULL - (1ULL << 13)) -#define REKEY_AFTER_TIME (120) -#define REJECT_AFTER_TIME (180) -#define REKEY_TIMEOUT (5) -#define KEEPALIVE_TIMEOUT (10) - -struct wireguard_keypair { - bool valid; - bool initiator; // Did we initiate this session (send the initiation packet rather than sending the response packet) - uint32_t keypair_millis; - - uint8_t sending_key[WIREGUARD_SESSION_KEY_LEN]; - bool sending_valid; - uint64_t sending_counter; - - uint8_t receiving_key[WIREGUARD_SESSION_KEY_LEN]; - bool receiving_valid; - - uint32_t last_tx; - uint32_t last_rx; - - uint32_t replay_bitmap; - uint64_t replay_counter; - - uint32_t local_index; // This is the index we generated for our end - uint32_t remote_index; // This is the index on the other end -}; - -struct wireguard_handshake { - bool valid; - bool initiator; - uint32_t local_index; - uint32_t remote_index; - uint8_t ephemeral_private[WIREGUARD_PRIVATE_KEY_LEN]; - uint8_t remote_ephemeral[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t hash[WIREGUARD_HASH_LEN]; - uint8_t chaining_key[WIREGUARD_HASH_LEN]; -}; - -struct wireguard_allowed_ip { - bool valid; - ip_addr_t ip; - ip_addr_t mask; -}; - -struct wireguard_peer { - bool valid; // Is this peer initialised? - bool active; // Should we be actively trying to connect? - - // This is the configured IP of the peer (endpoint) - ip_addr_t connect_ip; - u16_t connect_port; - // This is the latest received IP/port - ip_addr_t ip; - u16_t port; - // keep-alive interval in seconds, 0 is disable - uint16_t keepalive_interval; - - struct wireguard_allowed_ip allowed_source_ips[WIREGUARD_MAX_SRC_IPS]; - - uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN]; - - // Precomputed DH(Sprivi,Spubr) with device private key, and peer public key - uint8_t public_key_dh[WIREGUARD_PUBLIC_KEY_LEN]; - - // Session keypairs - struct wireguard_keypair curr_keypair; - struct wireguard_keypair prev_keypair; - struct wireguard_keypair next_keypair; - - // 5.1 Silence is a Virtue: The responder keeps track of the greatest timestamp received per peer - uint8_t greatest_timestamp[WIREGUARD_TAI64N_LEN]; - - // The active handshake that is happening - struct wireguard_handshake handshake; - - // Decrypted cookie from the responder - uint32_t cookie_millis; - uint8_t cookie[WIREGUARD_COOKIE_LEN]; - - // The latest mac1 we sent with initiation - bool handshake_mac1_valid; - uint8_t handshake_mac1[WIREGUARD_COOKIE_LEN]; - - // Precomputed keys for use in mac validation - uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN]; - - // The last time we received a valid initiation message - uint32_t last_initiation_rx; - // The last time we sent an initiation message to this peer - uint32_t last_initiation_tx; - - // last_tx and last_rx of data packets - uint32_t last_tx; - uint32_t last_rx; - - // We set this flag on RX/TX of packets if we think that we should initiate a new handshake - bool send_handshake; -}; - -struct wireguard_device { - // Maybe have a "Device private" member to abstract these? - struct netif *netif; - struct udp_pcb *udp_pcb; - - struct netif *underlying_netif; - - uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN]; - uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN]; - - uint8_t cookie_secret[WIREGUARD_HASH_LEN]; - uint32_t cookie_secret_millis; - - // Precalculated - uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN]; - uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN]; - - // List of peers associated with this device - struct wireguard_peer peers[WIREGUARD_MAX_PEERS]; - - bool valid; -}; - -#define MESSAGE_INVALID 0 -#define MESSAGE_HANDSHAKE_INITIATION 1 -#define MESSAGE_HANDSHAKE_RESPONSE 2 -#define MESSAGE_COOKIE_REPLY 3 -#define MESSAGE_TRANSPORT_DATA 4 - - -// 5.4.2 First Message: Initiator to Responder -struct message_handshake_initiation { - uint8_t type; - uint8_t reserved[3]; - uint32_t sender; - uint8_t ephemeral[32]; - uint8_t enc_static[32 + WIREGUARD_AUTHTAG_LEN]; - uint8_t enc_timestamp[WIREGUARD_TAI64N_LEN + WIREGUARD_AUTHTAG_LEN]; - uint8_t mac1[WIREGUARD_COOKIE_LEN]; - uint8_t mac2[WIREGUARD_COOKIE_LEN]; -} __attribute__ ((__packed__)); - -// 5.4.3 Second Message: Responder to Initiator -struct message_handshake_response { - uint8_t type; - uint8_t reserved[3]; - uint32_t sender; - uint32_t receiver; - uint8_t ephemeral[32]; - uint8_t enc_empty[0 + WIREGUARD_AUTHTAG_LEN]; - uint8_t mac1[WIREGUARD_COOKIE_LEN]; - uint8_t mac2[WIREGUARD_COOKIE_LEN]; -} __attribute__ ((__packed__)); - -// 5.4.7 Under Load: Cookie Reply Message -struct message_cookie_reply { - uint8_t type; - uint8_t reserved[3]; - uint32_t receiver; - uint8_t nonce[COOKIE_NONCE_LEN]; - uint8_t enc_cookie[WIREGUARD_COOKIE_LEN + WIREGUARD_AUTHTAG_LEN]; -} __attribute__ ((__packed__)); - -// 5.4.6 Subsequent Messages: Transport Data Messages -struct message_transport_data { - uint8_t type; - uint8_t reserved[3]; - uint32_t receiver; - uint8_t counter[8]; - // Followed by encrypted data - uint8_t enc_packet[]; -} __attribute__ ((__packed__)); - -// Initialise the WireGuard system - need to call this before anything else -void wireguard_init(); -bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key); -bool wireguard_peer_init(struct wireguard_device *device, struct wireguard_peer *peer, const uint8_t *public_key, const uint8_t *preshared_key); - -struct wireguard_peer *peer_alloc(struct wireguard_device *device); -uint8_t wireguard_peer_index(struct wireguard_device *device, struct wireguard_peer *peer); -struct wireguard_peer *peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key); -struct wireguard_peer *peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index); -struct wireguard_peer *peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver); -struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver); - -void wireguard_start_session(struct wireguard_peer *peer, bool initiator); - -void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair); -void keypair_destroy(struct wireguard_keypair *keypair); - -struct wireguard_keypair *get_peer_keypair_for_idx(struct wireguard_peer *peer, uint32_t idx); -bool wireguard_check_replay(struct wireguard_keypair *keypair, uint64_t seq); - -uint8_t wireguard_get_message_type(const uint8_t *data, size_t len); - -struct wireguard_peer *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg); -bool wireguard_process_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *src); -bool wireguard_process_cookie_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_cookie_reply *src); - -bool wireguard_create_handshake_initiation(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *dst); -bool wireguard_create_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *dst); -void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length); - - -bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1); -bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2); - -bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds); - -void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, struct wireguard_keypair *keypair); -bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, struct wireguard_keypair *keypair); - -bool wireguard_base64_decode(const char *str, uint8_t *out, size_t *outlen); -bool wireguard_base64_encode(const uint8_t *in, size_t inlen, char *out, size_t *outlen); - -#endif /* _WIREGUARD_H_ */ diff --git a/lib/WireGuard-ESP32/src/wireguardif.c b/lib/WireGuard-ESP32/src/wireguardif.c deleted file mode 100644 index 10ec89e..0000000 --- a/lib/WireGuard-ESP32/src/wireguardif.c +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * The original license is below: - * - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - -#include "wireguardif.h" - -#include -#include - -#include "lwip/netif.h" -#include "lwip/ip.h" -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "lwip/sys.h" -#include "lwip/timeouts.h" - -#include "wireguard.h" -#include "crypto.h" -#include "esp_log.h" -//#include "tcpip_adapter.h" -#include "esp_netif.h" - -#include "esp32-hal-log.h" - -#define WIREGUARDIF_TIMER_MSECS 400 - -#define TAG "[WireGuard] " - -static void update_peer_addr(struct wireguard_peer *peer, const ip_addr_t *addr, u16_t port) { - peer->ip = *addr; - peer->port = port; -} - -static struct wireguard_peer *peer_lookup_by_allowed_ip(struct wireguard_device *device, const ip_addr_t *ipaddr) { - struct wireguard_peer *result = NULL; - struct wireguard_peer *tmp; - int x; - int y; - for (x=0; (!result) && (x < WIREGUARD_MAX_PEERS); x++) { - tmp = &device->peers[x]; - if (tmp->valid) { - for (y=0; y < WIREGUARD_MAX_SRC_IPS; y++) { - if ((tmp->allowed_source_ips[y].valid) && ip_addr_netcmp(ipaddr, &tmp->allowed_source_ips[y].ip, ip_2_ip4(&tmp->allowed_source_ips[y].mask))) { - result = tmp; - break; - } - } - } - } - return result; -} - -static bool wireguardif_can_send_initiation(struct wireguard_peer *peer) { - return ((peer->last_initiation_tx == 0) || (wireguard_expired(peer->last_initiation_tx, REKEY_TIMEOUT))); -} - -static err_t wireguardif_peer_output(struct netif *netif, struct pbuf *q, struct wireguard_peer *peer) { - struct wireguard_device *device = (struct wireguard_device *)netif->state; - // Send to last know port, not the connect port - //TODO: Support DSCP and ECN - lwip requires this set on PCB globally, not per packet - return udp_sendto_if(device->udp_pcb, q, &peer->ip, peer->port, device->underlying_netif); -} - -static err_t wireguardif_device_output(struct wireguard_device *device, struct pbuf *q, const ip_addr_t *ipaddr, u16_t port) { - return udp_sendto_if(device->udp_pcb, q, ipaddr, port, device->underlying_netif); -} - -static err_t wireguardif_output_to_peer(struct netif *netif, struct pbuf *q, const ip_addr_t *ipaddr, struct wireguard_peer *peer) { - // The LWIP IP layer wants to send an IP packet out over the interface - we need to encrypt and send it to the peer - struct message_transport_data *hdr; - struct pbuf *pbuf; - err_t result; - size_t unpadded_len; - size_t padded_len; - size_t header_len = 16; - uint8_t *dst; - uint32_t now; - struct wireguard_keypair *keypair = &peer->curr_keypair; - - // Note: We may not be able to use the current keypair if we haven't received data, may need to resort to using previous keypair - if (keypair->valid && (!keypair->initiator) && (keypair->last_rx == 0)) { - keypair = &peer->prev_keypair; - } - - if (keypair->valid && (keypair->initiator || keypair->last_rx != 0)) { - - if ( - !wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME) && - (keypair->sending_counter < REJECT_AFTER_MESSAGES) - ) { - - // Calculate the outgoing packet size - round up to next 16 bytes, add 16 bytes for header - if (q) { - // This is actual transport data - unpadded_len = q->tot_len; - } else { - // This is a keep-alive - unpadded_len = 0; - } - padded_len = (unpadded_len + 15) & 0xFFFFFFF0; // Round up to next 16 byte boundary - - // The buffer needs to be allocated from "transport" pool to leave room for LwIP generated IP headers - // The IP packet consists of 16 byte header (struct message_transport_data), data padded upto 16 byte boundary + encrypted auth tag (16 bytes) - pbuf = pbuf_alloc(PBUF_TRANSPORT, header_len + padded_len + WIREGUARD_AUTHTAG_LEN, PBUF_RAM); - if (pbuf) { - log_v(TAG "preparing transport data..."); - // Note: allocating pbuf from RAM above guarantees that the pbuf is in one section and not chained - // - i.e payload points to the contiguous memory region - memset(pbuf->payload, 0, pbuf->tot_len); - - hdr = (struct message_transport_data *)pbuf->payload; - - hdr->type = MESSAGE_TRANSPORT_DATA; - hdr->receiver = keypair->remote_index; - // Alignment required... pbuf_alloc has probably aligned data, but want to be sure - U64TO8_LITTLE(hdr->counter, keypair->sending_counter); - - // Copy the encrypted (padded) data to the output packet - chacha20poly1305_encrypt() can encrypt data in-place which avoids call to mem_malloc - dst = &hdr->enc_packet[0]; - if ((padded_len > 0) && q) { - // Note: before copying make sure we have inserted the IP header checksum - // The IP header checksum (and other checksums in the IP packet - e.g. ICMP) need to be calculated by LWIP before calling - // The Wireguard interface always needs checksums to be generated in software but the base netif may have some checksums generated by hardware - - // Copy pbuf to memory - handles case where pbuf is chained - pbuf_copy_partial(q, dst, unpadded_len, 0); - } - - // Then encrypt - wireguard_encrypt_packet(dst, dst, padded_len, keypair); - - result = wireguardif_peer_output(netif, pbuf, peer); - - if (result == ERR_OK) { - now = wireguard_sys_now(); - peer->last_tx = now; - keypair->last_tx = now; - } - - pbuf_free(pbuf); - - // Check to see if we should rekey - if (keypair->sending_counter >= REKEY_AFTER_MESSAGES) { - peer->send_handshake = true; - } else if (keypair->initiator && wireguard_expired(keypair->keypair_millis, REKEY_AFTER_TIME)) { - peer->send_handshake = true; - } - - } else { - // Failed to allocate memory - result = ERR_MEM; - } - } else { - // key has expired... - keypair_destroy(keypair); - result = ERR_CONN; - } - } else { - // No valid keys! - result = ERR_CONN; - } - return result; -} - -// This is used as the output function for the Wireguard netif -// The ipaddr here is the one inside the VPN which we use to lookup the correct peer/endpoint -static err_t wireguardif_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ip4addr) { - struct wireguard_device *device = (struct wireguard_device *)netif->state; - // Send to peer that matches dest IP - ip_addr_t ipaddr; - ip_addr_copy_from_ip4(ipaddr, *ip4addr); - struct wireguard_peer *peer = peer_lookup_by_allowed_ip(device, &ipaddr); - if (peer) { - return wireguardif_output_to_peer(netif, q, &ipaddr, peer); - } else { - return ERR_RTE; - } -} - -static void wireguardif_send_keepalive(struct wireguard_device *device, struct wireguard_peer *peer) { - // Send a NULL packet as a keep-alive - wireguardif_output_to_peer(device->netif, NULL, NULL, peer); -} - -static void wireguardif_process_response_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *response, const ip_addr_t *addr, u16_t port) { - if (wireguard_process_handshake_response(device, peer, response)) { - // Packet is good - // Update the peer location - log_i(TAG "good handshake from %08x:%d", addr->u_addr.ip4.addr, port); - update_peer_addr(peer, addr, port); - - wireguard_start_session(peer, true); - wireguardif_send_keepalive(device, peer); - - // Set the IF-UP flag on netif - netif_set_link_up(device->netif); - } else { - // Packet bad - log_i(TAG "bad handshake from %08x:%d", addr->u_addr.ip4.addr, port); - } -} - -static bool peer_add_ip(struct wireguard_peer *peer, ip_addr_t ip, ip_addr_t mask) { - bool result = false; - struct wireguard_allowed_ip *allowed; - int x; - // Look for existing match first - for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) { - allowed = &peer->allowed_source_ips[x]; - if ((allowed->valid) && ip_addr_cmp(&allowed->ip, &ip) && ip_addr_cmp(&allowed->mask, &mask)) { - result = true; - break; - } - } - if (!result) { - // Look for a free slot - for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) { - allowed = &peer->allowed_source_ips[x]; - if (!allowed->valid) { - allowed->valid = true; - allowed->ip = ip; - allowed->mask = mask; - result = true; - break; - } - } - } - return result; -} - -static void wireguardif_process_data_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_transport_data *data_hdr, size_t data_len, const ip_addr_t *addr, u16_t port) { - struct wireguard_keypair *keypair; - uint64_t nonce; - uint8_t *src; - size_t src_len; - struct pbuf *pbuf; - struct ip_hdr *iphdr; - ip_addr_t dest; - bool dest_ok = false; - int x; - uint32_t now; - uint16_t header_len = 0xFFFF; - uint32_t idx = data_hdr->receiver; - - keypair = get_peer_keypair_for_idx(peer, idx); - - if (keypair) { - if ( - (keypair->receiving_valid) && - !wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME) && - (keypair->sending_counter < REJECT_AFTER_MESSAGES) - - ) { - - nonce = U8TO64_LITTLE(data_hdr->counter); - src = &data_hdr->enc_packet[0]; - src_len = data_len; - - // We don't know the unpadded size until we have decrypted the packet and validated/inspected the IP header - pbuf = pbuf_alloc(PBUF_TRANSPORT, src_len - WIREGUARD_AUTHTAG_LEN, PBUF_RAM); - if (pbuf) { - // Decrypt the packet - memset(pbuf->payload, 0, pbuf->tot_len); - if (wireguard_decrypt_packet(pbuf->payload, src, src_len, nonce, keypair)) { - - // 3. Since the packet has authenticated correctly, the source IP of the outer UDP/IP packet is used to update the endpoint for peer TrMv...WXX0. - // Update the peer location - update_peer_addr(peer, addr, port); - - now = wireguard_sys_now(); - keypair->last_rx = now; - peer->last_rx = now; - - // Might need to shuffle next key --> current keypair - keypair_update(peer, keypair); - - // Check to see if we should rekey - if (keypair->initiator && wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME - peer->keepalive_interval - REKEY_TIMEOUT)) { - peer->send_handshake = true; - } - - // Make sure that link is reported as up - netif_set_link_up(device->netif); - - if (pbuf->tot_len > 0) { - //4a. Once the packet payload is decrypted, the interface has a plaintext packet. If this is not an IP packet, it is dropped. - iphdr = (struct ip_hdr *)pbuf->payload; - // Check for packet replay / dupes - if (wireguard_check_replay(keypair, nonce)) { - - // 4b. Otherwise, WireGuard checks to see if the source IP address of the plaintext inner-packet routes correspondingly in the cryptokey routing table - // Also check packet length! -#if LWIP_IPV4 - if (IPH_V(iphdr) == 4) { - ip_addr_copy_from_ip4(dest, iphdr->dest); - for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) { - if (peer->allowed_source_ips[x].valid) { - if (ip_addr_netcmp(&dest, &peer->allowed_source_ips[x].ip, ip_2_ip4(&peer->allowed_source_ips[x].mask))) { - dest_ok = true; - header_len = PP_NTOHS(IPH_LEN(iphdr)); - break; - } - } - } - } -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - if (IPH_V(iphdr) == 6) { - // TODO: IPV6 support for route filtering - header_len = PP_NTOHS(IPH_LEN(iphdr)); - dest_ok = true; - } -#endif /* LWIP_IPV6 */ - if (header_len <= pbuf->tot_len) { - - // 5. If the plaintext packet has not been dropped, it is inserted into the receive queue of the wg0 interface. - if (dest_ok) { - // Send packet to be process by LWIP - ip_input(pbuf, device->netif); - // pbuf is owned by IP layer now - pbuf = NULL; - } - } else { - // IP header is corrupt or lied about packet size - } - } else { - // This is a duplicate packet / replayed / too far out of order - } - } else { - // This was a keep-alive packet - } - } - - if (pbuf) { - pbuf_free(pbuf); - } - } - - - } else { - //After Reject-After-Messages transport data messages or after the current secure session is Reject- After-Time seconds old, - // whichever comes first, WireGuard will refuse to send or receive any more transport data messages using the current secure session, - // until a new secure session is created through the 1-RTT handshake - keypair_destroy(keypair); - } - - } else { - // Could not locate valid keypair for remote index - } -} - -static struct pbuf *wireguardif_initiate_handshake(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *msg, err_t *error) { - struct pbuf *pbuf = NULL; - err_t err = ERR_OK; - if (wireguard_create_handshake_initiation(device, peer, msg)) { - // Send this packet out! - pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_handshake_initiation), PBUF_RAM); - if (pbuf) { - err = pbuf_take(pbuf, msg, sizeof(struct message_handshake_initiation)); - if (err == ERR_OK) { - // OK! - } else { - pbuf_free(pbuf); - pbuf = NULL; - } - } else { - err = ERR_MEM; - } - } else { - err = ERR_ARG; - } - if (error) { - *error = err; - } - return pbuf; -} - -static void wireguardif_send_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer) { - struct message_handshake_response packet; - struct pbuf *pbuf = NULL; - err_t err = ERR_OK; - - if (wireguard_create_handshake_response(device, peer, &packet)) { - - wireguard_start_session(peer, false); - - // Send this packet out! - pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_handshake_response), PBUF_RAM); - if (pbuf) { - err = pbuf_take(pbuf, &packet, sizeof(struct message_handshake_response)); - if (err == ERR_OK) { - // OK! - wireguardif_peer_output(device->netif, pbuf, peer); - } - pbuf_free(pbuf); - } - } -} - -static size_t get_source_addr_port(const ip_addr_t *addr, u16_t port, uint8_t *buf, size_t buflen) { - size_t result = 0; - -#if LWIP_IPV4 - if (IP_IS_V4(addr) && (buflen >= 4)) { - U32TO8_BIG(buf + result, PP_NTOHL(ip4_addr_get_u32(ip_2_ip4(addr)))); - result += 4; - } -#endif -#if LWIP_IPV6 - if (IP_IS_V6(addr) && (buflen >= 16)) { - U16TO8_BIG(buf + result + 0, IP6_ADDR_BLOCK1(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 2, IP6_ADDR_BLOCK2(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 4, IP6_ADDR_BLOCK3(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 6, IP6_ADDR_BLOCK4(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 8, IP6_ADDR_BLOCK5(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 10, IP6_ADDR_BLOCK6(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 12, IP6_ADDR_BLOCK7(ip_2_ip6(addr))); - U16TO8_BIG(buf + result + 14, IP6_ADDR_BLOCK8(ip_2_ip6(addr))); - result += 16; - } -#endif - if (buflen >= result + 2) { - U16TO8_BIG(buf + result, port); - result += 2; - } - return result; -} - -static void wireguardif_send_handshake_cookie(struct wireguard_device *device, const uint8_t *mac1, uint32_t index, const ip_addr_t *addr, u16_t port) { - struct message_cookie_reply packet; - struct pbuf *pbuf = NULL; - err_t err = ERR_OK; - uint8_t source_buf[18]; - size_t source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf)); - - wireguard_create_cookie_reply(device, &packet, mac1, index, source_buf, source_len); - - // Send this packet out! - pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_cookie_reply), PBUF_RAM); - if (pbuf) { - err = pbuf_take(pbuf, &packet, sizeof(struct message_cookie_reply)); - if (err == ERR_OK) { - wireguardif_device_output(device, pbuf, addr, port); - } - pbuf_free(pbuf); - } -} - -static bool wireguardif_check_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg, const ip_addr_t *addr, u16_t port) { - bool result = false; - uint8_t *data = (uint8_t *)msg; - uint8_t source_buf[18]; - size_t source_len; - // We received an initiation packet check it is valid - - if (wireguard_check_mac1(device, data, sizeof(struct message_handshake_initiation) - (2 * WIREGUARD_COOKIE_LEN), msg->mac1)) { - // mac1 is valid! - if (!wireguard_is_under_load()) { - // If we aren't under load we only need mac1 to be correct - result = true; - } else { - // If we are under load then check mac2 - source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf)); - - result = wireguard_check_mac2(device, data, sizeof(struct message_handshake_initiation) - (WIREGUARD_COOKIE_LEN), source_buf, source_len, msg->mac2); - - if (!result) { - // mac2 is invalid (cookie may have expired) or not present - // 5.3 Denial of Service Mitigation & Cookies - // If the responder receives a message with a valid msg.mac1 yet with an invalid msg.mac2, and is under load, it may respond with a cookie reply message - wireguardif_send_handshake_cookie(device, msg->mac1, msg->sender, addr, port); - } - } - - } else { - // mac1 is invalid - } - return result; -} - -static bool wireguardif_check_response_message(struct wireguard_device *device, struct message_handshake_response *msg, const ip_addr_t *addr, u16_t port) { - bool result = false; - uint8_t *data = (uint8_t *)msg; - uint8_t source_buf[18]; - size_t source_len; - // We received an initiation packet check it is valid - - if (wireguard_check_mac1(device, data, sizeof(struct message_handshake_response) - (2 * WIREGUARD_COOKIE_LEN), msg->mac1)) { - // mac1 is valid! - if (!wireguard_is_under_load()) { - // If we aren't under load we only need mac1 to be correct - result = true; - } else { - // If we are under load then check mac2 - source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf)); - - result = wireguard_check_mac2(device, data, sizeof(struct message_handshake_response) - (WIREGUARD_COOKIE_LEN), source_buf, source_len, msg->mac2); - - if (!result) { - // mac2 is invalid (cookie may have expired) or not present - // 5.3 Denial of Service Mitigation & Cookies - // If the responder receives a message with a valid msg.mac1 yet with an invalid msg.mac2, and is under load, it may respond with a cookie reply message - wireguardif_send_handshake_cookie(device, msg->mac1, msg->sender, addr, port); - } - } - - } else { - // mac1 is invalid - } - return result; -} - - -void wireguardif_network_rx(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { - LWIP_ASSERT("wireguardif_network_rx: invalid arg", arg != NULL); - LWIP_ASSERT("wireguardif_network_rx: invalid pbuf", p != NULL); - // We have received a packet from the base_netif to our UDP port - process this as a possible Wireguard packet - struct wireguard_device *device = (struct wireguard_device *)arg; - struct wireguard_peer *peer; - uint8_t *data = p->payload; - size_t len = p->len; // This buf, not chained ones - - struct message_handshake_initiation *msg_initiation; - struct message_handshake_response *msg_response; - struct message_cookie_reply *msg_cookie; - struct message_transport_data *msg_data; - - uint8_t type = wireguard_get_message_type(data, len); - ESP_LOGV(TAG, "network_rx: %08x:%d", addr->u_addr.ip4.addr, port); - - switch (type) { - case MESSAGE_HANDSHAKE_INITIATION: - msg_initiation = (struct message_handshake_initiation *)data; - log_i(TAG "HANDSHAKE_INITIATION: %08x:%d", addr->u_addr.ip4.addr, port); - // Check mac1 (and optionally mac2) are correct - note it may internally generate a cookie reply packet - if (wireguardif_check_initiation_message(device, msg_initiation, addr, port)) { - - peer = wireguard_process_initiation_message(device, msg_initiation); - if (peer) { - // Update the peer location - update_peer_addr(peer, addr, port); - - // Send back a handshake response - wireguardif_send_handshake_response(device, peer); - } - } - break; - - case MESSAGE_HANDSHAKE_RESPONSE: - log_i(TAG "HANDSHAKE_RESPONSE: %08x:%d", addr->u_addr.ip4.addr, port); - msg_response = (struct message_handshake_response *)data; - - // Check mac1 (and optionally mac2) are correct - note it may internally generate a cookie reply packet - if (wireguardif_check_response_message(device, msg_response, addr, port)) { - - peer = peer_lookup_by_handshake(device, msg_response->receiver); - if (peer) { - // Process the handshake response - wireguardif_process_response_message(device, peer, msg_response, addr, port); - } - } - break; - - case MESSAGE_COOKIE_REPLY: - log_i(TAG "COOKIE_REPLY: %08x:%d", addr->u_addr.ip4.addr, port); - msg_cookie = (struct message_cookie_reply *)data; - peer = peer_lookup_by_handshake(device, msg_cookie->receiver); - if (peer) { - if (wireguard_process_cookie_message(device, peer, msg_cookie)) { - // Update the peer location - update_peer_addr(peer, addr, port); - - // Don't send anything out - we stay quiet until the next initiation message - } - } - break; - - case MESSAGE_TRANSPORT_DATA: - ESP_LOGV(TAG, "TRANSPORT_DATA: %08x:%d", addr->u_addr.ip4.addr, port); - - msg_data = (struct message_transport_data *)data; - peer = peer_lookup_by_receiver(device, msg_data->receiver); - if (peer) { - // header is 16 bytes long so take that off the length - wireguardif_process_data_message(device, peer, msg_data, len - 16, addr, port); - } - break; - - default: - // Unknown or bad packet header - break; - } - // Release data! - pbuf_free(p); -} - -static err_t wireguard_start_handshake(struct netif *netif, struct wireguard_peer *peer) { - struct wireguard_device *device = (struct wireguard_device *)netif->state; - err_t result; - struct pbuf *pbuf; - struct message_handshake_initiation msg; - - pbuf = wireguardif_initiate_handshake(device, peer, &msg, &result); - if (pbuf) { - result = wireguardif_peer_output(netif, pbuf, peer); - log_i(TAG "start handshake %08x,%d - %d", peer->ip.u_addr.ip4.addr, peer->port, result); - pbuf_free(pbuf); - peer->send_handshake = false; - peer->last_initiation_tx = wireguard_sys_now(); - memcpy(peer->handshake_mac1, msg.mac1, WIREGUARD_COOKIE_LEN); - peer->handshake_mac1_valid = true; - } - return result; -} - -static err_t wireguardif_lookup_peer(struct netif *netif, u8_t peer_index, struct wireguard_peer **out) { - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("state != NULL", (netif->state != NULL)); - struct wireguard_device *device = (struct wireguard_device *)netif->state; - struct wireguard_peer *peer = NULL; - err_t result; - - if (device->valid) { - peer = peer_lookup_by_peer_index(device, peer_index); - if (peer) { - result = ERR_OK; - } else { - result = ERR_ARG; - } - } else { - result = ERR_ARG; - } - *out = peer; - return result; -} - -err_t wireguardif_connect(struct netif *netif, u8_t peer_index) { - struct wireguard_peer *peer; - err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); - if (result == ERR_OK) { - // Check that a valid connect ip and port have been set - if (!ip_addr_isany(&peer->connect_ip) && (peer->connect_port > 0)) { - // Set the flag that we want to try connecting - peer->active = true; - peer->ip = peer->connect_ip; - peer->port = peer->connect_port; - result = ERR_OK; - } else { - result = ERR_ARG; - } - } - return result; -} - -err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index) { - struct wireguard_peer *peer; - err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); - if (result == ERR_OK) { - // Set the flag that we want to try connecting - peer->active = false; - // Wipe out current keys - keypair_destroy(&peer->next_keypair); - keypair_destroy(&peer->curr_keypair); - keypair_destroy(&peer->prev_keypair); - result = ERR_OK; - } - return result; -} - -err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port) { - struct wireguard_peer *peer; - err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); - if (result == ERR_OK) { - if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { - result = ERR_OK; - } else { - result = ERR_CONN; - } - if (current_ip) { - *current_ip = peer->ip; - } - if (current_port) { - *current_port = peer->port; - } - } - return result; -} - -err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index) { - struct wireguard_peer *peer; - err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); - if (result == ERR_OK) { - crypto_zero(peer, sizeof(struct wireguard_peer)); - peer->valid = false; - result = ERR_OK; - } - return result; -} - -err_t wireguardif_update_endpoint(struct netif *netif, u8_t peer_index, const ip_addr_t *ip, u16_t port) { - struct wireguard_peer *peer; - err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); - if (result == ERR_OK) { - peer->connect_ip = *ip; - peer->connect_port = port; - result = ERR_OK; - } - return result; -} - - -err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *p, u8_t *peer_index) { - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("state != NULL", (netif->state != NULL)); - LWIP_ASSERT("p != NULL", (p != NULL)); - struct wireguard_device *device = (struct wireguard_device *)netif->state; - err_t result; - uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN]; - size_t public_key_len = sizeof(public_key); - struct wireguard_peer *peer = NULL; - - uint32_t t1 = wireguard_sys_now(); - - if (wireguard_base64_decode(p->public_key, public_key, &public_key_len) - && (public_key_len == WIREGUARD_PUBLIC_KEY_LEN)) { - - // See if the peer is already registered - peer = peer_lookup_by_pubkey(device, public_key); - if (!peer) { - // Not active - see if we have room to allocate a new one - peer = peer_alloc(device); - if (peer) { - - if (wireguard_peer_init(device, peer, public_key, p->preshared_key)) { - - peer->connect_ip = p->endpoint_ip; - peer->connect_port = p->endport_port; - peer->ip = peer->connect_ip; - peer->port = peer->connect_port; - if (p->keep_alive == WIREGUARDIF_KEEPALIVE_DEFAULT) { - peer->keepalive_interval = KEEPALIVE_TIMEOUT; - } else { - peer->keepalive_interval = p->keep_alive; - } - peer_add_ip(peer, p->allowed_ip, p->allowed_mask); - memcpy(peer->greatest_timestamp, p->greatest_timestamp, sizeof(peer->greatest_timestamp)); - - result = ERR_OK; - } else { - result = ERR_ARG; - } - } else { - result = ERR_MEM; - } - } else { - result = ERR_OK; - } - } else { - result = ERR_ARG; - } - - uint32_t t2 = wireguard_sys_now(); - log_i(TAG "Adding peer took %ums\r\n", (t2-t1)); - - if (peer_index) { - if (peer) { - *peer_index = wireguard_peer_index(device, peer); - } else { - *peer_index = WIREGUARDIF_INVALID_INDEX; - } - } - return result; -} - -static bool should_send_initiation(struct wireguard_peer *peer) { - bool result = false; - if (wireguardif_can_send_initiation(peer)) { - if (peer->send_handshake) { - result = true; - } else if (peer->curr_keypair.valid && !peer->curr_keypair.initiator && wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME - peer->keepalive_interval)) { - result = true; - } else if (!peer->curr_keypair.valid && peer->active) { - result = true; - } - } - return result; -} - -static bool should_send_keepalive(struct wireguard_peer *peer) { - bool result = false; - if (peer->keepalive_interval > 0) { - if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { - if (wireguard_expired(peer->last_tx, peer->keepalive_interval)) { - result = true; - } - } - } - return result; -} - -static bool should_destroy_current_keypair(struct wireguard_peer *peer) { - bool result = false; - if (peer->curr_keypair.valid && - (wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME) || - (peer->curr_keypair.sending_counter >= REJECT_AFTER_MESSAGES)) - ) { - result = true; - } - return result; -} - -static bool should_reset_peer(struct wireguard_peer *peer) { - bool result = false; - if (peer->curr_keypair.valid && (wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME * 3))) { - result = true; - } - return result; -} - -static void wireguardif_tmr(void *arg) { - struct wireguard_device *device = (struct wireguard_device *)arg; - struct wireguard_peer *peer; - int x; - // Reschedule this timer - sys_timeout(WIREGUARDIF_TIMER_MSECS, wireguardif_tmr, device); - - // Check periodic things - bool link_up = false; - for (x=0; x < WIREGUARD_MAX_PEERS; x++) { - peer = &device->peers[x]; - if (peer->valid) { - // Do we need to rekey / send a handshake? - if (should_reset_peer(peer)) { - // Nothing back for too long - we should wipe out all crypto state - keypair_destroy(&peer->next_keypair); - keypair_destroy(&peer->curr_keypair); - keypair_destroy(&peer->prev_keypair); - handshake_destroy(&peer->handshake); - - // Revert back to default IP/port if these were altered - peer->ip = peer->connect_ip; - peer->port = peer->connect_port; - } - if (should_destroy_current_keypair(peer)) { - // Destroy current keypair - keypair_destroy(&peer->curr_keypair); - } - if (should_send_keepalive(peer)) { - wireguardif_send_keepalive(device, peer); - } - if (should_send_initiation(peer)) { - wireguard_start_handshake(device->netif, peer); - } - - if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { - link_up = true; - } - } - } - - if (!link_up) { - // Clear the IF-UP flag on netif - netif_set_link_down(device->netif); - } -} - -void wireguardif_shutdown(struct netif *netif) { - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("state != NULL", (netif->state != NULL)); - - struct wireguard_device * device = (struct wireguard_device *)netif->state; - // Disable timer. - sys_untimeout(wireguardif_tmr, device); - // remove UDP context. - if( device->udp_pcb ) { - udp_disconnect(device->udp_pcb); - udp_remove(device->udp_pcb); - device->udp_pcb = NULL; - } - // remove device context. - free(device); - netif->state = NULL; -} - -err_t wireguardif_init(struct netif *netif) { - err_t result; - struct wireguardif_init_data *init_data; - struct wireguard_device *device; - struct udp_pcb *udp; - uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN]; - size_t private_key_len = sizeof(private_key); - - struct netif* underlying_netif; - /* All eddits for FOR LAN8720 */ - //tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &underlying_netif); //original - underlying_netif = netif_default; // Use current netif as the underlying netif of the WireGuard interface. - /* All eddits for FOR LAN8720 */ - - - log_i(TAG "underlying_netif = %p", underlying_netif); - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - LWIP_ASSERT("state != NULL", (netif->state != NULL)); - - // We need to initialise the wireguard module - wireguard_init(); - log_i(TAG "wireguard module initialized."); - - if (netif && netif->state) { - - // The init data is passed into the netif_add call as the 'state' - we will replace this with our private state data - init_data = (struct wireguardif_init_data *)netif->state; - - // Clear out and set if function is successful - netif->state = NULL; - - if (wireguard_base64_decode(init_data->private_key, private_key, &private_key_len) - && (private_key_len == WIREGUARD_PRIVATE_KEY_LEN)) { - - udp = udp_new(); - - if (udp) { - result = udp_bind(udp, IP_ADDR_ANY, init_data->listen_port); // Note this listens on all interfaces! Really just want the passed netif - if (result == ERR_OK) { - device = (struct wireguard_device *)mem_calloc(1, sizeof(struct wireguard_device)); - if (device) { - device->netif = netif; - device->underlying_netif = underlying_netif; - //udp_bind_netif(udp, underlying_netif); - - device->udp_pcb = udp; - log_d(TAG "start device initialization"); - // Per-wireguard netif/device setup - uint32_t t1 = wireguard_sys_now(); - if (wireguard_device_init(device, private_key)) { - uint32_t t2 = wireguard_sys_now(); - log_d(TAG "Device init took %ums\r\n", (t2-t1)); - -#if LWIP_CHECKSUM_CTRL_PER_NETIF - NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); -#endif - netif->state = device; - netif->name[0] = 'w'; - netif->name[1] = 'g'; - netif->output = wireguardif_output; - netif->linkoutput = NULL; - netif->hwaddr_len = 0; - netif->mtu = WIREGUARDIF_MTU; - // We set up no state flags here - caller should set them - // NETIF_FLAG_LINK_UP is automatically set/cleared when at least one peer is connected - netif->flags = 0; - - udp_recv(udp, wireguardif_network_rx, device); - - // Start a periodic timer for this wireguard device - sys_timeout(WIREGUARDIF_TIMER_MSECS, wireguardif_tmr, device); - - result = ERR_OK; - } else { - log_e(TAG "failed to initialize WireGuard device."); - mem_free(device); - device = NULL; - udp_remove(udp); - result = ERR_ARG; - } - } else { - log_e(TAG "failed to allocate device context."); - udp_remove(udp); - result = ERR_MEM; - } - } else { - log_e(TAG "failed to bind UDP err=%d", result); - udp_remove(udp); - } - - } else { - log_e(TAG "failed to allocate UDP"); - result = ERR_MEM; - } - } else { - log_e(TAG "invalid init_data private key"); - result = ERR_ARG; - } - } else { - log_e(TAG "netif or state is NULL: netif=%p, netif.state:%p", netif, netif ? netif->state : NULL); - result = ERR_ARG; - } - return result; -} - -void wireguardif_peer_init(struct wireguardif_peer *peer) { - LWIP_ASSERT("peer != NULL", (peer != NULL)); - memset(peer, 0, sizeof(struct wireguardif_peer)); - // Caller must provide 'public_key' - peer->public_key = NULL; - ip_addr_set_any(false, &peer->endpoint_ip); - peer->endport_port = WIREGUARDIF_DEFAULT_PORT; - peer->keep_alive = WIREGUARDIF_KEEPALIVE_DEFAULT; - ip_addr_set_any(false, &peer->allowed_ip); - ip_addr_set_any(false, &peer->allowed_mask); - memset(peer->greatest_timestamp, 0, sizeof(peer->greatest_timestamp)); - peer->preshared_key = NULL; -} diff --git a/lib/WireGuard-ESP32/src/wireguardif.h b/lib/WireGuard-ESP32/src/wireguardif.h deleted file mode 100644 index ad9d4a1..0000000 --- a/lib/WireGuard-ESP32/src/wireguardif.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) - * The original license is below: - * - * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of - * its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Daniel Hope - */ - - -#ifndef _WIREGUARDIF_H_ -#define _WIREGUARDIF_H_ - -#include "lwip/arch.h" -#include "lwip/netif.h" -#include "lwip/ip_addr.h" - -// Default MTU for WireGuard is 1420 bytes -#define WIREGUARDIF_MTU (1420) - -#define WIREGUARDIF_DEFAULT_PORT (51820) -#define WIREGUARDIF_KEEPALIVE_DEFAULT (0xFFFF) - -struct wireguardif_init_data { - // Required: the private key of this WireGuard network interface - const char *private_key; - // Required: What UDP port to listen on - u16_t listen_port; - // Optional: restrict send/receive of encapsulated WireGuard traffic to this network interface only (NULL to use routing table) - struct netif *bind_netif; -}; - -struct wireguardif_peer { - const char *public_key; - // Optional pre-shared key (32 bytes) - make sure this is NULL if not to be used - const uint8_t *preshared_key; - // tai64n of largest timestamp we have seen during handshake to avoid replays - uint8_t greatest_timestamp[12]; - - // Allowed ip/netmask (can add additional later but at least one is required) - ip_addr_t allowed_ip; - ip_addr_t allowed_mask; - - // End-point details (may be blank) - ip_addr_t endpoint_ip; - u16_t endport_port; - u16_t keep_alive; -}; - -#define WIREGUARDIF_INVALID_INDEX (0xFF) - -/* static struct netif wg_netif_struct = {0}; - * struct wireguard_interface wg; - * wg.private_key = "abcdefxxx..xxxxx="; - * wg.listen_port = 51820; - * wg.bind_netif = NULL; // Pass netif to listen on, NULL for all interfaces - * - * netif = netif_add(&netif_struct, &ipaddr, &netmask, &gateway, &wg, &wireguardif_init, &ip_input); - * - * netif_set_up(wg_net); - * - * struct wireguardif_peer peer; - * wireguardif_peer_init(&peer); - * peer.public_key = "apoehc...4322abcdfejg=; - * peer.preshared_key = NULL; - * peer.allowed_ip = allowed_ip; - * peer.allowed_mask = allowed_mask; - * - * // If you want to enable output connection - * peer.endpoint_ip = peer_ip; - * peer.endport_port = 12345; - * - * uint8_t wireguard_peer_index; - * wireguardif_add_peer(netif, &peer, &wireguard_peer_index); - * - * if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) { - * // Start outbound connection to peer - * wireguardif_connect(wg_net, wireguard_peer_index); - * } - * - */ - -// Initialise a new WireGuard network interface (netif) -err_t wireguardif_init(struct netif *netif); - -// Shutdown a WireGuard network interface (netif) -void wireguardif_shutdown(struct netif *netif); - -// Helper to initialise the peer struct with defaults -void wireguardif_peer_init(struct wireguardif_peer *peer); - -// Add a new peer to the specified interface - see wireguard.h for maximum number of peers allowed -// On success the peer_index can be used to reference this peer in future function calls -err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *peer, u8_t *peer_index); - -// Remove the given peer from the network interface -err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index); - -// Update the "connect" IP of the given peer -err_t wireguardif_update_endpoint(struct netif *netif, u8_t peer_index, const ip_addr_t *ip, u16_t port); - -// Try and connect to the given peer -err_t wireguardif_connect(struct netif *netif, u8_t peer_index); - -// Stop trying to connect to the given peer -err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index); - -// Is the given peer "up"? A peer is up if it has a valid session key it can communicate with -err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port); - -#endif /* _WIREGUARDIF_H_ */ diff --git a/platformio.ini b/platformio.ini index 5a59738..b4a9ac3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,7 +38,8 @@ monitor_filters = esp32_exception_decoder, default ;, log2file monitor_speed = 115200 upload_speed = 460800 extra_scripts = - pre:tools/build/version_increment_pre.py + ;pre:tools/build/version_increment_pre.py + pre:tools/build/version_update.py pre:tools/webfilesbuilder/build_html.py post:tools/build/build.py build_flags = diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..a3ab302 --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,1315 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "etc.h" + +Preferences preferences; + +#include "nvs.h" +#include "nvs_flash.h" +#include "HTTPClient.h" + +extern struct SysVarsStruct vars; +extern struct BrdConfigStruct hwConfig; +extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT]; + +extern struct SystemConfigStruct systemCfg; +extern struct NetworkConfigStruct networkCfg; +extern struct VpnConfigStruct vpnCfg; +extern struct MqttConfigStruct mqttCfg; + +const char *networkConfigKey = "network-config"; +const char *wifiEnableKey = "wifiEnable"; +const char *wifiSsidKey = "wifiSsid"; +const char *wifiPasswordKey = "wifiPassword"; +const char *wifiDhcpKey = "wifiDhcp"; +const char *wifiAddrKey = "wifiAddr"; +const char *wifiMaskKey = "wifiMask"; +const char *wifiGateKey = "wifiGate"; +const char *wifiDns1Key = "wifiDns1"; +const char *wifiDns2Key = "wifiDns2"; +const char *ethEnableKey = "ethEnable"; +const char *ethDhcpKey = "ethDhcp"; +const char *ethAddrKey = "ethAddr"; +const char *ethMaskKey = "ethMask"; +const char *ethGateKey = "ethGate"; +const char *ethDns1Key = "ethDns1"; +const char *ethDns2Key = "ethDns2"; + +const char *vpnConfigKey = "vpn-config"; +const char *wgEnableKey = "wgEnable"; +const char *wgLocalIPKey = "wgLocalIP"; +const char *wgLocalPrivKeyKey = "wgLocalPrivKey"; +const char *wgEndAddrKey = "wgEndAddr"; +const char *wgEndPubKeyKey = "wgEndPubKey"; +const char *wgEndPortKey = "wgEndPort"; +const char *hnEnableKey = "hnEnable"; +const char *hnJoinCodeKey = "hnJoinCode"; +const char *hnHostNameKey = "hnHostName"; +const char *hnDashUrlKey = "hnDashUrl"; + +const char *mqttConfigKey = "mqtt-config"; +const char *enableKey = "enable"; +const char *serverKey = "server"; +//const char *serverIPKey = "serverIP"; +const char *portKey = "port"; +const char *userKey = "user"; +const char *passKey = "pass"; +const char *topicKey = "topic"; +const char *intervalKey = "interval"; +const char *updateIntKey = "updateInt"; +const char *discoveryKey = "discovery"; +//const char *reconnectTimeKey = "reconnectTime"; +const char *reconnectIntKey = "reconnectIntKey"; +//const char *heartbeatTimeKey = "heartbeatTime"; + +const char *systemConfigKey = "system-config"; +const char *keepWebKey = "keepWeb"; +const char *disableWebKey = "disableWeb"; +const char *webAuthKey = "webAuth"; +const char *webUserKey = "webUser"; +const char *webPassKey = "webPass"; +const char *fwEnabledKey = "fwEnabled"; +const char *fwIpKey = "fwIp"; +const char *serialSpeedKey = "serialSpeed"; +const char *socketPortKey = "socketPort"; +const char *tempOffsetKey = "tempOffset"; +const char *disableLedUSBKey = "disableLedUSB"; +const char *disableLedPwrKey = "disableLedPwr"; +const char *disableLedsKey = "disableLeds"; +const char *refreshLogsKey = "refreshLogs"; +const char *hostnameKey = "hostname"; +const char *timeZoneKey = "timeZone"; +const char *ntpServ1Key = "ntpServ1"; +const char *ntpServ2Key = "ntpServ2"; +// const char *prevWorkModeKey = "prevWorkMode"; +// const char *workModeKey = "prevWorkMode"; + +const char *systemVarsKey = "system-vars"; +const char *hwBtnIsKey = "hwBtnIs"; +const char *hwLedUsbIsKey = "hwLedUsbIs"; +const char *hwLedPwrIsKey = "hwLedPwrIs"; +const char *hwUartSelIsKey = "hwUartSelIs"; +const char *hwZigbeeIsKey = "hwZigbeeIs"; +const char *workModeKey = "workMode"; +const char *connectedSocketKey = "connectedSocket"; +const char *connectedClientsKey = "connectedClients"; +const char *socketTimeKey = "socketTime"; +const char *connectedEtherKey = "connectedEther"; +const char *apStartedKey = "apStarted"; +const char *wifiWebSetupInProgressKey = "wifiWebSetupInProgress"; +const char *vpnWgInitKey = "vpnWgInit"; +const char *vpnWgConnectKey = "vpnWgConnect"; +const char *vpnWgPeerIpKey = "vpnWgPeerIp"; +const char *vpnWgCheckTimeKey = "vpnWgCheckTimeKey"; +const char *vpnHnInitKey = "vpnHnInit"; +const char *mqttConnKey = "mqttConn"; +const char *mqttReconnectTimeKey = "mqttReconnectTime"; +const char *mqttHeartbeatTimeKey = "mqttHeartbeatTime"; +const char *zbLedStateKey = "zbLedState"; +const char *zbFlashingKey = "zbFlashing"; + +String tag = "NVS"; + +void printNVSFreeSpace() +{ + nvs_stats_t nvsStats; + nvs_get_stats(NULL, &nvsStats); + + LOGI(tag, "Total Entries: %d, Used Entries: %d, Free Entries: %d", nvsStats.total_entries, nvsStats.used_entries, (nvsStats.total_entries - nvsStats.used_entries)); +} + +void eraseNVS() +{ + LOGI(tag, "Going to erase NVS. It will factory reset device."); + int timeDelay = 10; + for (int i = 0; i < timeDelay; i++) + { + LOGI(tag, "%d seconds left..", (timeDelay - i)); + delay(1000); + } + LOGI(tag, "Erasing NVS. It will factory reset device!"); + ESP_ERROR_CHECK(nvs_flash_erase()); + esp_err_t ret = nvs_flash_init(); + ESP_ERROR_CHECK(ret); + LOGI(tag, "Erase complete!"); +} + +void initNVS() +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + LOGI(tag, "ESP_ERR_NVS_NO_FREE_PAGES || ESP_ERR_NVS_NEW_VERSION_FOUND . DOWNGRADE and BACKUP CONFIG"); + while (true) + { + delay(1); // stop any work + } + // eraseNVS(); + } + ESP_ERROR_CHECK(ret); +} + +String makeJsonConfig(const NetworkConfigStruct *networkCfg, + const VpnConfigStruct *vpnCfg, + const MqttConfigStruct *mqttCfg, + const SystemConfigStruct *systemCfg, + const SysVarsStruct *systemVars) +{ + StaticJsonDocument<2048> doc; + + if (networkCfg != nullptr) + { + JsonObject network = doc.createNestedObject(networkConfigKey); + serializeNetworkConfigToJson(*networkCfg, network); + } + + if (vpnCfg != nullptr) + { + JsonObject vpn = doc.createNestedObject(vpnConfigKey); + serializeVpnConfigToJson(*vpnCfg, vpn); + } + + if (mqttCfg != nullptr) + { + JsonObject mqtt = doc.createNestedObject(mqttConfigKey); + serializeMqttConfigToJson(*mqttCfg, mqtt); + } + + if (systemCfg != nullptr) + { + JsonObject system = doc.createNestedObject(systemConfigKey); + serializeSystemConfigToJson(*systemCfg, system); + } + + if (systemVars != nullptr) + { + JsonObject varsJson = doc.createNestedObject(systemVarsKey); + serializeSysVarsToJson(*systemVars, varsJson); + } + + String output; + serializeJsonPretty(doc, output); + return output; +} + +void saveNetworkConfig(const NetworkConfigStruct &config) +{ + preferences.begin(networkConfigKey, false); + + preferences.putBool(wifiEnableKey, config.wifiEnable); + preferences.putString(wifiSsidKey, config.wifiSsid); + preferences.putString(wifiPasswordKey, config.wifiPassword); + preferences.putBool(wifiDhcpKey, config.wifiDhcp); + preferences.putString(wifiAddrKey, config.wifiAddr.toString()); + preferences.putString(wifiMaskKey, config.wifiMask.toString()); + preferences.putString(wifiGateKey, config.wifiGate.toString()); + preferences.putString(wifiDns1Key, config.wifiDns1.toString()); + preferences.putString(wifiDns2Key, config.wifiDns2.toString()); + + preferences.putBool(ethEnableKey, config.ethEnable); + preferences.putBool(ethDhcpKey, config.ethDhcp); + preferences.putString(ethAddrKey, config.ethAddr.toString()); + preferences.putString(ethMaskKey, config.ethMask.toString()); + preferences.putString(ethGateKey, config.ethGate.toString()); + preferences.putString(ethDns1Key, config.ethDns1.toString()); + preferences.putString(ethDns2Key, config.ethDns2.toString()); + + preferences.end(); +} + +void loadNetworkConfig(NetworkConfigStruct &config) +{ + preferences.begin(networkConfigKey, true); + + config.wifiEnable = preferences.getBool(wifiEnableKey, false); + strlcpy(config.wifiSsid, preferences.getString(wifiSsidKey).c_str(), sizeof(config.wifiSsid)); + strlcpy(config.wifiPassword, preferences.getString(wifiPasswordKey).c_str(), sizeof(config.wifiPassword)); + config.wifiDhcp = preferences.getBool(wifiDhcpKey, true); + config.wifiAddr.fromString(preferences.getString(wifiAddrKey)); + config.wifiMask.fromString(preferences.getString(wifiMaskKey, NETWORK_MASK)); + config.wifiGate.fromString(preferences.getString(wifiGateKey)); + config.wifiDns1.fromString(preferences.getString(wifiDns1Key, DNS_SERV_1)); + config.wifiDns2.fromString(preferences.getString(wifiDns2Key, DNS_SERV_2)); + + config.ethEnable = preferences.getBool(ethEnableKey, true); + config.ethDhcp = preferences.getBool(ethDhcpKey, true); + config.ethAddr.fromString(preferences.getString(ethAddrKey)); + config.ethMask.fromString(preferences.getString(ethMaskKey, NETWORK_MASK)); + config.ethGate.fromString(preferences.getString(ethGateKey)); + config.ethDns1.fromString(preferences.getString(ethDns1Key, DNS_SERV_1)); + config.ethDns2.fromString(preferences.getString(ethDns2Key, DNS_SERV_2)); + + preferences.end(); +} + +void saveVpnConfig(const VpnConfigStruct &config) +{ + preferences.begin(vpnConfigKey, false); + + preferences.putBool(wgEnableKey, config.wgEnable); + preferences.putString(wgLocalIPKey, config.wgLocalIP.toString()); + preferences.putString(wgLocalPrivKeyKey, config.wgLocalPrivKey); + preferences.putString(wgEndAddrKey, config.wgEndAddr); + preferences.putString(wgEndPubKeyKey, config.wgEndPubKey); + preferences.putInt(wgEndPortKey, config.wgEndPort); + + preferences.putBool(hnEnableKey, config.hnEnable); + preferences.putString(hnJoinCodeKey, config.hnJoinCode); + preferences.putString(hnHostNameKey, config.hnHostName); + preferences.putString(hnDashUrlKey, config.hnDashUrl); + + preferences.end(); +} + +void loadVpnConfig(VpnConfigStruct &config) +{ + preferences.begin(vpnConfigKey, true); + + config.wgEnable = preferences.getBool(wgEnableKey, false); + config.wgLocalIP.fromString(preferences.getString(wgLocalIPKey)); + strlcpy(config.wgLocalPrivKey, preferences.getString(wgLocalPrivKeyKey).c_str(), sizeof(config.wgLocalPrivKey)); + strlcpy(config.wgEndAddr, preferences.getString(wgEndAddrKey).c_str(), sizeof(config.wgEndAddr)); + strlcpy(config.wgEndPubKey, preferences.getString(wgEndPubKeyKey).c_str(), sizeof(config.wgEndPubKey)); + config.wgEndPort = preferences.getInt(wgEndPortKey); + + config.hnEnable = preferences.getBool(hnEnableKey, false); + strlcpy(config.hnJoinCode, preferences.getString(hnJoinCodeKey).c_str(), sizeof(config.hnJoinCode)); + strlcpy(config.hnHostName, preferences.getString(hnHostNameKey).c_str(), sizeof(config.hnHostName)); + strlcpy(config.hnDashUrl, preferences.getString(hnDashUrlKey).c_str(), sizeof(config.hnDashUrl)); + + preferences.end(); +} + +void saveMqttConfig(const MqttConfigStruct &config) +{ + preferences.begin(mqttConfigKey, false); + + preferences.putBool(enableKey, config.enable); + // preferences.putBool(connectKey, config.connect); + preferences.putString(serverKey, config.server); + //preferences.putString(serverIPKey, config.serverIP.toString()); + preferences.putInt(portKey, config.port); + preferences.putString(userKey, config.user); + preferences.putString(passKey, config.pass); + preferences.putString(topicKey, config.topic); + // preferences.putBool(retainKey, config.retain); // If needed + preferences.putInt(updateIntKey, config.updateInt); + preferences.putBool(discoveryKey, config.discovery); + preferences.putULong(reconnectIntKey, config.reconnectInt); + //preferences.putULong(heartbeatTimeKey, config.heartbeatTime); + + preferences.end(); +} + +void loadMqttConfig(MqttConfigStruct &config) +{ + preferences.begin(mqttConfigKey, true); + + config.enable = preferences.getBool(enableKey, false); + // config.connect = preferences.getBool(connect, false); + strlcpy(config.server, preferences.getString(serverKey, "").c_str(), sizeof(config.server)); + //config.serverIP.fromString(preferences.getString(serverIPKey)); + config.port = preferences.getInt(portKey, 1883); + strlcpy(config.user, preferences.getString(userKey, "").c_str(), sizeof(config.user)); + strlcpy(config.pass, preferences.getString(passKey, "").c_str(), sizeof(config.pass)); + strlcpy(config.topic, preferences.getString(topicKey, "").c_str(), sizeof(config.topic)); + // config.retain = preferences.getBool(retain, false); // If needed + config.updateInt = preferences.getInt(updateIntKey, 60); + config.discovery = preferences.getBool(discoveryKey, true); + config.reconnectInt = preferences.getULong(reconnectIntKey, 15); + //config.heartbeatTime = preferences.getULong(heartbeatTimeKey, 60000); + + preferences.end(); +} + +void saveSystemConfig(const SystemConfigStruct &config) +{ + preferences.begin(systemConfigKey, false); + + preferences.putBool(keepWebKey, config.keepWeb); + preferences.putBool(disableWebKey, config.disableWeb); + preferences.putBool(webAuthKey, config.webAuth); + preferences.putString(webUserKey, config.webUser); + preferences.putString(webPassKey, config.webPass); + preferences.putBool(fwEnabledKey, config.fwEnabled); + preferences.putString(fwIpKey, config.fwIp.toString()); + preferences.putInt(serialSpeedKey, config.serialSpeed); + preferences.putInt(socketPortKey, config.socketPort); + preferences.putInt(tempOffsetKey, config.tempOffset); + preferences.putBool(disableLedUSBKey, config.disableLedUSB); + preferences.putBool(disableLedPwrKey, config.disableLedPwr); + preferences.putBool(disableLedsKey, config.disableLeds); + preferences.putInt(refreshLogsKey, config.refreshLogs); + preferences.putString(hostnameKey, config.hostname); + preferences.putString(timeZoneKey, config.timeZone); + preferences.putString(ntpServ1Key, config.ntpServ1); + preferences.putString(ntpServ2Key, config.ntpServ2); + // preferences.putInt(prevWorkModeKey, static_cast(config.prevWorkMode)); + preferences.putInt(workModeKey, static_cast(config.workMode)); + + preferences.end(); +} + +void loadSystemConfig(SystemConfigStruct &config) +{ + preferences.begin(systemConfigKey, true); + + config.keepWeb = preferences.getBool(keepWebKey, true); + config.disableWeb = preferences.getBool(disableWebKey, false); + config.webAuth = preferences.getBool(webAuthKey, false); + strlcpy(config.webUser, preferences.getString(webUserKey, "").c_str(), sizeof(config.webUser)); + strlcpy(config.webPass, preferences.getString(webPassKey, "").c_str(), sizeof(config.webPass)); + config.fwEnabled = preferences.getBool(fwEnabledKey, false); + config.fwIp.fromString(preferences.getString(fwIpKey, "0.0.0.0")); + config.serialSpeed = preferences.getInt(serialSpeedKey, ZB_SERIAL_SPEED); + config.socketPort = preferences.getInt(socketPortKey, ZB_TCP_PORT); + config.tempOffset = preferences.getInt(tempOffsetKey, 0); + config.disableLedUSB = preferences.getBool(disableLedUSBKey, false); + config.disableLedPwr = preferences.getBool(disableLedPwrKey, false); + config.disableLeds = preferences.getBool(disableLedsKey, false); + config.refreshLogs = preferences.getInt(refreshLogsKey, 1000); + strlcpy(config.hostname, preferences.getString(hostnameKey, "XZG").c_str(), sizeof(config.hostname)); /// to do add def host name!! + strlcpy(config.timeZone, preferences.getString(timeZoneKey, NTP_TIME_ZONE).c_str(), sizeof(config.timeZone)); + strlcpy(config.ntpServ1, preferences.getString(ntpServ1Key, NTP_SERV_1).c_str(), sizeof(config.ntpServ1)); + strlcpy(config.ntpServ2, preferences.getString(ntpServ2Key, NTP_SERV_2).c_str(), sizeof(config.ntpServ2)); + // config.prevWorkMode = static_cast(preferences.getInt(prevWorkMode, WORK_MODE_NETWORK)); + // config.prevWorkMode = static_cast(preferences.getInt(prevWorkModeKey, WORK_MODE_NETWORK)); + config.workMode = static_cast(preferences.getInt(workModeKey, WORK_MODE_NETWORK)); + + preferences.end(); +} + +enum API_PAGE_t : uint8_t +{ + API_PAGE_ROOT, + API_PAGE_GENERAL, + API_PAGE_ETHERNET, + API_PAGE_NETWORK, + API_PAGE_ZIGBEE, + API_PAGE_SECURITY, + API_PAGE_TOOLS, + API_PAGE_ABOUT, + API_PAGE_MQTT, + API_PAGE_VPN +}; + +void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, NetworkConfigStruct &configNet, VpnConfigStruct &configVpn, MqttConfigStruct &configMqtt) +{ + const char *pageId = "pageId"; + const char *on = "on"; + const char *contTypeText = "text/plain"; + + if (serverWeb.hasArg(pageId)) + { + switch (serverWeb.arg(pageId).toInt()) + { + case API_PAGE_GENERAL: + { + if (serverWeb.hasArg(coordMode)) + { + const uint8_t mode = serverWeb.arg(coordMode).toInt(); + if (mode <= 2 && mode >= 0) + { + // vars.workMode = static_cast(mode); + // if (mode == 1) + // wifiWebSetupInProgress = true; //to do + configSys.workMode = static_cast(mode); + } + } + if (serverWeb.hasArg(keepWebKey)) + { + configSys.keepWeb = serverWeb.arg(keepWebKey) == on; + } + + + if (serverWeb.hasArg(disableLedPwrKey)) + { + configSys.disableLedPwr = serverWeb.arg(disableLedPwrKey) == on; + } + + + if (serverWeb.hasArg(disableLedUSBKey)) + { + configSys.disableLedUSB = serverWeb.arg(disableLedUSBKey) == on; + } + + + if (serverWeb.hasArg(refreshLogsKey)) + { + configSys.refreshLogs = serverWeb.arg(refreshLogsKey).toInt(); + } + + const char *hostname = "hostname"; + if (serverWeb.hasArg(hostname)) + { + // Ensure the string does not exceed 49 characters, leaving space for the null terminator + strncpy(configSys.hostname, serverWeb.arg(hostname).c_str(), sizeof(configSys.hostname) - 1); + configSys.hostname[sizeof(configSys.hostname) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *timeZoneName = "timeZoneName"; + if (serverWeb.hasArg(timeZoneName)) + { + strncpy(configSys.timeZone, serverWeb.arg(timeZoneName).c_str(), sizeof(configSys.timeZone) - 1); + configSys.timeZone[sizeof(configSys.timeZone) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *ntpServ1 = "ntpServ1"; + if (serverWeb.hasArg(ntpServ1)) + { + strncpy(configSys.ntpServ1, serverWeb.arg(ntpServ1).c_str(), sizeof(configSys.ntpServ1) - 1); + configSys.ntpServ1[sizeof(configSys.ntpServ1) - 1] = '\0'; // Guarantee a null terminator at the end + } + const char *ntpServ2 = "ntpServ2"; + if (serverWeb.hasArg(ntpServ2)) + { + strncpy(configSys.ntpServ2, serverWeb.arg(ntpServ2).c_str(), sizeof(configSys.ntpServ2) - 1); + configSys.ntpServ2[sizeof(configSys.ntpServ2) - 1] = '\0'; // Guarantee a null terminator at the end + } + + saveSystemConfig(configSys); + } + break; + case API_PAGE_NETWORK: + { + const char *ethEnableKey = "ethEnbl"; + configNet.ethEnable = serverWeb.hasArg(ethEnableKey) == true; + + const char *ethDhcpKey = "dhcp"; + configNet.ethDhcp = serverWeb.hasArg(ethDhcpKey) == true; + + const char *ethAddrKey = "ipAddress"; + if (serverWeb.hasArg(ethAddrKey)) + { + configNet.ethAddr.fromString(serverWeb.arg(ethAddrKey)); + } + const char *ethMaskKey = "ipMask"; + if (serverWeb.hasArg(ethMaskKey)) + { + configNet.ethMask.fromString(serverWeb.arg(ethMaskKey)); + } + const char *ethGateKey = "ipGW"; + if (serverWeb.hasArg(ethGateKey)) + { + configNet.ethGate.fromString(serverWeb.arg(ethGateKey)); + } + const char *ethDns1Key = "ethDns1"; + if (serverWeb.hasArg(ethDns1Key)) + { + configNet.ethDns1.fromString(serverWeb.arg(ethDns1Key)); + } + const char *ethDns2Key = "ethDns2"; + if (serverWeb.hasArg(ethDns2Key)) + { + configNet.ethDns2.fromString(serverWeb.arg(ethDns2Key)); + } + + const char *wifiEnableKey = "wifiEnbl"; + configNet.wifiEnable = serverWeb.hasArg(wifiEnableKey) == true; + + const char *wifiDhcpKey = "dhcpWiFi"; + configNet.wifiDhcp = serverWeb.hasArg(wifiDhcpKey) == true; + + const char *wifiSsidKey = "WIFISSID"; + if (serverWeb.arg(wifiSsidKey)) + { + strncpy(configNet.wifiSsid, serverWeb.arg(wifiSsidKey).c_str(), sizeof(configNet.wifiSsid) - 1); + configNet.wifiSsid[sizeof(configNet.wifiSsid) - 1] = '\0'; // Guarantee a null terminator at the end + } + const char *wifiPasswordKey = "WIFIpassword"; + if (serverWeb.arg("WIFIpassword")) + { + strncpy(configNet.wifiPassword, serverWeb.arg(wifiPasswordKey).c_str(), sizeof(configNet.wifiPassword) - 1); + configNet.wifiPassword[sizeof(configNet.wifiPassword) - 1] = '\0'; // Guarantee a null terminator at the end + } + const char *wifiAddrKey = "ipAddress"; + if (serverWeb.hasArg(wifiAddrKey)) + { + configNet.wifiAddr.fromString(serverWeb.arg(wifiAddrKey)); + } + const char *wifiMaskKey = "ipMask"; + if (serverWeb.hasArg(wifiMaskKey)) + { + configNet.wifiMask.fromString(serverWeb.arg(wifiMaskKey)); + } + const char *wifiGateKey = "ipGW"; + if (serverWeb.hasArg(wifiGateKey)) + { + configNet.wifiGate.fromString(serverWeb.arg(wifiGateKey)); + } + const char *wifiDns1Key = "wifiDns1"; + if (serverWeb.hasArg(wifiDns1Key)) + { + configNet.wifiDns1.fromString(serverWeb.arg(wifiDns1Key)); + } + const char *wifiDns2Key = "wifiDns2"; + if (serverWeb.hasArg(wifiDns2Key)) + { + configNet.wifiDns2.fromString(serverWeb.arg(wifiDns2Key)); + } + + saveNetworkConfig(configNet); + + if (configNet.wifiEnable) + { + WiFi.persistent(false); + if (vars.apStarted) + { + WiFi.mode(WIFI_AP_STA); + } + else + { + WiFi.mode(WIFI_STA); + } + WiFi.begin(configNet.wifiSsid, configNet.wifiPassword); + } + } + break; + case API_PAGE_ZIGBEE: + { + const char *baud = "baud"; + if (serverWeb.hasArg(baud)) + { + configSys.serialSpeed = serverWeb.arg(baud).toInt(); + } + + if (serverWeb.hasArg(baud)) + { + configSys.socketPort = serverWeb.arg(portKey).toInt(); + } + + saveSystemConfig(configSys); + } + break; + case API_PAGE_SECURITY: + { + configSys.disableWeb = serverWeb.hasArg(disableWebKey) == true; + + configSys.webAuth = serverWeb.hasArg(webAuthKey) == true; + + if (serverWeb.hasArg(webUserKey)) + { + strncpy(configSys.webUser, serverWeb.arg(webUserKey).c_str(), sizeof(configSys.webUser) - 1); + configSys.webUser[sizeof(configSys.webUser) - 1] = '\0'; // Guarantee a null terminator at the end + } + + if (serverWeb.hasArg(webPassKey)) + { + strncpy(configSys.webPass, serverWeb.arg(webPassKey).c_str(), sizeof(configSys.webPass) - 1); + configSys.webPass[sizeof(configSys.webPass) - 1] = '\0'; // Guarantee a null terminator at the end + } + + configSys.fwEnabled = serverWeb.hasArg(fwEnabledKey) == true; + + if (serverWeb.hasArg(fwIpKey)) + { + configSys.fwIp.fromString(serverWeb.arg(fwIpKey)); + } + + saveSystemConfig(configSys); + } + break; + case API_PAGE_MQTT: + { + const char *MqttEnableKey = "MqttEnable"; + configMqtt.enable = serverWeb.hasArg(MqttEnableKey) == true; + + const char *MqttServerKey = "MqttServer"; + if (serverWeb.hasArg(MqttServerKey)) + { + strncpy(configMqtt.server, serverWeb.arg(MqttServerKey).c_str(), sizeof(configMqtt.server) - 1); + configMqtt.server[sizeof(configMqtt.server) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *MqttPortKey = "MqttPort"; + if (serverWeb.hasArg(MqttPortKey)) + { + configMqtt.port = serverWeb.arg(MqttPortKey).toInt(); + } + + const char *MqttUserKey = "MqttUser"; + if (serverWeb.hasArg(MqttUserKey)) + { + strncpy(configMqtt.user, serverWeb.arg(MqttUserKey).c_str(), sizeof(configMqtt.user) - 1); + configMqtt.user[sizeof(configMqtt.user) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *MqttPassKey = "MqttPass"; + if (serverWeb.hasArg(MqttPassKey)) + { + strncpy(configMqtt.pass, serverWeb.arg(MqttPassKey).c_str(), sizeof(configMqtt.pass) - 1); + configMqtt.pass[sizeof(configMqtt.pass) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *MqttTopicKey = "MqttTopic"; + if (serverWeb.hasArg(MqttTopicKey)) + { + strncpy(configMqtt.topic, serverWeb.arg(MqttTopicKey).c_str(), sizeof(configMqtt.topic) - 1); + configMqtt.topic[sizeof(configMqtt.topic) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *MqttIntervalKey = "MqttInterval"; + if (serverWeb.hasArg(MqttIntervalKey)) + { + configMqtt.updateInt = serverWeb.arg(MqttIntervalKey).toInt(); + } + + const char *MqttDiscoveryKey = "MqttDiscovery"; + configMqtt.discovery = serverWeb.hasArg(MqttDiscoveryKey) == true; + + saveMqttConfig(configMqtt); + } + break; + case API_PAGE_VPN: + { + const char *WgEnableKey = "WgEnable"; + configVpn.wgEnable = serverWeb.hasArg(WgEnableKey) == true; + + const char *WgLocalAddrKey = "WgLocalAddr"; + if (serverWeb.hasArg(WgLocalAddrKey)) + { + configVpn.wgLocalIP.fromString(serverWeb.arg(WgLocalAddrKey)); + } + + const char *WgLocalPrivKeyKey = "WgLocalPrivKey"; + if (serverWeb.hasArg(WgLocalPrivKeyKey)) + { + strncpy(configVpn.wgLocalPrivKey, serverWeb.arg(WgLocalPrivKeyKey).c_str(), sizeof(configVpn.wgLocalPrivKey) - 1); + configVpn.wgLocalPrivKey[sizeof(configVpn.wgLocalPrivKey) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *WgEndAddrKey = "WgEndAddr"; + if (serverWeb.hasArg(WgEndAddrKey)) + { + strncpy(configVpn.wgEndAddr, serverWeb.arg(WgEndAddrKey).c_str(), sizeof(configVpn.wgEndAddr) - 1); + configVpn.wgEndAddr[sizeof(configVpn.wgEndAddr) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *WgEndPubKeyKey = "WgEndPubKey"; + if (serverWeb.hasArg(WgEndPubKeyKey)) + { + strncpy(configVpn.wgEndPubKey, serverWeb.arg(WgEndPubKeyKey).c_str(), sizeof(configVpn.wgEndPubKey) - 1); + configVpn.wgEndPubKey[sizeof(configVpn.wgEndPubKey) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *WgEndPortKey = "WgEndPort"; + if (serverWeb.hasArg(WgEndPortKey)) + { + configVpn.wgEndPort = serverWeb.arg(WgEndPortKey).toInt(); + } + + const char *HnEnableKey = "HnEnable"; + configVpn.hnEnable = serverWeb.hasArg(HnEnableKey) == true; + + const char *HnJoinCodeKey = "HnJoinCode"; + if (serverWeb.hasArg(HnJoinCodeKey)) + { + strncpy(configVpn.hnJoinCode, serverWeb.arg(HnJoinCodeKey).c_str(), sizeof(configVpn.hnJoinCode) - 1); + configVpn.hnJoinCode[sizeof(configVpn.hnJoinCode) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *HnHostNameKey = "HnHostName"; + if (serverWeb.hasArg(HnHostNameKey)) + { + strncpy(configVpn.hnHostName, serverWeb.arg(HnHostNameKey).c_str(), sizeof(configVpn.hnHostName) - 1); + configVpn.hnHostName[sizeof(configVpn.hnHostName) - 1] = '\0'; // Guarantee a null terminator at the end + } + + const char *HnDashUrlKey = "HnDashUrl"; + if (serverWeb.hasArg(HnDashUrlKey)) + { + strncpy(configVpn.hnDashUrl, serverWeb.arg(HnDashUrlKey).c_str(), sizeof(configVpn.hnDashUrl) - 1); + configVpn.hnDashUrl[sizeof(configVpn.hnDashUrl) - 1] = '\0'; // Guarantee a null terminator at the end + } + + saveVpnConfig(configVpn); + } + break; + } + // String cfg = makeJsonConfig(&configNet, &configVpn, &configMqtt, &configSys); + // DEBUG_PRINTLN(cfg); + serverWeb.send(HTTP_CODE_OK, contTypeText, "ok"); + } + else + { + serverWeb.send(500, contTypeText, "bad args"); + } +} + +// Serialization NetworkConfigStruct into JSON +void serializeNetworkConfigToJson(const NetworkConfigStruct &config, JsonObject obj) +{ + obj[wifiEnableKey] = config.wifiEnable; + obj[wifiSsidKey] = config.wifiSsid; + obj[wifiPasswordKey] = config.wifiPassword; + obj[wifiDhcpKey] = config.wifiDhcp; + obj[wifiAddrKey] = config.wifiAddr.toString(); + obj[wifiMaskKey] = config.wifiMask.toString(); + obj[wifiGateKey] = config.wifiGate.toString(); + obj[wifiDns1Key] = config.wifiDns1.toString(); + obj[wifiDns2Key] = config.wifiDns2.toString(); + obj[ethEnableKey] = config.ethEnable; + obj[ethDhcpKey] = config.ethDhcp; + obj[ethAddrKey] = config.ethAddr.toString(); + obj[ethMaskKey] = config.ethMask.toString(); + obj[ethGateKey] = config.ethGate.toString(); + obj[ethDns1Key] = config.ethDns1.toString(); + obj[ethDns2Key] = config.ethDns2.toString(); +} + +// Serialization VpnConfigStruct into JSON +void serializeVpnConfigToJson(const VpnConfigStruct &config, JsonObject obj) +{ + obj[wgEnableKey] = config.wgEnable; + obj[wgLocalIPKey] = config.wgLocalIP.toString(); + obj[wgLocalPrivKeyKey] = config.wgLocalPrivKey; + obj[wgEndAddrKey] = config.wgEndAddr; + obj[wgEndPubKeyKey] = config.wgEndPubKey; + obj[wgEndPortKey] = config.wgEndPort; + obj[hnEnableKey] = config.hnEnable; + obj[hnJoinCodeKey] = config.hnJoinCode; + obj[hnHostNameKey] = config.hnHostName; + obj[hnDashUrlKey] = config.hnDashUrl; +} + +// Serialization MqttConfigStruct into JSON +void serializeMqttConfigToJson(const MqttConfigStruct &config, JsonObject obj) +{ + obj[enableKey] = config.enable; + obj[serverKey] = config.server; + //obj[serverIPKey] = config.serverIP.toString(); + obj[portKey] = config.port; + obj[userKey] = config.user; + obj[passKey] = config.pass; + obj[topicKey] = config.topic; + obj[updateIntKey] = config.updateInt; + obj[discoveryKey] = config.discovery; + obj[reconnectIntKey] = config.reconnectInt; + //obj[heartbeatTimeKey] = config.heartbeatTime; +} + +// Serialization SystemConfigStruct into JSON +void serializeSystemConfigToJson(const SystemConfigStruct &config, JsonObject obj) +{ + obj[keepWebKey] = config.keepWeb; + obj[disableWebKey] = config.disableWeb; + obj[webAuthKey] = config.webAuth; + obj[webUserKey] = config.webUser; + obj[webPassKey] = config.webPass; + obj[fwEnabledKey] = config.fwEnabled; + obj[fwIpKey] = config.fwIp.toString(); + obj[serialSpeedKey] = config.serialSpeed; + obj[socketPortKey] = config.socketPort; + obj[tempOffsetKey] = config.tempOffset; + obj[disableLedUSBKey] = config.disableLedUSB; + obj[disableLedPwrKey] = config.disableLedPwr; + obj[disableLedsKey] = config.disableLeds; + obj[refreshLogsKey] = config.refreshLogs; + obj[hostnameKey] = config.hostname; + obj[timeZoneKey] = config.timeZone; + obj[ntpServ1Key] = config.ntpServ1; + obj[ntpServ2Key] = config.ntpServ2; + // obj[prevWorkModeKey] = static_cast(config.prevWorkMode); + obj[workModeKey] = static_cast(config.workMode); +} + +void serializeSysVarsToJson(const SysVarsStruct &vars, JsonObject obj) +{ + // Serializing system variables to JSON + obj[hwBtnIsKey] = vars.hwBtnIs; + obj[hwLedUsbIsKey] = vars.hwLedUsbIs; + obj[hwLedPwrIsKey] = vars.hwLedPwrIs; + obj[hwUartSelIsKey] = vars.hwUartSelIs; + obj[hwZigbeeIsKey] = vars.hwZigbeeIs; + + // Assuming WORK_MODE_t can be directly cast to int for serialization + obj[workModeKey] = static_cast(vars.workMode); + + // Serializing an array of connectedSocket + /*JsonArray connectedSocketArray = obj.createNestedArray(connectedSocket); + for (bool socket : vars.connectedSocket) { + connectedSocketArray.add(socket); + }*/ + + obj[connectedClientsKey] = vars.connectedClients; + obj[socketTimeKey] = vars.socketTime; + obj[connectedEtherKey] = vars.connectedEther; + obj[apStartedKey] = vars.apStarted; + obj[wifiWebSetupInProgressKey] = vars.wifiWebSetupInProgress; + + obj[vpnWgInitKey] = vars.vpnWgInit; + obj[vpnWgConnectKey] = vars.vpnWgConnect; + obj[vpnWgPeerIpKey] = vars.vpnWgPeerIp.toString(); // Assuming IPAddress can be converted to string + obj[vpnWgCheckTimeKey] = vars.vpnWgCheckTime; + obj[vpnHnInitKey] = vars.vpnHnInit; + + obj[mqttConnKey] = vars.mqttConn; + obj[mqttReconnectTimeKey] = vars.mqttReconnectTime; + obj[mqttHeartbeatTimeKey] = vars.mqttHeartbeatTime; + + obj[zbLedStateKey] = vars.zbLedState; + obj[zbFlashingKey] = vars.zbFlashing; +} + +bool loadFileConfigHW() +{ + const char *board = "board"; + const char *addr = "addr"; + const char *pwrPin = "pwrPin"; + const char *mdcPin = "mdcPin"; + const char *mdiPin = "mdiPin"; + const char *phyType = "phyType"; + const char *clkMode = "clkMode"; + const char *pwrAltPin = "pwrAltPin"; + const char *btnPin = "btnPin"; + const char *uartChPin = "uartChPin"; + const char *ledUsbPin = "ledUsbPin"; + const char *ledPwrPin = "ledPwrPin"; + const char *zbTxPin = "zbTxPin"; + const char *zbRxPin = "zbRxPin"; + const char *zbRstPin = "zbRstPin"; + const char *zbBslPin = "zbBslPin"; + + File configFile = LittleFS.open(configFileHw, FILE_READ); + + if (!configFile) + { + DynamicJsonDocument config(300); + config[board] = ""; + /* + config[addr] = -1; + config[pwrPin] = -1; + config[mdcPin] = -1; + config[mdiPin] = -1; + config[phyType] = -1; + config[clkMode] = -1; + config[pwrAltPin] = -1; + config[btnPin] = -1; + config[uartChPin] = -1; + config[ledUsbPin] = -1; + config[ledPwrPin] = -1; + config[zbTxPin] = -1; + config[zbRxPin] = -1; + config[zbRstPin] = -1; + config[zbBslPin] = -1; + */ + writeDefaultConfig(configFileHw, config); + configFile = LittleFS.open(configFileHw, FILE_READ); + } + + DynamicJsonDocument config(1024); + deserializeJson(config, configFile); + + DEBUG_PRINTLN(configFile.readString()); + configFile.close(); + + strlcpy(hwConfig.board, config[board] | "", sizeof(hwConfig.board)); + hwConfig.eth.addr = config[addr]; + hwConfig.eth.pwrPin = config[pwrPin]; + hwConfig.eth.mdcPin = config[mdcPin]; + hwConfig.eth.mdiPin = config[mdiPin]; + hwConfig.eth.phyType = config[phyType]; + hwConfig.eth.clkMode = config[clkMode]; + hwConfig.eth.pwrAltPin = config[pwrAltPin]; + hwConfig.mist.btnPin = config[btnPin]; + hwConfig.mist.uartSelPin = config[uartChPin]; + hwConfig.mist.ledUsbPin = config[ledUsbPin]; + hwConfig.mist.ledPwrPin = config[ledPwrPin]; + hwConfig.zb.txPin = config[zbTxPin]; + hwConfig.zb.rxPin = config[zbRxPin]; + hwConfig.zb.rstPin = config[zbRstPin]; + hwConfig.zb.bslPin = config[zbBslPin]; + + if (hwConfig.board[0] != '\0' && strlen(hwConfig.board) > 0) + { + DEBUG_PRINTLN("hwConfig LOAD - OK"); + + delay(1000); + return true; + } + else + { + DEBUG_PRINTLN("hwConfig LOAD - ERROR"); + delay(1000); + int searchId = 0; + if (config["searchId"]) + { + searchId = config["searchId"]; + } + BrdConfigStruct *newConfig = findBrdConfig(searchId); + if (newConfig) + { + DEBUG_PRINTLN(F("Saving HW config")); + + DynamicJsonDocument config(512); + config[board] = newConfig->board; + config[addr] = newConfig->eth.addr; + config[pwrPin] = newConfig->eth.pwrPin; + config[mdcPin] = newConfig->eth.mdcPin; + config[mdiPin] = newConfig->eth.mdiPin; + config[phyType] = newConfig->eth.phyType; + config[clkMode] = newConfig->eth.clkMode; + config[pwrAltPin] = newConfig->eth.pwrAltPin; + config[btnPin] = newConfig->mist.btnPin; + config[uartChPin] = newConfig->mist.uartSelPin; + config[ledUsbPin] = newConfig->mist.ledUsbPin; + config[ledPwrPin] = newConfig->mist.ledPwrPin; + config[zbTxPin] = newConfig->zb.txPin; + config[zbRxPin] = newConfig->zb.rxPin; + config[zbRstPin] = newConfig->zb.rstPin; + config[zbBslPin] = newConfig->zb.bslPin; + writeDefaultConfig(configFileHw, config); + // configFile = LittleFS.open(configFileHw, FILE_WRITE); + // serializeJson(config, configFile); + + // serializeJson(config, Serial); + // configFile.close(); + + // delay(500); + DEBUG_PRINTLN(F("Restarting...")); + ESP.restart(); + } + } + return false; +} + +/* Previous firmware read config support. start */ + +const char *msg_file_rm = "OK. Remove old format file"; +const char *msg_open_f = "open failed"; + +bool loadFileSystemVar() +{ + DEBUG_PRINT(F(configFileSystem)); + + File configFile = LittleFS.open(configFileSystem, FILE_READ); + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(200); + DeserializationError error = deserializeJson(doc, configFile); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + return false; + } + + systemCfg.tempOffset = (int)doc[tempOffsetKey]; + + configFile.close(); + DEBUG_PRINTLN(F(msg_file_rm)); + saveSystemConfig(systemCfg); + LittleFS.remove(configFileSystem); + return true; +} + +bool loadFileConfigWifi() +{ + DEBUG_PRINT(F(configFileWifi)); + + const char *enableWiFi = "enableWiFi"; + const char *ssid = "ssid"; + const char *dhcpWiFi = "dhcpWiFi"; + const char *ip = "ip"; + const char *mask = "mask"; + const char *gw = "gw"; + + File configFile = LittleFS.open(configFileWifi, FILE_READ); + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + return false; + } + + networkCfg.wifiDhcp = (int)doc[dhcpWiFi]; + strlcpy(networkCfg.wifiSsid, doc[ssid] | "", sizeof(networkCfg.wifiSsid)); + strlcpy(networkCfg.wifiPassword, doc[passKey] | "", sizeof(networkCfg.wifiPassword)); + + networkCfg.wifiAddr.fromString(doc[ip] | ""); + networkCfg.wifiMask.fromString(doc[mask] | ""); + networkCfg.wifiGate.fromString(doc[gw] | ""); + + configFile.close(); + DEBUG_PRINTLN(F(msg_file_rm)); + saveNetworkConfig(networkCfg); + LittleFS.remove(configFileWifi); + return true; +} + +bool loadFileConfigEther() +{ + DEBUG_PRINT(F(configFileEther)); + + const char *dhcp = "dhcp"; + const char *ip = "ip"; + const char *mask = "mask"; + const char *gw = "gw"; + File configFile = LittleFS.open(configFileEther, FILE_READ); + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + return false; + } + + networkCfg.ethDhcp = (int)doc[dhcp]; + networkCfg.ethAddr.fromString(doc[ip] | ""); + networkCfg.ethMask.fromString(doc[mask] | ""); + networkCfg.ethGate.fromString(doc[gw] | ""); + + configFile.close(); + DEBUG_PRINTLN(F(msg_file_rm)); + saveNetworkConfig(networkCfg); + LittleFS.remove(configFileEther); + return true; +} + +bool loadFileConfigGeneral() +{ + DEBUG_PRINT(F(configFileGeneral)); + const char *hostname = "hostname"; + + + File configFile = LittleFS.open(configFileGeneral, FILE_READ); + + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + return false; + } + + if ((double)doc[refreshLogsKey] < 1000) + { + systemCfg.refreshLogs = 1000; + } + else + { + systemCfg.refreshLogs = (int)doc[refreshLogsKey]; + } + // DEBUG_PRINT(F("[loadFileConfigGeneral] 'doc[coordMode]' res is: ")); + // DEBUG_PRINTLN(String((uint8_t)doc[coordMode])); + + strlcpy(systemCfg.hostname, doc[hostname] | "", sizeof(systemCfg.hostname)); + + vars.workMode = static_cast((uint8_t)doc[coordMode]); + systemCfg.prevWorkMode = static_cast((uint8_t)doc[prevCoordMode]); + // DEBUG_PRINT(F("[loadFileConfigGeneral] 'vars.workMode' res is: ")); + // DEBUG_PRINTLN(String(vars.workMode)); + + systemCfg.disableLedPwr = (uint8_t)doc[disableLedPwrKey]; + // DEBUG_PRINTLN(F("[loadFileConfigGeneral] disableLedPwr")); + systemCfg.disableLedUSB = (uint8_t)doc[disableLedUSBKey]; + // DEBUG_PRINTLN(F("[loadFileConfigGeneral] disableLedUSB")); + systemCfg.disableLeds = (uint8_t)doc[disableLedsKey]; + // DEBUG_PRINTLN(F("[loadFileConfigGeneral] disableLeds")); + systemCfg.keepWeb = (uint8_t)doc[keepWebKey]; + // DEBUG_PRINTLN(F("[loadFileConfigGeneral] disableLeds")); + strlcpy(systemCfg.timeZone, doc[timeZoneKey] | "", sizeof(systemCfg.timeZone)); + + configFile.close(); + DEBUG_PRINTLN(F(msg_file_rm)); + saveSystemConfig(systemCfg); + LittleFS.remove(configFileGeneral); + return true; +} + +bool loadFileConfigSecurity() +{ + DEBUG_PRINT(F(configFileSecurity)); + File configFile = LittleFS.open(configFileSecurity, FILE_READ); + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + return false; + } + + systemCfg.disableWeb = (uint8_t)doc[disableWebKey]; + systemCfg.webAuth = (uint8_t)doc[webAuthKey]; + strlcpy(systemCfg.webUser, doc[webUserKey] | "", sizeof(systemCfg.webUser)); + strlcpy(systemCfg.webPass, doc[webPassKey] | "", sizeof(systemCfg.webPass)); + systemCfg.fwEnabled = (uint8_t)doc[fwEnabledKey]; + systemCfg.fwIp.fromString(doc[fwIpKey] | "0.0.0.0"); + + configFile.close(); + DEBUG_PRINTLN(F(msg_file_rm)); + saveSystemConfig(systemCfg); + LittleFS.remove(configFileSecurity); + return true; +} + +bool loadFileConfigSerial() +{ + DEBUG_PRINT(F(configFileSerial)); + const char *baud = "baud"; + File configFile = LittleFS.open(configFileSerial, FILE_READ); + + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + serializeJson(doc, Serial); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + return false; + } + + systemCfg.serialSpeed = (int)doc[baud]; + systemCfg.socketPort = (int)doc[portKey]; + + configFile.close(); + DEBUG_PRINTLN(F(msg_file_rm)); + saveSystemConfig(systemCfg); + LittleFS.remove(configFileSerial); + return true; +} + +bool loadFileConfigMqtt() +{ + DEBUG_PRINT(F(configFileMqtt)); + + + File configFile = LittleFS.open(configFileMqtt, FILE_READ); + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + serializeJson(doc, Serial); + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + if (error == DeserializationError::EmptyInput) + { + DEBUG_PRINTLN(F(msg_file_rm)); + LittleFS.remove(configFileMqtt); + } + return false; + } + + mqttCfg.enable = (int)doc[enableKey]; + strlcpy(mqttCfg.server, doc[serverKey] | "", sizeof(mqttCfg.server)); + //mqttCfg.serverIP.fromString(mqttCfg.server); // parse_ip_address(mqttCfg.server); + mqttCfg.port = (int)doc[portKey]; + strlcpy(mqttCfg.user, doc[userKey] | "", sizeof(mqttCfg.user)); + strlcpy(mqttCfg.pass, doc[passKey] | "", sizeof(mqttCfg.pass)); + strlcpy(mqttCfg.topic, doc[topicKey] | "", sizeof(mqttCfg.topic)); + mqttCfg.updateInt = (int)doc[intervalKey]; + mqttCfg.discovery = (int)doc[discoveryKey]; + + configFile.close(); + saveMqttConfig(mqttCfg); + DEBUG_PRINTLN(F("OK")); + return true; +} + +bool loadFileConfigWg() +{ + DEBUG_PRINT(F(configFileWg)); + const char *localAddr = "localAddr"; + const char *localPrivKey = "localIP"; + const char *endAddr = "endAddr"; + const char *endPubKey = "endPubKey"; + const char *endPort = "endPort"; + + File configFile = LittleFS.open(configFileWg, FILE_READ); + if (!configFile) + { + DEBUG_PRINTLN(F(msg_open_f)); + return false; + } + + DynamicJsonDocument doc(512); + DeserializationError error = deserializeJson(doc, configFile); + + if (error) + { + DEBUG_PRINTLN(error.f_str()); + configFile.close(); + if (error == DeserializationError::EmptyInput) + { + DEBUG_PRINTLN(F(msg_file_rm)); + LittleFS.remove(configFileWg); + } + return false; + } + + vpnCfg.wgEnable = (int)doc[enableKey]; + + // strlcpy(WgSettings.localAddr, doc[localAddr] | "", sizeof(WgSettings.localAddr)); + + vpnCfg.wgLocalIP.fromString(doc[localAddr] | ""); // parse_ip_address(doc[localAddr]); + + strlcpy(vpnCfg.wgLocalPrivKey, doc[localPrivKey] | "", sizeof(vpnCfg.wgLocalPrivKey)); + strlcpy(vpnCfg.wgEndAddr, doc[endAddr] | "", sizeof(vpnCfg.wgEndAddr)); + strlcpy(vpnCfg.wgEndPubKey, doc[endPubKey] | "", sizeof(vpnCfg.wgEndPubKey)); + vpnCfg.wgEndPort = (int)doc[endPort]; + + configFile.close(); + saveVpnConfig(vpnCfg); + DEBUG_PRINTLN(F("OK")); + return true; +} + +/* Previous firmware read config support. end */ \ No newline at end of file diff --git a/src/config.h b/src/config.h index f4e4732..fdb87cc 100644 --- a/src/config.h +++ b/src/config.h @@ -2,31 +2,24 @@ #define CONFIG_H_ #include -#include +#include +#include #include "version.h" - -// #define DEBUG -// ESP32 PINS TO CONTROL LAN8720 -/* -#define ETH_CLK_MODE_1 ETH_CLOCK_GPIO17_OUT -#define ETH_POWER_PIN_ALTERNATIVE_1 5 -#define ETH_POWER_PIN_1 -1 -#define ETH_TYPE_1 ETH_PHY_LAN8720 -#define ETH_ADDR_1 0 -#define ETH_MDC_PIN_1 23 -#define ETH_MDIO_PIN_1 18 -*/ -// ESP32 PINS TO CONTROL CC2652P -// #define CC2652P_RST 16 -// #define CC2652P_FLASH 32 -// #define CC2652P_RXD 36 -// #define CC2652P_TXD 4 -// #define BTN 35 -// #define MODE_SWITCH 33 +#include +#include +#include #define DEBOUNCE_TIME 70 -#define TCP_LISTEN_PORT 9999 // any port ever. later setup from config file +#define ZB_TCP_PORT 9999 // any port ever. later setup from config file +#define ZB_SERIAL_SPEED 115200 +#define NTP_TIME_ZONE "Europe/Kiev" +#define NTP_SERV_1 "pool.ntp.org" +#define NTP_SERV_2 "time.google.com" +#define DNS_SERV_1 "1.1.1.1" +#define DNS_SERV_2 "8.8.8.8" +#define NETWORK_MASK "255.255.255.0" + #define MAX_SOCKET_CLIENTS 5 #define FORMAT_LITTLEFS_IF_FAILED true @@ -37,14 +30,12 @@ const int16_t overseerInterval = 5 * 1000; // check lan or wifi connection every 5sec const uint8_t overseerMaxRetry = 3; // 5x12 = 60sec delay for AP start -// const uint8_t LED_USB = 12; // RED -// const uint8_t LED_PWR = 14; // BLUE -enum COORDINATOR_MODE_t : uint8_t +enum WORK_MODE_t : uint8_t { - COORDINATOR_MODE_LAN, - COORDINATOR_MODE_WIFI, - COORDINATOR_MODE_USB + WORK_MODE_NETWORK, + // COORDINATOR_MODE_WIFI, + WORK_MODE_USB }; extern const char *coordMode; // coordMode node name @@ -60,48 +51,198 @@ extern const char *configFileWg; extern const char *configFileHw; // extern const char *deviceModel; -struct ConfigSettingsStruct + +struct SysVarsStruct { - char ssid[50]; - char password[50]; - char ipAddressWiFi[18]; - char ipMaskWiFi[16]; - char ipGWWiFi[18]; - bool dhcpWiFi; - bool dhcp; - bool connectedEther; - char ipAddress[18]; - char ipMask[16]; - char ipGW[18]; - int serialSpeed; - int socketPort; - bool disableWeb; - int refreshLogs; - char hostname[50]; - bool connectedSocket[10]; - int connectedClients; - unsigned long socketTime; - int tempOffset; + bool hwBtnIs = false; + bool hwLedUsbIs = false; + bool hwLedPwrIs = false; + bool hwUartSelIs = false; + bool hwZigbeeIs = false; + + WORK_MODE_t workMode; // for button // WORK_MODE_t + + bool connectedSocket[MAX_SOCKET_CLIENTS]; //[10] + int connectedClients; + unsigned long socketTime; + + bool connectedEther = false; + + bool apStarted = false; + bool wifiWebSetupInProgress = false; + + bool vpnWgInit = false; + bool vpnWgConnect = false; + IPAddress vpnWgPeerIp; + unsigned long vpnWgCheckTime; + + bool vpnHnInit = false; + bool mqttConn = true; + unsigned long mqttReconnectTime; + unsigned long mqttHeartbeatTime; + + bool zbLedState; + bool zbFlashing; +}; + +// Network configuration structure +struct NetworkConfigStruct +{ + // Wi-Fi + bool wifiEnable; + char wifiSsid[50]; + char wifiPassword[50]; + bool wifiDhcp; + IPAddress wifiAddr; + IPAddress wifiMask; + IPAddress wifiGate; + IPAddress wifiDns1; + IPAddress wifiDns2; + // LAN + bool ethEnable; + bool ethDhcp; + IPAddress ethAddr; + IPAddress ethMask; + IPAddress ethGate; + IPAddress ethDns1; + IPAddress ethDns2; +}; + +// Function prototypes for NetworkConfigStruct +void saveNetworkConfig(const NetworkConfigStruct &config); +void loadNetworkConfig(NetworkConfigStruct &config); + +// VPN configuration structure +struct VpnConfigStruct +{ + // Wireguard + bool wgEnable; + IPAddress wgLocalIP; + char wgLocalPrivKey[50]; + char wgEndAddr[50]; + char wgEndPubKey[50]; + int wgEndPort; + // Husarnet + bool hnEnable; + char hnJoinCode[80]; + char hnHostName[30]; + char hnDashUrl[30]; +}; + +// Function prototypes for VpnConfigStruct +void saveVpnConfig(const VpnConfigStruct &config); +void loadVpnConfig(VpnConfigStruct &config); + +// MQTT configuration structure +struct MqttConfigStruct +{ + bool enable; + // bool connect; + char server[50]; + //IPAddress serverIP; + int port; + char user[50]; + char pass[50]; + char topic[50]; + // bool retain; // commented as per the structure definition + int updateInt; + bool discovery; + int reconnectInt; + //unsigned long heartbeatTime; +}; + +// Function prototypes for MqttConfigStruct +void saveMqttConfig(const MqttConfigStruct &config); +void loadMqttConfig(MqttConfigStruct &config); + +struct SystemConfigStruct +{ + bool keepWeb; // when usb mode active + + bool disableWeb; // when socket connected bool webAuth; char webUser[50]; char webPass[50]; + + bool fwEnabled; // firewall for socket connection + IPAddress fwIp; // allowed IP + + int serialSpeed; + int socketPort; + + int tempOffset; + bool disableLedUSB; bool disableLedPwr; - // bool disablePingCtrl; bool disableLeds; - COORDINATOR_MODE_t coordinator_mode; - COORDINATOR_MODE_t prevCoordinator_mode; // for button - bool keepWeb; - bool apStarted; - bool wifiWebSetupInProgress; - bool fwEnabled; - IPAddress fwIp; - bool zbLedState; - bool zbFlashing; + int refreshLogs; + char hostname[50]; + char timeZone[50]; + char ntpServ1[50]; + char ntpServ2[50]; + + WORK_MODE_t prevWorkMode; // for button // WORK_MODE_t + WORK_MODE_t workMode; // for button // WORK_MODE_t }; +// Function prototypes for SystemConfigStruct +void saveSystemConfig(const SystemConfigStruct &config); +void loadSystemConfig(SystemConfigStruct &config); + +// Serialization function declarations +void serializeNetworkConfigToJson(const NetworkConfigStruct &config, JsonObject obj); +void serializeVpnConfigToJson(const VpnConfigStruct &config, JsonObject obj); +void serializeMqttConfigToJson(const MqttConfigStruct &config, JsonObject obj); +void serializeSystemConfigToJson(const SystemConfigStruct &config, JsonObject obj); +void serializeSysVarsToJson(const SysVarsStruct &vars, JsonObject obj); + +void updateConfiguration(WebServer &server, SystemConfigStruct &configSys, NetworkConfigStruct &configNet, VpnConfigStruct &configVpn, MqttConfigStruct &configMqtt); + +/* +struct ConfigSettingsStruct +{ + char ssid[50]; //+ + char password[50]; //+ + char ipAddressWiFi[18]; //+ + char ipMaskWiFi[16]; //+ + char ipGWWiFi[18]; //+ + bool dhcpWiFi; //+ + bool dhcp; //+ + *bool connectedEther; //+ + char ipAddress[18]; //+ + char ipMask[16]; //+ + char ipGW[18]; //+ + int serialSpeed; //+ + int socketPort; //+ + bool disableWeb; //+ + int refreshLogs; //+ + char hostname[50]; //+ + bool connectedSocket[10]; //+ + int connectedClients; //+ + unsigned long socketTime; //+ + int tempOffset; //+ + bool webAuth; //+ + char webUser[50]; //+ + char webPass[50]; //+ + bool disableLedUSB; //+ + bool disableLedPwr; //+ + // bool disablePingCtrl; + bool disableLeds; //+ + WORK_MODE_t coordinator_mode; //+ + WORK_MODE_t prevCoordinator_mode; // for button //+ + bool keepWeb; //+ + bool apStarted; //+ + bool wifiWebSetupInProgress; + bool fwEnabled; //+ + IPAddress fwIp; //+ + + bool zbLedState; //+ + bool zbFlashing; //+ + char timeZone[50]; //+ +};*/ +/* struct MqttSettingsStruct { bool enable; @@ -117,28 +258,19 @@ struct MqttSettingsStruct bool discovery; unsigned long reconnectTime; unsigned long heartbeatTime; -}; - +};*/ +/* struct WgSettingsStruct { bool enable; bool init = 0; - char localAddr[20]; + char localAddr[16]; IPAddress localIP; char localPrivKey[45]; char endAddr[45]; char endPubKey[45]; int endPort; -}; - -/* -struct InfosStruct -{ - char device[8]; - char mac[8]; - char flash[8]; -}; -*/ +};*/ struct zbVerStruct { @@ -155,11 +287,33 @@ typedef CircularBuffer LogConsoleType; // #define WL_MAC_ADDR_LENGTH 6 +void initNVS(); +void printNVSFreeSpace(); +void eraseNVS(); +String makeJsonConfig(const NetworkConfigStruct *networkCfg = nullptr, + const VpnConfigStruct *vpnCfg = nullptr, + const MqttConfigStruct *mqttCfg = nullptr, + const SystemConfigStruct *systemCfg = nullptr, + const SysVarsStruct *systemVars = nullptr); + +bool loadFileConfigHW(); + +/* Previous firmware read config support. start */ +bool loadFileSystemVar(); +bool loadFileConfigWifi(); +bool loadFileConfigEther(); +bool loadFileConfigGeneral(); +bool loadFileConfigSecurity(); +bool loadFileConfigSerial(); +bool loadFileConfigMqtt(); +bool loadFileConfigWg(); +// IPAddress parse_ip_address(const char *str); +/* Previous firmware read config support. end */ + #ifdef DEBUG #define DEBUG_PRINT(x) Serial.print(String(x)) #define DEBUG_PRINTLN(x) Serial.println(String(x)) - #define LOGE(tag, format, ...) Serial.printf("[%s] " format " (%s:%d)\n", tag, ##__VA_ARGS__, __FILE__, __LINE__) #define LOGI(tag, format, ...) Serial.printf("[%s] " format "\n", tag, ##__VA_ARGS__) @@ -179,7 +333,3 @@ typedef CircularBuffer LogConsoleType; #define LOGI(f_, ...) #endif #endif - - - - diff --git a/src/etc.cpp b/src/etc.cpp index 64826f7..c7cc1ef 100644 --- a/src/etc.cpp +++ b/src/etc.cpp @@ -12,18 +12,30 @@ #include "log.h" #include "etc.h" #include "zones.h" -#include "hw.h" +// #include "hw.h" #include "zb.h" -extern struct ConfigSettingsStruct ConfigSettings; +#include +static WireGuard wg; + +// extern struct ConfigSettingsStruct ConfigSettings; +extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT]; extern struct BrdConfigStruct hwConfig; -extern struct CurrentModesStruct modes; +// extern struct CurrentModesStruct modes; + +extern struct SystemConfigStruct systemCfg; +extern struct NetworkConfigStruct networkCfg; +extern struct VpnConfigStruct vpnCfg; +extern struct MqttConfigStruct mqttCfg; + +extern struct SysVarsStruct vars; extern CCTools CCTool; -const char *coordMode = "coordMode"; // coordMode node name -const char *prevCoordMode = "prevCoordMode"; // prevCoordMode node name +const char *coordMode = "coordMode"; // coordMode node name ?? not name but text field with mode +const char *prevCoordMode = "prevCoordMode"; // prevCoordMode node name ?? not name but text field with mode + const char *configFileSystem = "/config/system.json"; const char *configFileWifi = "/config/configWifi.json"; const char *configFileEther = "/config/configEther.json"; @@ -33,7 +45,18 @@ const char *configFileSerial = "/config/configSerial.json"; const char *configFileMqtt = "/config/configMqtt.json"; const char *configFileWg = "/config/configWg.json"; const char *configFileHw = "/config/configHw.json"; -// const char *deviceModel = "UZG-01"; + +/* +const char *cfgFileHw = "/cfg/hardware.json"; +const char *cfgFileGen = "/cfg/general.json"; +const char *cfgFileNet = "/cfg/network.json"; +const char *cfgFileSec = "/cfg/security.json"; +const char *cfgFileSer = "/cfg/serial.json"; +const char *cfgFileVpn = "/cfg/vpn.json"; +const char *cfgFileMqtt = "/cfg/mqtt.json"; +*/ + +// const char *deviceModel = "XZG"; void getReadableTime(String &readableTime, unsigned long beginTime) { @@ -81,17 +104,17 @@ float readTemperature(bool clear) } else { - return (temprature_sens_read() - 32) / 1.8 - ConfigSettings.tempOffset; + return (temprature_sens_read() - 32) / 1.8 - systemCfg.tempOffset; } } float getCPUtemp(bool clear) { - DEBUG_PRINTLN(F("getCPUtemp")); + //DEBUG_PRINTLN(F("getCPUtemp")); float CPUtemp = 0.0; if (WiFi.getMode() == WIFI_MODE_NULL || WiFi.getMode() == WIFI_OFF) { - DEBUG_PRINTLN(F("enable wifi to enable temp sensor")); + //DEBUG_PRINTLN(F("enable wifi to enable temp sensor")); WiFi.mode(WIFI_STA); // enable wifi to enable temp sensor CPUtemp = readTemperature(clear); WiFi.disconnect(); @@ -133,71 +156,71 @@ void zigbeeRestart() void adapterModeUSB() { - if (modes.uartChIs) + if (vars.hwUartSelIs) { - printLogMsg("Switched UZG-01 to USB mode"); - DEBUG_PRINTLN(F("Switched UZG-01 to USB mode")); - if (modes.uartChIs) + printLogMsg("Switched XZG to USB mode"); + DEBUG_PRINTLN(F("Switched XZG to USB mode")); + if (vars.hwUartSelIs) { - digitalWrite(hwConfig.uartChPin, 1); - DEBUG_PRINTLN(F("digitalWrite(hwConfig.uartChPin, 1) - HIGH")); + digitalWrite(hwConfig.mist.uartSelPin, 1); + DEBUG_PRINTLN(F("digitalWrite(hwConfig.mist.uartSelPin, 1) - HIGH")); } - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { - digitalWrite(hwConfig.ledUsbPin, 1); + digitalWrite(hwConfig.mist.ledUsbPin, 1); } } else { - DEBUG_PRINTLN(F("NO modes.uartChIs. NO mode USB")); + DEBUG_PRINTLN(F("NO vars.hwUartSelIs. NO mode USB")); } } void adapterModeLAN() { - if (modes.uartChIs) + if (vars.hwUartSelIs) { - printLogMsg("Switched UZG-01 to LAN mode"); - DEBUG_PRINTLN(F("Switched UZG-01 to LAN mode")); - digitalWrite(hwConfig.uartChPin, 0); - DEBUG_PRINTLN(F("digitalWrite(hwConfig.uartChPin, 0) - LOW")); + printLogMsg("Switched XZG to LAN mode"); + DEBUG_PRINTLN(F("Switched XZG to LAN mode")); + digitalWrite(hwConfig.mist.uartSelPin, 0); + DEBUG_PRINTLN(F("digitalWrite(hwConfig.mist.uartSelPin, 0) - LOW")); - if (modes.ledUsbIs) - digitalWrite(hwConfig.ledUsbPin, 0); + if (vars.hwLedUsbIs) + digitalWrite(hwConfig.mist.ledUsbPin, 0); } else { - DEBUG_PRINTLN(F("NO modes.uartChIs. NO mode LAN")); + DEBUG_PRINTLN(F("NO vars.hwUartSelIs. NO mode LAN")); } } void ledPwrToggle() { - if (modes.ledPwrIs) + if (vars.hwLedPwrIs) { printLogMsg("BLUE LED has been toggled"); DEBUG_PRINTLN(F("BLUE LED has been toggled")); DEBUG_PRINT(F("pin - ")); - DEBUG_PRINTLN(hwConfig.ledPwrPin); - digitalWrite(hwConfig.ledPwrPin, !digitalRead(hwConfig.ledPwrPin)); + DEBUG_PRINTLN(hwConfig.mist.ledPwrPin); + digitalWrite(hwConfig.mist.ledPwrPin, !digitalRead(hwConfig.mist.ledPwrPin)); } else { - DEBUG_PRINTLN(F("NO modes.ledPwrIs. NO BLUE LED")); + DEBUG_PRINTLN(F("NO vars.hwLedPwrIs. NO BLUE LED")); } } void ledUsbToggle() { - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { printLogMsg("RED LED has been toggled"); DEBUG_PRINTLN(F("RED LED has been toggled")); - digitalWrite(hwConfig.ledUsbPin, !digitalRead(hwConfig.ledUsbPin)); + digitalWrite(hwConfig.mist.ledUsbPin, !digitalRead(hwConfig.mist.ledUsbPin)); } else { - DEBUG_PRINTLN(F("NO modes.ledUsbIs. NO RED LED")); + DEBUG_PRINTLN(F("NO vars.hwLedUsbIs. NO RED LED")); } } @@ -227,7 +250,9 @@ void getDeviceID(char *arr) } // Form the final string including the board name and the processed MAC address - sprintf(arr, "%s-%s", hwConfig.board, buf); + + //sprintf(arr, "%s-%s", hwConfig.board, buf); + snprintf(arr, MAX_DEV_ID_LONG, "%s-%s", hwConfig.board, buf); } /* @@ -301,7 +326,7 @@ void writeDefaultConfig(const char *path, DynamicJsonDocument &doc) { DEBUG_PRINT(F("Write defaults to ")); DEBUG_PRINTLN(path); - serializeJson(doc, Serial); + serializeJsonPretty(doc, Serial); File configFile = LittleFS.open(path, FILE_WRITE); if (!configFile) { @@ -310,12 +335,12 @@ void writeDefaultConfig(const char *path, DynamicJsonDocument &doc) } else { - serializeJson(doc, configFile); + serializeJsonPretty(doc, configFile); } configFile.close(); } -String hexToDec(String hexString) +/*String hexToDec(String hexString) { unsigned int decValue = 0; @@ -337,29 +362,29 @@ String hexToDec(String hexString) } return String(decValue); -} +}*/ -void resetSettings() +void resetSettings() // to do adapt to Preferences { DEBUG_PRINTLN(F("[resetSettings] Start")); - if (modes.ledPwrIs) + if (vars.hwLedPwrIs) { - digitalWrite(hwConfig.ledPwrPin, 1); + digitalWrite(hwConfig.mist.ledPwrPin, 1); } - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { - digitalWrite(hwConfig.ledUsbPin, 0); + digitalWrite(hwConfig.mist.ledUsbPin, 0); } for (uint8_t i = 0; i < 15; i++) { delay(200); - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { - digitalWrite(hwConfig.ledUsbPin, !digitalRead(hwConfig.ledUsbPin)); + digitalWrite(hwConfig.mist.ledUsbPin, !digitalRead(hwConfig.mist.ledUsbPin)); } - if (modes.ledPwrIs) + if (vars.hwLedPwrIs) { - digitalWrite(hwConfig.ledPwrPin, !digitalRead(hwConfig.ledPwrPin)); + digitalWrite(hwConfig.mist.ledPwrPin, !digitalRead(hwConfig.mist.ledPwrPin)); } } DEBUG_PRINTLN(F("[resetSettings] Led blinking done")); @@ -381,7 +406,7 @@ void resetSettings() void setClock() { - configTime(0, 0, "pool.ntp.org", "time.google.com"); + configTime(0, 0, systemCfg.ntpServ1, systemCfg.ntpServ2); DEBUG_PRINT(F("Waiting for NTP time sync: ")); int startTryingTime = millis(); @@ -404,9 +429,9 @@ void setClock() DEBUG_PRINT(asctime(&timeinfo)); char *zoneToFind = const_cast("Europe/Kiev"); - if (ConfigSettings.timeZone) + if (systemCfg.timeZone) { - zoneToFind = ConfigSettings.timeZone; + zoneToFind = systemCfg.timeZone; } const char *gmtOffset = getGmtOffsetForZone(zoneToFind); @@ -482,27 +507,27 @@ BrdConfigStruct *findBrdConfig(int searchId = 0) int i = searchId; - if (ETH.begin(brdConfigs[i].addr, brdConfigs[i].pwrPin, brdConfigs[i].mdcPin, brdConfigs[i].mdiPin, brdConfigs[i].phyType, brdConfigs[i].clkMode, brdConfigs[i].pwrAltPin)) + if (ETH.begin(brdConfigs[i].eth.addr, brdConfigs[i].eth.pwrPin, brdConfigs[i].eth.mdcPin, brdConfigs[i].eth.mdiPin, brdConfigs[i].eth.phyType, brdConfigs[i].eth.clkMode, brdConfigs[i].eth.pwrAltPin)) { Serial.print("BrdConfig found: "); Serial.println(brdConfigs[i].board); brdOk = true; // zigbee check - if (brdConfigs[i].zbRxPin > 0 && brdConfigs[i].zbTxPin > 0 && brdConfigs[i].zbRstPin > 0 && brdConfigs[i].zbBslPin > 0) + if (brdConfigs[i].zb.rxPin > 0 && brdConfigs[i].zb.txPin > 0 && brdConfigs[i].zb.rstPin > 0 && brdConfigs[i].zb.bslPin > 0) { DEBUG_PRINTLN(F("Zigbee pins OK. Try to connect...")); esp_task_wdt_reset(); - Serial2.begin(ConfigSettings.serialSpeed, SERIAL_8N1, brdConfigs[i].zbRxPin, brdConfigs[i].zbTxPin); // start zigbee serial + Serial2.begin(systemCfg.serialSpeed, SERIAL_8N1, brdConfigs[i].zb.rxPin, brdConfigs[i].zb.txPin); // start zigbee serial // CCTool.switchStream(Serial2); int BSL_MODE = 0; // delay(500); - - if (zbInit(brdConfigs[i].zbRstPin, brdConfigs[i].zbBslPin, BSL_MODE)) + + if (zbInit(brdConfigs[i].zb.rstPin, brdConfigs[i].zb.bslPin, BSL_MODE)) { DEBUG_PRINTLN(F("Zigbee find - OK")); brdOk = true; @@ -512,7 +537,6 @@ BrdConfigStruct *findBrdConfig(int searchId = 0) DEBUG_PRINTLN(F("Zigbee find - ERROR")); brdOk = false; } - } } if (brdOk == true) @@ -523,7 +547,7 @@ BrdConfigStruct *findBrdConfig(int searchId = 0) { Serial.print("BrdConfig error with: "); Serial.println(brdConfigs[i].board); - //delay(500); + // delay(500); DynamicJsonDocument config(300); config["searchId"] = i + 1; @@ -566,7 +590,7 @@ ZbConfig *findZbConfig(int ethPwrPin, int ethMdcPin, int ethMdiPin, int ethClkPi //Serial2.end(); //DEBUG_PRINTLN(F("Serial2.end")); - Serial2.begin(ConfigSettings.serialSpeed, SERIAL_8N1, zbConfigs[i].rxPin, zbConfigs[i].txPin); // start zigbee serial + Serial2.begin(systemCfg.serialSpeed, SERIAL_8N1, zbConfigs[i].rxPin, zbConfigs[i].txPin); // start zigbee serial DEBUG_PRINTLN(F("Serial2.begin")); CCTool.switchStream(Serial2); @@ -586,4 +610,83 @@ ZbConfig *findZbConfig(int ethPwrPin, int ethMdcPin, int ethMdiPin, int ethClkPi return nullptr; } -*/ \ No newline at end of file +*/ + +void wgBegin() +{ + if (!wg.is_initialized()) + { + // printLogMsg(String("Initializing WireGuard interface...")); + auto subnet = IPAddress(255, 255, 255, 255); + auto gateway = IPAddress(0, 0, 0, 0); + auto localport = 50000; + if (!wg.begin( + vpnCfg.wgLocalIP, + subnet, + localport, + gateway, + vpnCfg.wgLocalPrivKey, + vpnCfg.wgEndAddr, + vpnCfg.wgEndPubKey, + vpnCfg.wgEndPort)) + { + printLogMsg(String("Failed to initialize WG")); + vars.vpnWgInit = false; + } + else + { + printLogMsg(String("WG was initialized")); + vars.vpnWgInit = true; + } + } +} + +void wgLoop() +{ + String tag = "WG"; + uint16_t localport = 50000; + //IPAddress ip = ; + + int checkPeriod = 5; // to do vpnCfg.checkTime; + ip_addr_t lwip_ip; + + lwip_ip.u_addr.ip4.addr = static_cast(vpnCfg.wgLocalIP); + + if (wg.is_initialized()) + { + if (vars.vpnWgCheckTime == 0) + { + vars.vpnWgCheckTime = millis() + 1000 * checkPeriod; + } + else + { + if (vars.vpnWgCheckTime <= millis()) + { + //LOGI(tag, "check"); + vars.vpnWgCheckTime = millis() + 1000 * checkPeriod; + if (wg.is_peer_up(&lwip_ip, &localport)) + { + vars.vpnWgPeerIp = (lwip_ip.u_addr.ip4.addr); + if (!vars.vpnWgConnect) + { + LOGI(tag, "Peer with IP %s connect", vars.vpnWgPeerIp.toString().c_str()); + } + vars.vpnWgConnect = true; + } + else + { + if (vars.vpnWgConnect) + { + LOGI(tag, "Peer disconnect"); + } + vars.vpnWgPeerIp.clear(); + vars.vpnWgConnect = false; + } + } + } + } + else + { + vars.vpnWgInit = false; + } +} \ No newline at end of file diff --git a/src/etc.h b/src/etc.h index 0199fc8..08d7c64 100644 --- a/src/etc.h +++ b/src/etc.h @@ -1,4 +1,5 @@ #include +#include "hw.h" void getReadableTime(String &readableTime, unsigned long beginTime); @@ -15,6 +16,8 @@ uint8_t temprature_sens_read(); #define STRINGIFY(s) STRINGIFY1(s) // Don’t ask why. It has to do with the inner workings of the preprocessor. #define STRINGIFY1(s) #s // https://community.platformio.org/t/how-to-put-a-string-in-a-define-in-build-flag-into-a-libary-json-file/13480/6 +#define MAX_DEV_ID_LONG 50 +/* struct CurrentModesStruct { bool btnIs = false; @@ -22,8 +25,9 @@ struct CurrentModesStruct bool ledPwrIs = false; bool uartChIs = false; bool zigbeeIs = false; -}; +};*/ +/* struct BrdConfigStruct { char board[50]; @@ -42,9 +46,11 @@ struct BrdConfigStruct int zbRxPin; int zbRstPin; int zbBslPin; -}; +};*/ -BrdConfigStruct*findBrdConfig(int searchId); +extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT]; + +BrdConfigStruct *findBrdConfig(int searchId); float getCPUtemp(bool clear = false); @@ -63,11 +69,14 @@ void writeDefaultConfig(const char *path, DynamicJsonDocument &doc); void resetSettings(); -String hexToDec(String hexString); +//String hexToDec(String hexString); void setClock(); void setTimezone(String timezone); const char *getGmtOffsetForZone(const char *zone); void ledsScheduler(); +void wgBegin(); +void wgLoop(); + // #define min(a, b) ((a) < (b) ? (a) : (b)) \ No newline at end of file diff --git a/src/hw.cpp b/src/hw.cpp new file mode 100644 index 0000000..7f2136e --- /dev/null +++ b/src/hw.cpp @@ -0,0 +1,29 @@ +#include "hw.h" + + +BrdConfigStruct brdConfigs[BOARD_CFG_CNT] = { + {"UZG-01", + {.addr = 0, .pwrPin = -1, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = 5}, + {.btnPin = 35, .btnPlr = 1, .uartSelPin = 33, .uartSelPlr = 1, .ledUsbPin = 12, .ledUsbPlr = 1, .ledPwrPin = 14, .ledPwrPlr = 1}, + {.txPin = 4, .rxPin = 36, .rstPin = 16, .bslPin = 32}}, + {"SLZB-06", + {.addr = 1, .pwrPin = 16, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO0_IN, .pwrAltPin = -1}, + {.btnPin = 35, .btnPlr = 1, .uartSelPin = 4, .uartSelPlr = 1, .ledUsbPin = 12, .ledUsbPlr = 1, .ledPwrPin = 14, .ledPwrPlr = 1}, + {.txPin = 17, .rxPin = 5, .rstPin = 33, .bslPin = 32}}, + {"Omilex-ESP32-POE", + {.addr = 0, .pwrPin = 12, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = -1}, + {.btnPin = -1, .btnPlr = 0, .uartSelPin = -1, .uartSelPlr = 0, .ledUsbPin = -1, .ledUsbPlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, + {.txPin = 4, .rxPin = 36, .rstPin = 16, .bslPin = 32}}, + {"WT32-ETH01", + {.addr = 1, .pwrPin = 16, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO0_IN, .pwrAltPin = -1}, + {.btnPin = -1, .btnPlr = 0, .uartSelPin = -1, .uartSelPlr = 0, .ledUsbPin = -1, .ledUsbPlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, + {.txPin = 17, .rxPin = 5, .rstPin = 33, .bslPin = 32}}, + {"T-Internet-POE", + {.addr = 0, .pwrPin = -1, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = -1}, + {.btnPin = -1, .btnPlr = 0, .uartSelPin = -1, .uartSelPlr = 0, .ledUsbPin = -1, .ledUsbPlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, + {.txPin = 4, .rxPin = 36, .rstPin = 16, .bslPin = 32}}, + {"China-GW", + {.addr = 0, .pwrPin = 12, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = -1}, + {.btnPin = -1, .btnPlr = 0, .uartSelPin = -1, .uartSelPlr = 0, .ledUsbPin = -1, .ledUsbPlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, + {.txPin = 33, .rxPin = 32, .rstPin = 12, .bslPin = 14}}, +}; \ No newline at end of file diff --git a/src/hw.h b/src/hw.h index ad967a6..491d601 100644 --- a/src/hw.h +++ b/src/hw.h @@ -1,5 +1,6 @@ #include +/* BrdConfigStruct brdConfigs[] = { //{"BRD_NAME", addr, pwrPin, mdcPin, mdiPin, eth_phy_type, eth_clock_mode, pwrAltPin, btnPin, uartChPin, ledUsbPin, ledPwrPin, zbTxPin, zbRxPin, zbRstPin, zbBslPin}, {"UZG-01", 0, -1, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO17_OUT, 5, 35, 33, 12, 14, 4, 36, 16, 32}, @@ -8,4 +9,49 @@ BrdConfigStruct brdConfigs[] = { {"WT32-ETH01", 1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN, -1, -1, -1, -1, -1, 17, 5, 33, 32}, {"T-Internet-POE", 0, -1, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO17_OUT, -1, -1, -1, -1, -1, 4, 36, 16, 32}, {"China-GW", 0, 12, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO17_OUT, -1, -1, -1, -1, -1, 33, 32, 12, 14}, -}; \ No newline at end of file +};*/ + + +// Ethernet settings structure +struct EthConfig +{ + int addr; + int pwrPin; + int mdcPin; + int mdiPin; + eth_phy_type_t phyType; + eth_clock_mode_t clkMode; + int pwrAltPin; +}; + +// Miscellaneous settings structure +struct MistConfig { + int btnPin; + int btnPlr; + int uartSelPin; + int uartSelPlr; + int ledUsbPin; + int ledUsbPlr; + int ledPwrPin; + int ledPwrPlr; +}; + +// ZigBee settings structure +struct ZbConfig +{ + int txPin; + int rxPin; + int rstPin; + int bslPin; +}; + +// Root configuration structure that includes all substructures +struct BrdConfigStruct +{ + char board[50]; + EthConfig eth; + MistConfig mist; + ZbConfig zb; +}; + +#define BOARD_CFG_CNT 6 \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e0f8429..cf6a49a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,10 @@ #include "mqtt.h" #include "zb.h" #include "version.h" +// #include "hw.h" + +#include "esp_system.h" +#include "esp_task_wdt.h" /* #ifdef ETH_CLK_MODE @@ -31,13 +35,23 @@ #define BUFFER_SIZE 256 -ConfigSettingsStruct ConfigSettings; -zbVerStruct zbVer; -// InfosStruct Infos; -MqttSettingsStruct MqttSettings; -WgSettingsStruct WgSettings; +// ConfigSettingsStruct ConfigSettings; +// MqttSettingsStruct MqttSettings; +// WgSettingsStruct WgSettings; +// CurrentModesStruct modes; + +extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT]; + BrdConfigStruct hwConfig; -CurrentModesStruct modes; + +SystemConfigStruct systemCfg; +NetworkConfigStruct networkCfg; +VpnConfigStruct vpnCfg; +MqttConfigStruct mqttCfg; + +SysVarsStruct vars; + +zbVerStruct zbVer; // volatile bool btnFlag = false; int btnFlag = false; @@ -49,16 +63,15 @@ void handleLongBtn(); void handleTmrNetworkOverseer(); void setupCoordinatorMode(); void startAP(const bool start); -IPAddress parse_ip_address(const char *str); Ticker tmrBtnLongPress(handleLongBtn, 1000, 0, MILLIS); Ticker tmrNetworkOverseer(handleTmrNetworkOverseer, overseerInterval, 0, MILLIS); IPAddress apIP(192, 168, 1, 1); DNSServer dnsServer; -WiFiServer server(TCP_LISTEN_PORT, MAX_SOCKET_CLIENTS); +WiFiServer server(ZB_TCP_PORT, MAX_SOCKET_CLIENTS); + -static WireGuard wg; CCTools CCTool(Serial2); @@ -69,13 +82,13 @@ void initLan() DEBUG_PRINT(F("Some ETH config found. Try to use ")); DEBUG_PRINTLN(hwConfig.board); - if (ETH.begin(hwConfig.addr, hwConfig.pwrPin, hwConfig.mdcPin, hwConfig.mdiPin, hwConfig.phyType, hwConfig.clkMode, hwConfig.pwrAltPin)) + if (ETH.begin(hwConfig.eth.addr, hwConfig.eth.pwrPin, hwConfig.eth.mdcPin, hwConfig.eth.mdiPin, hwConfig.eth.phyType, hwConfig.eth.clkMode, hwConfig.eth.pwrAltPin)) { DEBUG_PRINTLN(F("LAN start ok")); - if (!ConfigSettings.dhcp) + if (!networkCfg.ethDhcp) { DEBUG_PRINTLN(F("ETH STATIC")); - ETH.config(parse_ip_address(ConfigSettings.ipAddress), parse_ip_address(ConfigSettings.ipGW), parse_ip_address(ConfigSettings.ipMask)); + ETH.config(networkCfg.ethAddr, networkCfg.ethGate, networkCfg.ethMask, networkCfg.ethDns1, networkCfg.ethDns2); // ConfigSettings.disconnectEthTime = millis(); } else @@ -115,7 +128,7 @@ void initZb() { DEBUG_PRINTLN(F("Some ZB config found. Try to use")); - Serial2.begin(ConfigSettings.serialSpeed, SERIAL_8N1, hwConfig.rxPin, hwConfig.txPin); // start zigbee serial + Serial2.begin(systemCfg.serialSpeed, SERIAL_8N1, hwConfig.rxPin, hwConfig.txPin); // start zigbee serial int BSL_MODE = 0; @@ -186,87 +199,89 @@ void initZb() void startSocketServer() { - server.begin(ConfigSettings.socketPort); + server.begin(systemCfg.socketPort); server.setNoDelay(true); } -void wgBegin() -{ - if (!wg.is_initialized()) - { - // printLogMsg(String("Initializing WireGuard interface...")); - if (!wg.begin( - WgSettings.localIP, - WgSettings.localPrivKey, - WgSettings.endAddr, - WgSettings.endPubKey, - WgSettings.endPort)) - { - printLogMsg(String("Failed to initialize WG")); - WgSettings.init = false; - } - else - { - printLogMsg(String("WG was initialized")); - WgSettings.init = true; - } - } -} void startServers(bool usb = false) { initWebServer(); + // DEBUG_PRINTLN("6"); if (!usb) + { startSocketServer(); + } + // DEBUG_PRINTLN("7"); startAP(false); + // DEBUG_PRINTLN("8"); mDNS_start(); + // DEBUG_PRINTLN("9"); getZbVer(); - if (WgSettings.enable) + // DEBUG_PRINTLN("10"); + if (vpnCfg.wgEnable) { wgBegin(); } + if (mqttCfg.enable) + { + mqttConnectSetup(); + } + // DEBUG_PRINTLN("11"); } void handleTmrNetworkOverseer() { - switch (ConfigSettings.coordinator_mode) + switch (vars.workMode) { - case COORDINATOR_MODE_WIFI: - DEBUG_PRINT(F("WiFi.status = ")); - DEBUG_PRINTLN(WiFi.status()); - if (WiFi.isConnected()) + case WORK_MODE_NETWORK: + if (!networkCfg.wifiEnable && !networkCfg.ethEnable) { - DEBUG_PRINTLN(F("WIFI CONNECTED")); - startServers(); - tmrNetworkOverseer.stop(); + DEBUG_PRINTLN(F("Both interfaces disabled. Start AP")); + startAP(true); + connectWifi(); } - else + if (networkCfg.wifiEnable) { - if (tmrNetworkOverseer.counter() > overseerMaxRetry) + DEBUG_PRINT(F("WiFi.status = ")); + DEBUG_PRINTLN(WiFi.status()); + if (WiFi.isConnected()) { - DEBUG_PRINTLN(F("WIFI counter overflow")); - startAP(true); - connectWifi(); + DEBUG_PRINTLN(F("WIFI CONNECTED")); + startServers(); + tmrNetworkOverseer.stop(); + } + else + { + if (tmrNetworkOverseer.counter() > overseerMaxRetry) + { + DEBUG_PRINTLN(F("WIFI counter overflow")); + startAP(true); + connectWifi(); + } } } - break; - case COORDINATOR_MODE_LAN: - if (ConfigSettings.connectedEther) - { - DEBUG_PRINTLN(F("LAN CONNECTED")); - startServers(); - tmrNetworkOverseer.stop(); - } - else + // break; + // case WORK_MODE_NETWORK: + if (networkCfg.ethEnable) { - if (tmrNetworkOverseer.counter() > overseerMaxRetry) + if (vars.connectedEther) { - DEBUG_PRINTLN(F("LAN counter overflow")); - startAP(true); + DEBUG_PRINTLN(F("LAN CONNECTED")); + startServers(); + tmrNetworkOverseer.stop(); + } + else + { + if (tmrNetworkOverseer.counter() > overseerMaxRetry) + { + DEBUG_PRINTLN(F("LAN counter overflow")); + startAP(true); + } } } break; - case COORDINATOR_MODE_USB: + case WORK_MODE_USB: if (tmrNetworkOverseer.counter() > 3) { // 10 seconds for wifi connect if (WiFi.isConnected()) @@ -279,7 +294,7 @@ void handleTmrNetworkOverseer() initLan(); if (tmrNetworkOverseer.counter() > 6) { // 3sec for lan - if (ConfigSettings.connectedEther) + if (vars.connectedEther) { tmrNetworkOverseer.stop(); startServers(true); @@ -294,21 +309,21 @@ void handleTmrNetworkOverseer() } break; - default: - break; + // default: + // break; } } void NetworkEvent(WiFiEvent_t event) { - DEBUG_PRINT(F("NetworkEvent ")); - DEBUG_PRINTLN(event); + // DEBUG_PRINT(F("NetworkEvent ")); + // DEBUG_PRINTLN(event); switch (event) { case ARDUINO_EVENT_ETH_START: // 18: // SYSTEM_EVENT_ETH_START: DEBUG_PRINTLN(F("ETH Started")); // ConfigSettings.disconnectEthTime = millis(); - ETH.setHostname(ConfigSettings.hostname); + ETH.setHostname(systemCfg.hostname); break; case ARDUINO_EVENT_ETH_CONNECTED: // 20: // SYSTEM_EVENT_ETH_CONNECTED: DEBUG_PRINTLN(F("ETH Connected")); @@ -329,16 +344,16 @@ void NetworkEvent(WiFiEvent_t event) DEBUG_PRINT(F(", ")); DEBUG_PRINT(ETH.linkSpeed()); DEBUG_PRINTLN(F("Mbps")); - ConfigSettings.connectedEther = true; + vars.connectedEther = true; // ConfigSettings.disconnectEthTime = 0; // mDNS_start(); - setClock(); + // setClock(); break; case ARDUINO_EVENT_ETH_DISCONNECTED: // 21: //SYSTEM_EVENT_ETH_DISCONNECTED: DEBUG_PRINTLN(F("ETH Disconnected")); - ConfigSettings.connectedEther = false; + vars.connectedEther = false; // ConfigSettings.disconnectEthTime = millis(); - if (tmrNetworkOverseer.state() == STOPPED && ConfigSettings.coordinator_mode == COORDINATOR_MODE_LAN) + if (tmrNetworkOverseer.state() == STOPPED && vars.workMode == WORK_MODE_NETWORK) { tmrNetworkOverseer.start(); } @@ -346,7 +361,7 @@ void NetworkEvent(WiFiEvent_t event) case SYSTEM_EVENT_ETH_STOP: // 27: case ARDUINO_EVENT_ETH_STOP: DEBUG_PRINTLN(F("ETH Stopped")); - ConfigSettings.connectedEther = false; + vars.connectedEther = false; // ConfigSettings.disconnectEthTime = millis(); if (tmrNetworkOverseer.state() == STOPPED) { @@ -362,7 +377,7 @@ void NetworkEvent(WiFiEvent_t event) DEBUG_PRINT(WiFi.subnetMask().toString()); DEBUG_PRINT(F(", ")); DEBUG_PRINTLN(WiFi.gatewayIP().toString()); - setClock(); + // setClock(); break; case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: // SYSTEM_EVENT_STA_DISCONNECTED: DEBUG_PRINTLN(F("WIFI STA DISCONNECTED")); @@ -376,585 +391,25 @@ void NetworkEvent(WiFiEvent_t event) } } -IPAddress parse_ip_address(const char *str) -{ - IPAddress result; - int index = 0; - - result[0] = 0; - while (*str) - { - if (isdigit((unsigned char)*str)) - { - result[index] *= 10; - result[index] += *str - '0'; - } - else - { - index++; - if (index < 4) - { - result[index] = 0; - } - } - str++; - } - - return result; -} - -bool loadSystemVar() -{ // todo remove - File configFile = LittleFS.open(configFileSystem, FILE_READ); - if (!configFile) - { - DEBUG_PRINTLN(F("failed open. try to write defaults")); - - float CPUtemp = getCPUtemp(true); - int correct = CPUtemp - 30; - String tempOffset = String(correct); - - String StringConfig = "{\"emergencyWifi\":0,\"tempOffset\":" + tempOffset + "}"; - DEBUG_PRINTLN(StringConfig); - DynamicJsonDocument doc(1024); - deserializeJson(doc, StringConfig); - - File configFile = LittleFS.open(configFileSystem, FILE_WRITE); - if (!configFile) - { - DEBUG_PRINTLN(F("failed write")); - return false; - } - else - { - serializeJson(doc, configFile); - } - return false; - } - - DynamicJsonDocument doc(1024); - deserializeJson(doc, configFile); - - ConfigSettings.tempOffset = (int)doc["tempOffset"]; - if (!ConfigSettings.tempOffset) - { - DEBUG_PRINTLN(F("no tempOffset in system.json")); - configFile.close(); - - float CPUtemp = getCPUtemp(true); - int correct = CPUtemp - 30; - String tempOffset = String(correct); - doc["tempOffset"] = int(tempOffset.toInt()); - - configFile = LittleFS.open(configFileSystem, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); - DEBUG_PRINTLN(F("saved tempOffset in system.json")); - ConfigSettings.tempOffset = int(tempOffset.toInt()); - } - configFile.close(); - return true; -} - -bool loadConfigWifi() -{ - File configFile = LittleFS.open(configFileWifi, FILE_READ); - const char *enableWiFi = "enableWiFi"; - const char *ssid = "ssid"; - const char *pass = "pass"; - const char *dhcpWiFi = "dhcpWiFi"; - const char *ip = "ip"; - const char *mask = "mask"; - const char *gw = "gw"; - if (!configFile) - { - // String StringConfig = "{\"enableWiFi\":0,\"ssid\":\"\",\"pass\":\"\",\"dhcpWiFi\":1,\"ip\":\"\",\"mask\":\"\",\"gw\":\"\",\"disableEmerg\":1}"; - DynamicJsonDocument doc(1024); - doc[enableWiFi] = 0; - doc[ssid] = ""; - doc[pass] = ""; - doc[dhcpWiFi] = 1; - doc[ip] = ""; - doc[mask] = ""; - doc[gw] = ""; - writeDefaultConfig(configFileWifi, doc); - } - - configFile = LittleFS.open(configFileWifi, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - - configFile.close(); - LittleFS.remove(configFileWifi); - return false; - } - - ConfigSettings.dhcpWiFi = (int)doc[dhcpWiFi]; - strlcpy(ConfigSettings.ssid, doc[ssid] | "", sizeof(ConfigSettings.ssid)); - strlcpy(ConfigSettings.password, doc[pass] | "", sizeof(ConfigSettings.password)); - strlcpy(ConfigSettings.ipAddressWiFi, doc[ip] | "", sizeof(ConfigSettings.ipAddressWiFi)); - strlcpy(ConfigSettings.ipMaskWiFi, doc[mask] | "", sizeof(ConfigSettings.ipMaskWiFi)); - strlcpy(ConfigSettings.ipGWWiFi, doc[gw] | "", sizeof(ConfigSettings.ipGWWiFi)); - // ConfigSettings.enableWiFi = (int)doc["enableWiFi"]; - // ConfigSettings.disableEmerg = (int)doc["disableEmerg"]; - - configFile.close(); - return true; -} - -bool loadConfigEther() -{ - const char *dhcp = "dhcp"; - const char *ip = "ip"; - const char *mask = "mask"; - const char *gw = "gw"; - File configFile = LittleFS.open(configFileEther, FILE_READ); - if (!configFile) - { - DynamicJsonDocument doc(1024); - doc[dhcp] = 1; - doc[ip] = ""; - doc[mask] = ""; - doc[gw] = ""; - // doc["disablePingCtrl"] = 0; - // String StringConfig = "{\"dhcp\":1,\"ip\":\"\",\"mask\":\"\",\"gw\":\"\",\"disablePingCtrl\":0}"; - writeDefaultConfig(configFileEther, doc); - } - - configFile = LittleFS.open(configFileEther, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - - configFile.close(); - LittleFS.remove(configFileEther); - return false; - } - - ConfigSettings.dhcp = (int)doc[dhcp]; - strlcpy(ConfigSettings.ipAddress, doc[ip] | "", sizeof(ConfigSettings.ipAddress)); - strlcpy(ConfigSettings.ipMask, doc[mask] | "", sizeof(ConfigSettings.ipMask)); - strlcpy(ConfigSettings.ipGW, doc[gw] | "", sizeof(ConfigSettings.ipGW)); - // ConfigSettings.disablePingCtrl = (int)doc["disablePingCtrl"]; - - configFile.close(); - return true; -} - -bool loadConfigHW() -{ - const char *board = "board"; - const char *addr = "addr"; - const char *pwrPin = "pwrPin"; - const char *mdcPin = "mdcPin"; - const char *mdiPin = "mdiPin"; - const char *phyType = "phyType"; - const char *clkMode = "clkMode"; - const char *pwrAltPin = "pwrAltPin"; - const char *btnPin = "btnPin"; - const char *uartChPin = "uartChPin"; - const char *ledUsbPin = "ledUsbPin"; - const char *ledPwrPin = "ledPwrPin"; - const char *zbTxPin = "zbTxPin"; - const char *zbRxPin = "zbRxPin"; - const char *zbRstPin = "zbRstPin"; - const char *zbBslPin = "zbBslPin"; - - File configFile = LittleFS.open(configFileHw, FILE_READ); - - if (!configFile) - { - DynamicJsonDocument config(300); - config[board] = ""; - /* - config[addr] = -1; - config[pwrPin] = -1; - config[mdcPin] = -1; - config[mdiPin] = -1; - config[phyType] = -1; - config[clkMode] = -1; - config[pwrAltPin] = -1; - config[btnPin] = -1; - config[uartChPin] = -1; - config[ledUsbPin] = -1; - config[ledPwrPin] = -1; - config[zbTxPin] = -1; - config[zbRxPin] = -1; - config[zbRstPin] = -1; - config[zbBslPin] = -1; - */ - writeDefaultConfig(configFileHw, config); - configFile = LittleFS.open(configFileHw, FILE_READ); - } - - DynamicJsonDocument config(1024); - deserializeJson(config, configFile); - - DEBUG_PRINTLN(configFile.readString()); - configFile.close(); - - strlcpy(hwConfig.board, config[board] | "", sizeof(hwConfig.board)); - hwConfig.addr = config[addr]; - hwConfig.pwrPin = config[pwrPin]; - hwConfig.mdcPin = config[mdcPin]; - hwConfig.mdiPin = config[mdiPin]; - hwConfig.phyType = config[phyType]; - hwConfig.clkMode = config[clkMode]; - hwConfig.pwrAltPin = config[pwrAltPin]; - hwConfig.btnPin = config[btnPin]; - hwConfig.uartChPin = config[uartChPin]; - hwConfig.ledUsbPin = config[ledUsbPin]; - hwConfig.ledPwrPin = config[ledPwrPin]; - hwConfig.zbTxPin = config[zbTxPin]; - hwConfig.zbRxPin = config[zbRxPin]; - hwConfig.zbRstPin = config[zbRstPin]; - hwConfig.zbBslPin = config[zbBslPin]; - - if (hwConfig.board[0] != '\0' && strlen(hwConfig.board) > 0) - { - DEBUG_PRINTLN("hwConfig LOAD - OK"); - - delay(1000); - return true; - } - else - { - DEBUG_PRINTLN("hwConfig LOAD - ERROR"); - delay(1000); - int searchId = 0; - if (config["searchId"]) - { - searchId = config["searchId"]; - } - BrdConfigStruct *newConfig = findBrdConfig(searchId); - if (newConfig) - { - DEBUG_PRINTLN(F("Saving HW config")); - - DynamicJsonDocument config(512); - config[board] = newConfig->board; - config[addr] = newConfig->addr; - config[pwrPin] = newConfig->pwrPin; - config[mdcPin] = newConfig->mdcPin; - config[mdiPin] = newConfig->mdiPin; - config[phyType] = newConfig->phyType; - config[clkMode] = newConfig->clkMode; - config[pwrAltPin] = newConfig->pwrAltPin; - config[btnPin] = newConfig->btnPin; - config[uartChPin] = newConfig->uartChPin; - config[ledUsbPin] = newConfig->ledUsbPin; - config[ledPwrPin] = newConfig->ledPwrPin; - config[zbTxPin] = newConfig->zbTxPin; - config[zbRxPin] = newConfig->zbRxPin; - config[zbRstPin] = newConfig->zbRstPin; - config[zbBslPin] = newConfig->zbBslPin; - writeDefaultConfig(configFileHw, config); - // configFile = LittleFS.open(configFileHw, FILE_WRITE); - // serializeJson(config, configFile); - - // serializeJson(config, Serial); - // configFile.close(); - - // delay(500); - DEBUG_PRINTLN(F("Restarting...")); - ESP.restart(); - } - } - return false; -} - -bool loadConfigGeneral() -{ - const char *hostname = "hostname"; - const char *disableLeds = "disableLeds"; - const char *refreshLogs = "refreshLogs"; - const char *disableLedPwr = "disableLedPwr"; - const char *disableLedUSB = "disableLedUSB"; - const char *prevCoordMode = "prevCoordMode"; - const char *keepWeb = "keepWeb"; - const char *timeZoneName = "timeZoneName"; - File configFile = LittleFS.open(configFileGeneral, FILE_READ); - DEBUG_PRINTLN(configFile.readString()); - if (!configFile) - { - // String deviceID = deviceModel; - // getDeviceID(deviceID); - // DEBUG_PRINTLN("RESET ConfigGeneral"); - // String StringConfig = "{\"hostname\":\"" + deviceID + "\",\"disableLeds\": false,\"refreshLogs\":1000,\"usbMode\":0,\"disableLedPwr\":0,\"disableLedUSB\":0,\""+ coordMode +"\":0}\""+ prevCoordMode +"\":0, \"keepWeb\": 0}"; - DynamicJsonDocument doc(1024); - doc[hostname] = hwConfig.board; - doc[disableLeds] = 0; - doc[refreshLogs] = 1000; - doc[disableLedPwr] = 0; - doc[disableLedUSB] = 0; - doc[coordMode] = 0; - doc[prevCoordMode] = 0; - doc[keepWeb] = 0; - doc[timeZoneName] = "Europe/Kiev"; - writeDefaultConfig(configFileGeneral, doc); - } - - configFile = LittleFS.open(configFileGeneral, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - - configFile.close(); - LittleFS.remove(configFileGeneral); - return false; - } - - if ((double)doc[refreshLogs] < 1000) - { - ConfigSettings.refreshLogs = 1000; - } - else - { - ConfigSettings.refreshLogs = (int)doc[refreshLogs]; - } - DEBUG_PRINT(F("[loadConfigGeneral] 'doc[coordMode]' res is: ")); - DEBUG_PRINTLN(String((uint8_t)doc[coordMode])); - - strlcpy(ConfigSettings.hostname, doc[hostname] | "", sizeof(ConfigSettings.hostname)); - - ConfigSettings.coordinator_mode = static_cast((uint8_t)doc[coordMode]); - ConfigSettings.prevCoordinator_mode = static_cast((uint8_t)doc[prevCoordMode]); - DEBUG_PRINT(F("[loadConfigGeneral] 'ConfigSettings.coordinator_mode' res is: ")); - DEBUG_PRINTLN(String(ConfigSettings.coordinator_mode)); - - ConfigSettings.disableLedPwr = (uint8_t)doc[disableLedPwr]; - // DEBUG_PRINTLN(F("[loadConfigGeneral] disableLedPwr")); - ConfigSettings.disableLedUSB = (uint8_t)doc[disableLedUSB]; - // DEBUG_PRINTLN(F("[loadConfigGeneral] disableLedUSB")); - ConfigSettings.disableLeds = (uint8_t)doc[disableLeds]; - // DEBUG_PRINTLN(F("[loadConfigGeneral] disableLeds")); - ConfigSettings.keepWeb = (uint8_t)doc[keepWeb]; - // DEBUG_PRINTLN(F("[loadConfigGeneral] disableLeds")); - strlcpy(ConfigSettings.timeZone, doc[timeZoneName] | "", sizeof(ConfigSettings.timeZone)); - configFile.close(); - DEBUG_PRINTLN(F("[loadConfigGeneral] config load done")); - return true; -} - -bool loadConfigSecurity() -{ - const char *disableWeb = "disableWeb"; - const char *webAuth = "webAuth"; - const char *webUser = "webUser"; - const char *webPass = "webPass"; - const char *fwEnabled = "fwEnabled"; - const char *fwIp = "fwIp"; - File configFile = LittleFS.open(configFileSecurity, FILE_READ); - if (!configFile) - { - // String StringConfig = "{\"disableWeb\":0,\"webAuth\":0,\"webUser\":"",\"webPass\":""}"; - DynamicJsonDocument doc(1024); - doc[disableWeb] = 0; - doc[webAuth] = 0; - doc[webUser] = "admin"; - doc[webPass] = ""; - doc[fwEnabled] = 0; - doc[fwIp] = ""; - writeDefaultConfig(configFileSecurity, doc); - } - - configFile = LittleFS.open(configFileSecurity, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - - configFile.close(); - LittleFS.remove(configFileSecurity); - return false; - } - - ConfigSettings.disableWeb = (uint8_t)doc[disableWeb]; - ConfigSettings.webAuth = (uint8_t)doc[webAuth]; - strlcpy(ConfigSettings.webUser, doc[webUser] | "", sizeof(ConfigSettings.webUser)); - strlcpy(ConfigSettings.webPass, doc[webPass] | "", sizeof(ConfigSettings.webPass)); - ConfigSettings.fwEnabled = (uint8_t)doc[fwEnabled]; - ConfigSettings.fwIp = parse_ip_address(doc[fwIp] | "0.0.0.0"); - - configFile.close(); - return true; -} - -bool loadConfigSerial() -{ - const char *baud = "baud"; - const char *port = "port"; - File configFile = LittleFS.open(configFileSerial, FILE_READ); - if (!configFile) - { - // String StringConfig = "{\"baud\":115200,\"port\":6638}"; - DynamicJsonDocument doc(1024); - doc[baud] = 115200; - doc[port] = 6638; - writeDefaultConfig(configFileSerial, doc); - } - - configFile = LittleFS.open(configFileSerial, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - - configFile.close(); - LittleFS.remove(configFileSerial); - return false; - } - - ConfigSettings.serialSpeed = (int)doc[baud]; - ConfigSettings.socketPort = (int)doc[port]; - if (ConfigSettings.socketPort == 0) - { - ConfigSettings.socketPort = TCP_LISTEN_PORT; - } - configFile.close(); - return true; -} - -bool loadConfigMqtt() -{ - const char *enable = "enable"; - const char *server = "server"; - const char *port = "port"; - const char *user = "user"; - const char *pass = "pass"; - const char *topic = "topic"; - const char *interval = "interval"; - const char *discovery = "discovery"; - - File configFile = LittleFS.open(configFileMqtt, FILE_READ); - if (!configFile) - { - char deviceIdArr[20]; - getDeviceID(deviceIdArr); - - DynamicJsonDocument doc(1024); - doc[enable] = 0; - doc[server] = ""; - doc[port] = 1883; - doc[user] = "mqttuser"; - doc[pass] = ""; - doc[topic] = String(deviceIdArr); - doc[interval] = 60; - doc[discovery] = 0; - writeDefaultConfig(configFileMqtt, doc); - } - - configFile = LittleFS.open(configFileMqtt, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - configFile.close(); - LittleFS.remove(configFileMqtt); - return false; - } - - MqttSettings.enable = (int)doc[enable]; - strlcpy(MqttSettings.server, doc[server] | "", sizeof(MqttSettings.server)); - MqttSettings.serverIP = parse_ip_address(MqttSettings.server); - MqttSettings.port = (int)doc[port]; - strlcpy(MqttSettings.user, doc[user] | "", sizeof(MqttSettings.user)); - strlcpy(MqttSettings.pass, doc[pass] | "", sizeof(MqttSettings.pass)); - strlcpy(MqttSettings.topic, doc[topic] | "", sizeof(MqttSettings.topic)); - MqttSettings.interval = (int)doc[interval]; - MqttSettings.discovery = (int)doc[discovery]; - - configFile.close(); - return true; -} - -bool loadConfigWg() -{ - const char *enable = "enable"; - const char *localAddr = "localAddr"; - const char *localIP = "localIP"; - const char *endAddr = "endAddr"; - const char *endPubKey = "endPubKey"; - const char *endPort = "endPort"; - - File configFile = LittleFS.open(configFileWg, FILE_READ); - if (!configFile) - { - DynamicJsonDocument doc(1024); - doc[enable] = 0; - doc[localAddr] = ""; - doc[localIP] = ""; - doc[endAddr] = ""; - doc[endPubKey] = ""; - doc[endPort] = ""; - writeDefaultConfig(configFileWg, doc); - } - - configFile = LittleFS.open(configFileWg, FILE_READ); - DynamicJsonDocument doc(1024); - DeserializationError error = deserializeJson(doc, configFile); - - if (error) - { - DEBUG_PRINTLN(F("deserializeJson() failed: ")); - DEBUG_PRINTLN(error.f_str()); - configFile.close(); - LittleFS.remove(configFileWg); - return false; - } - - WgSettings.enable = (int)doc[enable]; - - strlcpy(WgSettings.localAddr, doc[localAddr] | "", sizeof(WgSettings.localAddr)); - WgSettings.localIP = parse_ip_address(WgSettings.localAddr); - - strlcpy(WgSettings.localPrivKey, doc[localIP] | "", sizeof(WgSettings.localPrivKey)); - strlcpy(WgSettings.endAddr, doc[endAddr] | "", sizeof(WgSettings.endAddr)); - strlcpy(WgSettings.endPubKey, doc[endPubKey] | "", sizeof(WgSettings.endPubKey)); - WgSettings.endPort = (int)doc[endPort]; - - configFile.close(); - return true; -} - void startAP(const bool start) { - if (ConfigSettings.apStarted) + if (vars.apStarted) { if (!start) { - if (ConfigSettings.coordinator_mode != COORDINATOR_MODE_WIFI) + if (!networkCfg.wifiEnable) // vars.workMode != COORDINATOR_MODE_WIFI) { + // DEBUG_PRINTLN("1"); WiFi.softAPdisconnect(true); // off wifi } else { + // DEBUG_PRINTLN("2"); WiFi.mode(WIFI_STA); } + // DEBUG_PRINTLN("3"); dnsServer.stop(); - ConfigSettings.apStarted = false; + vars.apStarted = false; } } else @@ -974,7 +429,7 @@ void startAP(const bool start) // } WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); - char apSsid[18]; + char apSsid[MAX_DEV_ID_LONG]; getDeviceID(apSsid); WiFi.softAP(apSsid); //, WIFIPASS); // if DNSServer is started with "*" for domain name, it will reply with @@ -983,8 +438,10 @@ void startAP(const bool start) dnsServer.start(53, "*", apIP); WiFi.setSleep(false); // ConfigSettings.wifiAPenblTime = millis(); + DEBUG_PRINTLN("4"); startServers(); - ConfigSettings.apStarted = true; + vars.apStarted = true; + DEBUG_PRINTLN("5"); } } @@ -1004,10 +461,10 @@ void connectWifi() } WiFi.persistent(false); esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B); - if ((strlen(ConfigSettings.ssid) >= 2) && (strlen(ConfigSettings.password) >= 8)) + if ((strlen(networkCfg.wifiSsid) >= 2) && (strlen(networkCfg.wifiPassword) >= 8)) { DEBUG_PRINTLN(F("[connectWifi] Ok SSID & PASS")); - if (ConfigSettings.apStarted) + if (vars.apStarted) { // DEBUG_PRINTLN(F("[connectWifi] WiFi.mode(WIFI_AP_STA)")); // WiFi.mode(WIFI_AP_STA); @@ -1019,16 +476,13 @@ void connectWifi() } delay(100); - WiFi.begin(ConfigSettings.ssid, ConfigSettings.password); + WiFi.begin(networkCfg.wifiSsid, networkCfg.wifiPassword); WiFi.setSleep(false); DEBUG_PRINTLN(F("[connectWifi] WiFi.begin")); - if (!ConfigSettings.dhcpWiFi) + if (!networkCfg.wifiDhcp) { - IPAddress ip_address = parse_ip_address(ConfigSettings.ipAddressWiFi); - IPAddress gateway_address = parse_ip_address(ConfigSettings.ipGWWiFi); - IPAddress netmask = parse_ip_address(ConfigSettings.ipMaskWiFi); - WiFi.config(ip_address, gateway_address, netmask); + WiFi.config(networkCfg.wifiAddr, networkCfg.wifiGate, networkCfg.wifiMask, networkCfg.wifiDns1, networkCfg.wifiDns2); DEBUG_PRINTLN(F("[connectWifi] WiFi.config")); } else @@ -1038,21 +492,29 @@ void connectWifi() } else { - if (!(ConfigSettings.coordinator_mode == COORDINATOR_MODE_USB && ConfigSettings.keepWeb)) + if (!(vars.workMode == WORK_MODE_USB && systemCfg.keepWeb)) { // dont start ap in keepWeb - DEBUG_PRINTLN(F("[connectWifi] NO SSID & PASS")); - startAP(true); - DEBUG_PRINTLN(F("[connectWifi] setupWifiAP")); + DEBUG_PRINT(F("[connectWifi] NO SSID & PASS ")); + if (!vars.connectedEther) + { + DEBUG_PRINTLN(F("and problem with LAN")); + startAP(true); + DEBUG_PRINTLN(F("So [connectWifi] setupWifiAP")); + } + else + { + DEBUG_PRINTLN(F("but LAN is OK")); + } } } } void mDNS_start() { - const char *host = "_uzg-01"; + const char *host = "_xzg"; const char *http = "_http"; const char *tcp = "_tcp"; - if (!MDNS.begin(ConfigSettings.hostname)) + if (!MDNS.begin(systemCfg.hostname)) { printLogMsg("Error setting up MDNS responder!"); } @@ -1061,11 +523,12 @@ void mDNS_start() printLogMsg("mDNS responder started"); MDNS.addService(http, tcp, 80); // web //--zeroconf zha-- - MDNS.addService(host, tcp, ConfigSettings.socketPort); + MDNS.addService(host, tcp, systemCfg.socketPort); MDNS.addServiceTxt(host, tcp, "version", "1.0"); MDNS.addServiceTxt(host, tcp, "radio_type", "znp"); - MDNS.addServiceTxt(host, tcp, "baud_rate", String(ConfigSettings.serialSpeed)); + MDNS.addServiceTxt(host, tcp, "baud_rate", String(systemCfg.serialSpeed)); MDNS.addServiceTxt(host, tcp, "data_flow_control", "software"); + MDNS.addServiceTxt(host, tcp, "board", String(hwConfig.board)); } } @@ -1090,7 +553,7 @@ IRAM_ATTR void btnInterrupt() void setLedsDisable(bool mode, bool setup) { - if (modes.ledPwrIs || modes.ledUsbIs) + if (vars.hwLedPwrIs || vars.hwLedUsbIs) { DEBUG_PRINTLN(F("[setLedsDisable] start")); if (!setup) @@ -1106,43 +569,43 @@ void setLedsDisable(bool mode, bool setup) configFile = LittleFS.open(path, FILE_WRITE); serializeJson(doc, configFile); configFile.close(); - ConfigSettings.disableLeds = mode; - ConfigSettings.disableLedPwr = mode; - ConfigSettings.disableLedUSB = mode; + systemCfg.disableLeds = mode; + systemCfg.disableLedPwr = mode; + systemCfg.disableLedUSB = mode; } if (mode) { - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { - digitalWrite(hwConfig.ledUsbPin, !mode); + digitalWrite(hwConfig.mist.ledUsbPin, !mode); } - if (modes.ledPwrIs) + if (vars.hwLedPwrIs) { - digitalWrite(hwConfig.ledPwrPin, !mode); + digitalWrite(hwConfig.mist.ledPwrPin, !mode); } } else { - if (modes.ledPwrIs) + if (vars.hwLedPwrIs) { - if (!ConfigSettings.disableLedPwr) + if (!systemCfg.disableLedPwr) { - digitalWrite(hwConfig.ledPwrPin, !mode); + digitalWrite(hwConfig.mist.ledPwrPin, !mode); } else { - digitalWrite(hwConfig.ledPwrPin, 0); + digitalWrite(hwConfig.mist.ledPwrPin, 0); } } - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { - if (ConfigSettings.coordinator_mode == COORDINATOR_MODE_USB && !ConfigSettings.disableLedUSB) + if (vars.workMode == WORK_MODE_USB && !systemCfg.disableLedUSB) { - digitalWrite(hwConfig.ledUsbPin, !mode); + digitalWrite(hwConfig.mist.ledUsbPin, !mode); } else { - digitalWrite(hwConfig.ledUsbPin, 0); + digitalWrite(hwConfig.mist.ledUsbPin, 0); } } } @@ -1152,7 +615,7 @@ void setLedsDisable(bool mode, bool setup) void handleLongBtn() { - if (!digitalRead(hwConfig.btnPin)) + if (!digitalRead(hwConfig.mist.btnPin)) { // long press DEBUG_PRINT(F("Long press ")); DEBUG_PRINT(btnFlag); @@ -1172,7 +635,7 @@ void handleLongBtn() if (btnFlag >= 2) { printLogMsg("Long press 2sec - setLedsDisable"); - setLedsDisable(!ConfigSettings.disableLeds, false); + setLedsDisable(!systemCfg.disableLeds, false); } tmrBtnLongPress.stop(); btnFlag = false; @@ -1187,47 +650,47 @@ void toggleUsbMode() DEBUG_PRINTLN(F("coordMode")); DEBUG_PRINTLN(coordMode); delay(500); - if (ConfigSettings.coordinator_mode != COORDINATOR_MODE_USB) + if (vars.workMode != WORK_MODE_USB) { - ConfigSettings.prevCoordinator_mode = ConfigSettings.coordinator_mode; // remember current state - ConfigSettings.coordinator_mode = COORDINATOR_MODE_USB; // toggle + systemCfg.prevWorkMode = vars.workMode; // remember current state + vars.workMode = WORK_MODE_USB; // toggle DEBUG_PRINTLN(F("Change usb mode to USB")); } else { - ConfigSettings.coordinator_mode = ConfigSettings.prevCoordinator_mode; + vars.workMode = systemCfg.prevWorkMode; DEBUG_PRINTLN(F("Change usb mode to:")); - DEBUG_PRINTLN(String(ConfigSettings.coordinator_mode)); + DEBUG_PRINTLN(String(vars.workMode)); } const char *path = configFileGeneral; DynamicJsonDocument doc(300); File configFile = LittleFS.open(path, FILE_READ); deserializeJson(doc, configFile); configFile.close(); - doc[prevCoordMode] = ConfigSettings.prevCoordinator_mode; - doc[coordMode] = ConfigSettings.coordinator_mode; + doc[prevCoordMode] = systemCfg.prevWorkMode; + doc[coordMode] = vars.workMode; configFile = LittleFS.open(path, FILE_WRITE); serializeJson(doc, configFile); configFile.close(); - if (modes.ledUsbIs) + if (vars.hwLedUsbIs) { - digitalWrite(hwConfig.ledUsbPin, ConfigSettings.coordinator_mode == COORDINATOR_MODE_USB ? 1 : 0); + digitalWrite(hwConfig.mist.ledUsbPin, vars.workMode == WORK_MODE_USB ? 1 : 0); } ESP.restart(); } void setupCoordinatorMode() { - if (ConfigSettings.coordinator_mode > 2 || ConfigSettings.coordinator_mode < 0) + if (vars.workMode > 2 || vars.workMode < 0) { DEBUG_PRINTLN(F("WRONG MODE DETECTED, set to LAN")); - ConfigSettings.coordinator_mode = COORDINATOR_MODE_LAN; + vars.workMode = WORK_MODE_NETWORK; } DEBUG_PRINTLN(F("setupCoordinatorMode")); DEBUG_PRINTLN(F("Mode is:")); - DEBUG_PRINTLN(ConfigSettings.coordinator_mode); + DEBUG_PRINTLN(vars.workMode); DEBUG_PRINTLN(F("--------------")); - if (ConfigSettings.coordinator_mode != COORDINATOR_MODE_USB || ConfigSettings.keepWeb) + if (vars.workMode != WORK_MODE_USB || systemCfg.keepWeb) { // start network overseer if (tmrNetworkOverseer.state() == STOPPED) { @@ -1235,35 +698,38 @@ void setupCoordinatorMode() } WiFi.onEvent(NetworkEvent); } - switch (ConfigSettings.coordinator_mode) + switch (vars.workMode) { - case COORDINATOR_MODE_USB: + case WORK_MODE_USB: DEBUG_PRINTLN(F("Coordinator USB mode")); delay(500); - if (modes.uartChIs) + if (vars.hwUartSelIs) { - digitalWrite(hwConfig.uartChPin, 1); - DEBUG_PRINTLN(F("digitalWrite(hwConfig.uartChPin, 1) - HIGH")); + digitalWrite(hwConfig.mist.uartSelPin, 1); + DEBUG_PRINTLN(F("digitalWrite(hwConfig.mist.uartSelPin, 1) - HIGH")); } break; - case COORDINATOR_MODE_WIFI: - DEBUG_PRINTLN(F("Coordinator WIFI mode")); - // initLan(); - connectWifi(); - break; - - case COORDINATOR_MODE_LAN: - DEBUG_PRINTLN(F("Coordinator LAN mode")); - initLan(); + // case COORDINATOR_MODE_WIFI: + // DEBUG_PRINTLN(F("Coordinator WIFI mode")); + // initLan(); + // connectWifi(); + // break; + + case WORK_MODE_NETWORK: + DEBUG_PRINTLN(F("Coordinator NETWORK mode")); + if (networkCfg.ethEnable) + initLan(); + if (networkCfg.wifiEnable) + connectWifi(); break; default: break; } - if (!ConfigSettings.disableWeb && (ConfigSettings.coordinator_mode != COORDINATOR_MODE_USB || ConfigSettings.keepWeb)) + if (!systemCfg.disableWeb && (vars.workMode != WORK_MODE_USB || systemCfg.keepWeb)) updWeb = true; // handle web server - if (ConfigSettings.coordinator_mode == COORDINATOR_MODE_USB && ConfigSettings.keepWeb) + if (vars.workMode == WORK_MODE_USB && systemCfg.keepWeb) connectWifi(); // try 2 connect wifi } @@ -1286,108 +752,117 @@ void setup() { Serial.begin(115200); // todo ifdef DEBUG + //delay(3000); + // esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(0)); + + // Отключить WDT для IDLE (простоя) задачи на ядре 1 + // esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(1)); + + // Отключение TWDT (Task Watchdog Timer) + // esp_task_wdt_deinit(); + + // Ваш код setup() здесь + + String tag = "SETUP"; + /* + LOGI(tag, "CLEAR config\n"); + delay(500); + printConfig(networkCfg, vpnCfg, mqttCfg, systemCfg); + */ + initNVS(); + // printNVSFreeSpace(); + + loadNetworkConfig(networkCfg); + loadVpnConfig(vpnCfg); + loadMqttConfig(mqttCfg); + loadSystemConfig(systemCfg); + /* + LOGI(tag, "After NVS load config\n"); + delay(500); + printConfig(networkCfg, vpnCfg, mqttCfg, systemCfg); + */ + // LOAD System vars and create FS / start if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED, "/lfs2", 10)) { - DEBUG_PRINTLN(F("Error with LITTLEFS")); + LOGI(tag, "Error with LITTLEFS"); return; } - DEBUG_PRINTLN(F("LITTLEFS OK")); - if (!loadSystemVar()) - { - DEBUG_PRINTLN(F("Error load system vars")); - const char *path = "/config"; - - if (LittleFS.mkdir(path)) - { - DEBUG_PRINTLN(F("Config dir created")); - delay(500); - ESP.restart(); - } - else - { - DEBUG_PRINTLN(F("mkdir failed")); - } - } - else - { - DEBUG_PRINTLN(F("System vars load OK")); - } // LOAD System vars and create FS / end - ConfigSettings.serialSpeed = 115200; + // systemCfg.serialSpeed = 115200; - loadConfigHW(); + loadFileConfigHW(); - ConfigSettings.apStarted = false; + vars.apStarted = false; // DEBUG_PRINTLN(F("Start")); // AVOID USING PIN 0 - if (hwConfig.btnPin > 0) + if (hwConfig.mist.btnPin > 0) { - pinMode(hwConfig.btnPin, INPUT); - modes.btnIs = true; + pinMode(hwConfig.mist.btnPin, INPUT); + vars.hwBtnIs = true; } - if (hwConfig.ledUsbPin > 0) + if (hwConfig.mist.ledUsbPin > 0) { - pinMode(hwConfig.ledUsbPin, OUTPUT); - digitalWrite(hwConfig.ledUsbPin, 1); // enable ledUsbPin - modes.ledUsbIs = true; + pinMode(hwConfig.mist.ledUsbPin, OUTPUT); + digitalWrite(hwConfig.mist.ledUsbPin, 1); // enable ledUsbPin + vars.hwLedUsbIs = true; } - if (hwConfig.ledPwrPin > 0) + if (hwConfig.mist.ledPwrPin > 0) { - pinMode(hwConfig.ledPwrPin, OUTPUT); - digitalWrite(hwConfig.ledPwrPin, 1); // enable ledPwrPin - modes.ledPwrIs = true; + pinMode(hwConfig.mist.ledPwrPin, OUTPUT); + digitalWrite(hwConfig.mist.ledPwrPin, 1); // enable ledPwrPin + vars.hwLedPwrIs = true; } - if (hwConfig.uartChPin > 0) + if (hwConfig.mist.uartSelPin > 0) { - pinMode(hwConfig.uartChPin, OUTPUT); - DEBUG_PRINTLN(F("pinMode(hwConfig.uartChPin, OUTPUT)")); - digitalWrite(hwConfig.uartChPin, 0); // enable zigbee serial on LAN.so free USB + pinMode(hwConfig.mist.uartSelPin, OUTPUT); + DEBUG_PRINTLN(F("pinMode(hwConfig.mist.uartSelPin, OUTPUT)")); + digitalWrite(hwConfig.mist.uartSelPin, 0); // enable zigbee serial on LAN.so free USB DEBUG_PRINTLN(F("enable zigbee serial 1 - LOW")); - modes.uartChIs = true; + vars.hwUartSelIs = true; } - if ((hwConfig.zbTxPin > 0) && (hwConfig.zbRxPin > 0) && (hwConfig.zbRstPin > 0) && (hwConfig.zbBslPin > 0)) + if ((hwConfig.zb.txPin > 0) && (hwConfig.zb.rxPin > 0) && (hwConfig.zb.rstPin > 0) && (hwConfig.zb.bslPin > 0)) { - if (modes.uartChIs == true) + if (vars.hwUartSelIs == true) { - digitalWrite(hwConfig.uartChPin, 0); // enable zigbee serial + digitalWrite(hwConfig.mist.uartSelPin, 0); // enable zigbee serial DEBUG_PRINTLN(F("enable zigbee serial 2 - LOW")); } - Serial2.begin(ConfigSettings.serialSpeed, SERIAL_8N1, hwConfig.zbRxPin, hwConfig.zbTxPin); // start zigbee serial + Serial2.begin(systemCfg.serialSpeed, SERIAL_8N1, hwConfig.zb.rxPin, hwConfig.zb.txPin); // start zigbee serial int BSL_MODE = 0; - if (zbInit(hwConfig.zbRstPin, hwConfig.zbBslPin, BSL_MODE)) + if (zbInit(hwConfig.zb.rstPin, hwConfig.zb.bslPin, BSL_MODE)) { DEBUG_PRINTLN(F("Zigbee init - OK")); - modes.zigbeeIs = true; + vars.hwZigbeeIs = true; } else { DEBUG_PRINTLN(F("Zigbee init - ERROR")); - modes.zigbeeIs = false; + vars.hwZigbeeIs = false; } } - if (modes.btnIs) + if (vars.hwBtnIs) { // hard reset BTN -#if BUILD_ENV_NAME != debug - if (!digitalRead(hwConfig.btnPin)) +//#if BUILD_ENV_NAME != debug + if (!digitalRead(hwConfig.mist.btnPin)) { DEBUG_PRINTLN(F("[hard reset] Entering hard reset mode")); uint8_t counter = 0; - while (!digitalRead(hwConfig.btnPin)) + while (!digitalRead(hwConfig.mist.btnPin)) { if (counter >= 10) { @@ -1402,48 +877,55 @@ void setup() } DEBUG_PRINTLN(F("[hard reset] Btn up, exit")); } -#endif +//#endif - attachInterrupt(digitalPinToInterrupt(hwConfig.btnPin), btnInterrupt, FALLING); - } - if (!loadConfigSerial()) - { - DEBUG_PRINTLN(F("Error load config serial")); - ESP.restart(); - } - else - { - DEBUG_PRINTLN(F("Config serial load OK")); + attachInterrupt(digitalPinToInterrupt(hwConfig.mist.btnPin), btnInterrupt, FALLING); } - if ((!loadConfigWifi()) || (!loadConfigEther()) || (!loadConfigGeneral()) || (!loadConfigSecurity()) || (!loadConfigMqtt()) || (!loadConfigWg())) - { - DEBUG_PRINTLN(F("Error load config files")); - ESP.restart(); - } - else - { - DEBUG_PRINTLN(F("Config files load OK")); - } - DEBUG_PRINTLN("ConfigSettings.disableLeds: "); - DEBUG_PRINTLN(ConfigSettings.disableLeds); - setLedsDisable(ConfigSettings.disableLeds, true); // with setup ?? + // READ file to support migrate from old firmware + loadFileSystemVar(); + loadFileConfigSerial(); + loadFileConfigWifi(); + loadFileConfigEther(); + loadFileConfigGeneral(); + loadFileConfigSecurity(); + loadFileConfigMqtt(); + loadFileConfigWg(); + // READ file to support migrate from old firmware + + LOGI(tag, "After full load config\n"); + // printConfig(networkCfg, vpnCfg, mqttCfg, systemCfg); + String cfg = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg, &vars); + DEBUG_PRINTLN(cfg); + + DEBUG_PRINTLN(""); + + // DEBUG_PRINTLN("systemCfg.disableLeds: "); + // DEBUG_PRINTLN(systemCfg.disableLeds); + setLedsDisable(systemCfg.disableLeds, true); // with setup ?? setupCoordinatorMode(); - ConfigSettings.connectedClients = 0; + vars.connectedClients = 0; // initZb(); - if (MqttSettings.enable) - { - mqttConnectSetup(); - } - // DEBUG_PRINTLN(millis()); - // Serial2.updateBaudRate(ConfigSettings.serialSpeed); // set actual speed + // Serial2.updateBaudRate(systemCfg.serialSpeed); // set actual speed printLogMsg("Setup done"); + //delay(2000); + + printNVSFreeSpace(); - char deviceIdArr[100]; + /* + LOGI(tag, "Saving config to NVS"); + saveNetworkConfig(networkCfg); + saveVpnConfig(vpnCfg); + saveMqttConfig(mqttCfg); + saveSystemConfig(systemCfg); + printNVSFreeSpace(); + */ + + char deviceIdArr[MAX_DEV_ID_LONG]; getDeviceID(deviceIdArr); DEBUG_PRINTLN(String(deviceIdArr)); @@ -1464,35 +946,35 @@ WiFiClient client[10]; void socketClientConnected(int client) { - if (ConfigSettings.connectedSocket[client] != true) + if (vars.connectedSocket[client] != true) { DEBUG_PRINT(F("Connected client ")); DEBUG_PRINTLN(client); - if (ConfigSettings.connectedClients == 0) + if (vars.connectedClients == 0) { - ConfigSettings.socketTime = millis(); + vars.socketTime = millis(); DEBUG_PRINT(F("Socket time ")); - DEBUG_PRINTLN(ConfigSettings.socketTime); + DEBUG_PRINTLN(vars.socketTime); mqttPublishIo("socket", "ON"); } - ConfigSettings.connectedSocket[client] = true; - ConfigSettings.connectedClients++; + vars.connectedSocket[client] = true; + vars.connectedClients++; } } void socketClientDisconnected(int client) { - if (ConfigSettings.connectedSocket[client] != false) + if (vars.connectedSocket[client] != false) { DEBUG_PRINT(F("Disconnected client ")); DEBUG_PRINTLN(client); - ConfigSettings.connectedSocket[client] = false; - ConfigSettings.connectedClients--; - if (ConfigSettings.connectedClients == 0) + vars.connectedSocket[client] = false; + vars.connectedClients--; + if (vars.connectedClients == 0) { - ConfigSettings.socketTime = millis(); + vars.socketTime = millis(); DEBUG_PRINT(F("Socket time ")); - DEBUG_PRINTLN(ConfigSettings.socketTime); + DEBUG_PRINTLN(vars.socketTime); mqttPublishIo("socket", "OFF"); } } @@ -1563,9 +1045,9 @@ void printSendSocket(size_t bytes_read, uint8_t serial_buf[BUFFER_SIZE]) void loop(void) { - if (btnFlag && modes.btnIs) + if (btnFlag && vars.hwBtnIs) { - if (!digitalRead(hwConfig.btnPin)) + if (!digitalRead(hwConfig.mist.btnPin)) { // pressed if (tmrBtnLongPress.state() == STOPPED) { @@ -1591,13 +1073,13 @@ void loop(void) } else { - if (ConfigSettings.connectedClients == 0) + if (vars.connectedClients == 0) { webServerHandleClient(); } } - if (ConfigSettings.coordinator_mode != COORDINATOR_MODE_USB) + if (vars.workMode != WORK_MODE_USB) { uint16_t net_bytes_read = 0; uint8_t net_buf[BUFFER_SIZE]; @@ -1614,10 +1096,10 @@ void loop(void) { client[i].stop(); } - if (ConfigSettings.fwEnabled) + if (systemCfg.fwEnabled) { WiFiClient TempClient2 = server.available(); - if (TempClient2.remoteIP() == ConfigSettings.fwIp) + if (TempClient2.remoteIP() == systemCfg.fwIp) { printLogMsg(String("[SOCK IP WHITELIST] Accepted connection from IP: ") + TempClient2.remoteIP().toString()); client[i] = TempClient2; @@ -1680,11 +1162,15 @@ void loop(void) serial_bytes_read = 0; } - if (MqttSettings.enable) + if (mqttCfg.enable) { mqttLoop(); } } + if (vpnCfg.wgEnable && vars.vpnWgInit) { + wgLoop(); + } + if (WiFi.getMode() == WIFI_MODE_AP || WiFi.getMode() == WIFI_MODE_APSTA) { diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 8d01ec7..ce810bd 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "config.h" #include "web.h" @@ -13,77 +14,92 @@ #include "etc.h" #include "mqtt.h" -extern struct ConfigSettingsStruct ConfigSettings; +// extern struct ConfigSettingsStruct ConfigSettings; extern struct zbVerStruct zbVer; -extern struct MqttSettingsStruct MqttSettings; +// extern struct MqttSettingsStruct MqttSettings; + +extern struct SystemConfigStruct systemCfg; +extern struct NetworkConfigStruct networkCfg; +extern struct MqttConfigStruct mqttCfg; + +extern struct SysVarsStruct vars; WiFiClient clientMqtt; PubSubClient clientPubSub(clientMqtt); +String tagMQTT = "MQTT"; const char *homeAssistant = "homeassistant"; const char *haSensor = "sensor"; const char *haButton = "button"; const char *haBinarySensor = "binary_sensor"; +const char *willMessage = "offline"; void mqttConnectSetup() { - clientPubSub.setServer(MqttSettings.serverIP, MqttSettings.port); - clientPubSub.setCallback(mqttCallback); + LOGI(tagMQTT, "Try to connect %s:%d", mqttCfg.server, mqttCfg.port); + if (strlen(mqttCfg.server) > 0 && mqttCfg.port > 0) + { + clientPubSub.setServer(mqttCfg.server, mqttCfg.port); // + LOGI(tagMQTT, "Try to setCallback"); + clientPubSub.setCallback(mqttCallback); + } + else + { + LOGE(tagMQTT, "Error in config"); + } } -void mqttReconnect() +bool mqttReconnect() { - DEBUG_PRINT(F("Attempting MQTT connection...")); + LOGI(tagMQTT, "Attempting MQTT connection..."); byte willQoS = 0; - String willTopic = String(MqttSettings.topic) + "/avty"; - const char *willMessage = "offline"; + String willTopic = String(mqttCfg.topic) + "/avty"; + boolean willRetain = false; - char deviceIdArr[20]; + char deviceIdArr[MAX_DEV_ID_LONG]; getDeviceID(deviceIdArr); - if (clientPubSub.connect(String(deviceIdArr).c_str(), MqttSettings.user, MqttSettings.pass, willTopic.c_str(), willQoS, willRetain, willMessage)) + if (clientPubSub.connect(deviceIdArr, mqttCfg.user, mqttCfg.pass, willTopic.c_str(), willQoS, willRetain, willMessage)) { - MqttSettings.reconnectTime = 0; + vars.mqttReconnectTime = 0; mqttOnConnect(); + LOGI(tagMQTT, "OK, %d", clientPubSub.state()); + return true; } else { - DEBUG_PRINT(F("failed, rc=")); - DEBUG_PRINT(clientPubSub.state()); - DEBUG_PRINT(F(" try again in ")); - DEBUG_PRINT(MqttSettings.interval); - DEBUG_PRINTLN(F(" seconds")); + LOGI(tagMQTT, "failed, rc= %d try again in %d seconds", clientPubSub.state(), mqttCfg.reconnectInt); - MqttSettings.reconnectTime = millis() + MqttSettings.interval * 1000; + return false; } } void mqttOnConnect() { - DEBUG_PRINTLN(F("connected")); - MqttSettings.connect = true; + //LOGI(tagMQTT, "connected"); + vars.mqttConn = true; mqttSubscribe("cmd"); - DEBUG_PRINTLN(F("mqtt Subscribed")); - if (MqttSettings.discovery) + LOGI(tagMQTT, "mqtt Subscribed"); + if (mqttCfg.discovery) { mqttPublishDiscovery(); - DEBUG_PRINTLN(F("mqtt Published Discovery")); + LOGI(tagMQTT, "mqtt Published Discovery"); } mqttPublishIo("rst_esp", "OFF"); mqttPublishIo("rst_zig", "OFF"); mqttPublishIo("enbl_bsl", "OFF"); mqttPublishIo("socket", "OFF"); - DEBUG_PRINTLN(F("mqtt Published IOs")); + LOGI(tagMQTT, "mqtt Published IOs"); mqttPublishAvail(); - DEBUG_PRINTLN(F("mqtt Published Avty")); - if (MqttSettings.interval > 0) + LOGI(tagMQTT, "mqtt Published Avty"); + if (mqttCfg.updateInt > 0) { mqttPublishState(); - DEBUG_PRINTLN(F("mqtt Published State")); + LOGI(tagMQTT, "mqtt Published State"); } } @@ -96,7 +112,7 @@ void mqttPublishMsg(String topic, String msg, bool retain) void mqttPublishAvail() { - String topic(MqttSettings.topic); + String topic(mqttCfg.topic); topic = topic + "/avty"; String mqttBuffer = "online"; clientPubSub.publish(topic.c_str(), mqttBuffer.c_str(), true); @@ -104,7 +120,7 @@ void mqttPublishAvail() void mqttPublishState() { - String topic(MqttSettings.topic); + String topic(mqttCfg.topic); topic = topic + "/state"; DynamicJsonDocument root(1024); String readableTime; @@ -113,67 +129,68 @@ void mqttPublishState() float CPUtemp = getCPUtemp(); root["temperature"] = String(CPUtemp); - - root["connections"] = ConfigSettings.connectedClients; - - if (ConfigSettings.connectedEther) + + root["connections"] = vars.connectedClients; + + if (vars.connectedEther) { - if (ConfigSettings.dhcp) + if (networkCfg.ethDhcp) { root["ip"] = ETH.localIP().toString(); } else { - root["ip"] = ConfigSettings.ipAddress; + root["ip"] = networkCfg.ethAddr; } } else { - if (ConfigSettings.dhcpWiFi) + if (networkCfg.wifiDhcp) { root["ip"] = WiFi.localIP().toString(); } else { - root["ip"] = ConfigSettings.ipAddressWiFi; + root["ip"] = networkCfg.wifiAddr; } } - //if (ConfigSettings.emergencyWifi) + // if (ConfigSettings.emergencyWifi) //{ - // root["emergencyMode"] = "ON"; - //} - //else + // root["emergencyMode"] = "ON"; + // } + // else //{ - // root["emergencyMode"] = "OFF"; - //} + // root["emergencyMode"] = "OFF"; + // } - switch (ConfigSettings.coordinator_mode) { - case COORDINATOR_MODE_USB: - root["mode"] = "Zigbee-to-USB"; - break; - case COORDINATOR_MODE_WIFI: - root["mode"] = "Zigbee-to-WiFi"; - break; - case COORDINATOR_MODE_LAN: - root["mode"] = "Zigbee-to-Ethernet"; - break; - default: - break; + switch (vars.workMode) + { + case WORK_MODE_USB: + root["mode"] = "Zigbee-to-USB"; + break; + /*case COORDINATOR_MODE_WIFI: + root["mode"] = "Zigbee-to-WiFi"; + break;*/ + case WORK_MODE_NETWORK: + root["mode"] = "Zigbee-to-Network"; + break; + default: + break; } root["zbfw"] = String(zbVer.zbRev); - root["hostname"] = ConfigSettings.hostname; + root["hostname"] = systemCfg.hostname; String mqttBuffer; serializeJson(root, mqttBuffer); - DEBUG_PRINTLN(mqttBuffer); + // DEBUG_PRINTLN(mqttBuffer); clientPubSub.publish(topic.c_str(), mqttBuffer.c_str(), true); - MqttSettings.heartbeatTime = millis() + (MqttSettings.interval * 1000); + vars.mqttHeartbeatTime = millis() + (mqttCfg.updateInt * 1000); } void mqttPublishIo(String const &io, String const &state) { if (clientPubSub.connected()) { - String topic(MqttSettings.topic); + String topic(mqttCfg.topic); topic = topic + "/io/" + io; clientPubSub.publish(topic.c_str(), state.c_str(), true); } @@ -183,20 +200,20 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) { char jjson[length + 1]; memcpy(jjson, payload, length); - jjson[length + 1] = '\0'; + //jjson[length + 1] = '\0'; + jjson[length] = '\0'; - DynamicJsonDocument jsonBuffer(1024); + DynamicJsonDocument jsonBuffer(512); deserializeJson(jsonBuffer, jjson); const char *command = jsonBuffer["cmd"]; - DEBUG_PRINT(F("mqtt Callback - ")); - DEBUG_PRINTLN(jjson); + LOGI(tagMQTT, "mqtt Callback - %s", String(jjson)); - if (command) { - DEBUG_PRINT(F("mqtt cmd - ")); - DEBUG_PRINTLN(command); + if (command) + { + LOGI(tagMQTT, "mqtt cmd - %s", String(command)); if (strcmp(command, "rst_esp") == 0) { printLogMsg("ESP restart MQTT"); @@ -220,7 +237,7 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) void mqttSubscribe(String topic) { - String mtopic(MqttSettings.topic); + String mtopic(mqttCfg.topic); mtopic = mtopic + "/" + topic; clientPubSub.subscribe(mtopic.c_str()); } @@ -228,242 +245,249 @@ void mqttSubscribe(String topic) void mqttLoop() { if (!clientPubSub.connected()) - { - MqttSettings.connect = false; - if (MqttSettings.reconnectTime == 0) + { + vars.mqttConn = false; + if (vars.mqttReconnectTime == 0) { - //mqttReconnect(); - DEBUG_PRINTLN(F("mqttReconnect in 5 seconds")); - MqttSettings.reconnectTime = millis() + 5000; + // mqttReconnect(); + LOGI(tagMQTT, "Connect in %d seconds", mqttCfg.reconnectInt); + vars.mqttReconnectTime = millis() + mqttCfg.reconnectInt*1000; } else { - if (MqttSettings.reconnectTime <= millis()) + if (vars.mqttReconnectTime <= millis()) { - mqttReconnect(); + bool conn = mqttReconnect(); + //LOGI(tagMQTT, "mqttReconnect exit with %s", conn ? "true" : "false"); + vars.mqttReconnectTime = millis() + mqttCfg.reconnectInt*1000; } } } else { clientPubSub.loop(); - if (MqttSettings.interval > 0) + if (mqttCfg.updateInt > 0) { - if (MqttSettings.heartbeatTime <= millis()) + if (vars.mqttHeartbeatTime <= millis()) { mqttPublishState(); } } } + // LOGI(tagMQTT, "loop end"); } void mqttPublishDiscovery() { - String mtopic(MqttSettings.topic); - String deviceName = mtopic; //ConfigSettings.hostname; + String mtopic(mqttCfg.topic); + String deviceName = mtopic; // systemCfg.hostname; String topic; DynamicJsonDocument buffJson(2048); String mqttBuffer; - DynamicJsonDocument via(1024); - char deviceIdArr[20]; + DynamicJsonDocument via(150); + char deviceIdArr[MAX_DEV_ID_LONG]; getDeviceID(deviceIdArr); via["ids"] = String(deviceIdArr); String sensor_topic = String(homeAssistant) + "/" + String(haSensor) + "/"; String button_topic = String(homeAssistant) + "/" + String(haButton) + "/"; String binary_sensor_topic = String(homeAssistant) + "/" + String(haBinarySensor) + "/"; - //int lastAutoMsg = 9; - //if (ConfigSettings.board == 2) lastAutoMsg--; + // int lastAutoMsg = 9; + // if (ConfigSettings.board == 2) lastAutoMsg--; for (int i = 0; i <= 99; i++) { switch (i) { - case 0: - { - DynamicJsonDocument dev(1024); - char deviceIdArr[20]; - getDeviceID(deviceIdArr); - - dev["ids"] = String(deviceIdArr); - dev["name"] = ConfigSettings.hostname; - dev["mf"] = "Zig Star"; - //dev["mdl"] = ConfigSettings.boardName; - - char verArr[25]; - const char * env = STRINGIFY(BUILD_ENV_NAME); - sprintf(verArr, "%s (%s)", VERSION, env); - dev["sw"] = String(verArr); - - topic = button_topic + deviceName + "/rst_esp/config"; - buffJson["name"] = "Restart ESP"; - buffJson["uniq_id"] = deviceName + "/rst_esp"; - buffJson["stat_t"] = mtopic + "/io/rst_esp"; - buffJson["cmd_t"] = mtopic + "/cmd"; - buffJson["icon"] = "mdi:restore-alert"; - buffJson["payload_press"] = "{cmd:\"rst_esp\"}"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["dev"] = dev; - break; - } - case 1: - { - topic = button_topic + deviceName + "/rst_zig/config"; - buffJson["name"] = "Restart Zigbee"; - buffJson["uniq_id"] = deviceName + "/rst_zig"; - buffJson["stat_t"] = mtopic + "/io/rst_zig"; - buffJson["cmd_t"] = mtopic + "/cmd"; - buffJson["icon"] = "mdi:restart"; - buffJson["payload_press"] = "{cmd:\"rst_zig\"}"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["dev"] = via; - break; - } - case 2: - { - topic = button_topic + deviceName + "/enbl_bsl/config"; - buffJson["name"] = "Enable BSL"; - buffJson["uniq_id"] = deviceName + "/enbl_bsl"; - buffJson["stat_t"] = mtopic + "/io/enbl_bsl"; - buffJson["cmd_t"] = mtopic + "/cmd"; - buffJson["icon"] = "mdi:flash"; - buffJson["payload_press"] = "{cmd:\"enbl_bsl\"}"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["dev"] = via; - break; - } - case 3: - { - topic = binary_sensor_topic + deviceName + "/socket/config"; - buffJson["name"] = "Socket"; - buffJson["uniq_id"] = deviceName + "/socket"; - buffJson["stat_t"] = mtopic + "/io/socket"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["dev_cla"] = "connectivity"; - buffJson["dev"] = via; - break; - } - //case 4: - //{ - // topic = binary_sensor_topic + deviceName + "/emrgncMd/config"; - // buffJson["name"] = "Emergency mode"; - // buffJson["uniq_id"] = deviceName + "/emrgncMd"; - // buffJson["stat_t"] = mtopic + "/state"; - // buffJson["avty_t"] = mtopic + "/avty"; - // buffJson["val_tpl"] = "{{ value_json.emergencyMode }}"; - // buffJson["json_attr_t"] = mtopic + "/state"; - // buffJson["dev_cla"] = "power"; - // buffJson["icon"] = "mdi:access-point-network"; - // buffJson["dev"] = via; - // break; - //} - case 4: - { - topic = sensor_topic + deviceName + "/uptime/config"; - buffJson["name"] = "Uptime"; - buffJson["uniq_id"] = deviceName + "/uptime"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.uptime }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:clock"; - buffJson["dev"] = via; - break; - } - case 5: - { - topic = sensor_topic + deviceName + "/ip/config"; - buffJson["name"] = "IP"; - buffJson["uniq_id"] = deviceName + "/ip"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.ip }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:check-network"; - buffJson["dev"] = via; - break; - } - case 6: - { - topic = sensor_topic + deviceName + "/temperature/config"; - buffJson["name"] = "ESP temperature"; - buffJson["uniq_id"] = deviceName + "/temperature"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.temperature }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:coolant-temperature"; - buffJson["dev"] = via; - buffJson["dev_cla"] = "temperature"; - buffJson["stat_cla"] = "measurement"; - buffJson["unit_of_meas"] = "°C"; - break; - } - case 7: - { - topic = sensor_topic + deviceName + "/hostname/config"; - buffJson["name"] = "Hostname"; - buffJson["uniq_id"] = deviceName + "/hostname"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.hostname }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:account-network"; - buffJson["dev"] = via; - break; - } - case 8: - { - topic = sensor_topic + deviceName + "/connections/config"; - buffJson["name"] = "Socket connections"; - buffJson["uniq_id"] = deviceName + "/connections"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.connections }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:check-network-outline"; - buffJson["dev"] = via; - break; - } - case 9: - { - topic = sensor_topic + deviceName + "/mode/config"; - buffJson["name"] = "Mode"; - buffJson["uniq_id"] = deviceName + "/mode"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.mode }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:access-point-network"; - buffJson["dev"] = via; - break; - } - case 10: - { - topic = sensor_topic + deviceName + "/zbfw/config"; - buffJson["name"] = "Zigbee fw rev"; - buffJson["uniq_id"] = deviceName + "/zbfw"; - buffJson["stat_t"] = mtopic + "/state"; - buffJson["avty_t"] = mtopic + "/avty"; - buffJson["val_tpl"] = "{{ value_json.zbfw }}"; - buffJson["json_attr_t"] = mtopic + "/state"; - buffJson["icon"] = "mdi:access-point-network"; - buffJson["dev"] = via; - break; - } - default: - topic = "error"; - break; + case 0: + { + DynamicJsonDocument dev(256); + char deviceIdArr[MAX_DEV_ID_LONG]; + getDeviceID(deviceIdArr); + + dev["ids"] = String(deviceIdArr); + dev["name"] = systemCfg.hostname; + dev["mf"] = "Zig Star"; + // dev["mdl"] = ConfigSettings.boardName; + + char verArr[25]; + const char *env = STRINGIFY(BUILD_ENV_NAME); + sprintf(verArr, "%s (%s)", VERSION, env); + dev["sw"] = String(verArr); + + topic = button_topic + deviceName + "/rst_esp/config"; + buffJson["name"] = "Restart ESP"; + buffJson["uniq_id"] = deviceName + "/rst_esp"; + buffJson["stat_t"] = mtopic + "/io/rst_esp"; + buffJson["cmd_t"] = mtopic + "/cmd"; + buffJson["icon"] = "mdi:restore-alert"; + buffJson["payload_press"] = "{cmd:\"rst_esp\"}"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["dev"] = dev; + break; + } + case 1: + { + topic = button_topic + deviceName + "/rst_zig/config"; + buffJson["name"] = "Restart Zigbee"; + buffJson["uniq_id"] = deviceName + "/rst_zig"; + buffJson["stat_t"] = mtopic + "/io/rst_zig"; + buffJson["cmd_t"] = mtopic + "/cmd"; + buffJson["icon"] = "mdi:restart"; + buffJson["payload_press"] = "{cmd:\"rst_zig\"}"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["dev"] = via; + break; + } + case 2: + { + topic = button_topic + deviceName + "/enbl_bsl/config"; + buffJson["name"] = "Enable BSL"; + buffJson["uniq_id"] = deviceName + "/enbl_bsl"; + buffJson["stat_t"] = mtopic + "/io/enbl_bsl"; + buffJson["cmd_t"] = mtopic + "/cmd"; + buffJson["icon"] = "mdi:flash"; + buffJson["payload_press"] = "{cmd:\"enbl_bsl\"}"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["dev"] = via; + break; + } + case 3: + { + topic = binary_sensor_topic + deviceName + "/socket/config"; + buffJson["name"] = "Socket"; + buffJson["uniq_id"] = deviceName + "/socket"; + buffJson["stat_t"] = mtopic + "/io/socket"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["dev_cla"] = "connectivity"; + buffJson["dev"] = via; + break; + } + // case 4: + //{ + // topic = binary_sensor_topic + deviceName + "/emrgncMd/config"; + // buffJson["name"] = "Emergency mode"; + // buffJson["uniq_id"] = deviceName + "/emrgncMd"; + // buffJson["stat_t"] = mtopic + "/state"; + // buffJson["avty_t"] = mtopic + "/avty"; + // buffJson["val_tpl"] = "{{ value_json.emergencyMode }}"; + // buffJson["json_attr_t"] = mtopic + "/state"; + // buffJson["dev_cla"] = "power"; + // buffJson["icon"] = "mdi:access-point-network"; + // buffJson["dev"] = via; + // break; + // } + case 4: + { + topic = sensor_topic + deviceName + "/uptime/config"; + buffJson["name"] = "Uptime"; + buffJson["uniq_id"] = deviceName + "/uptime"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.uptime }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:clock"; + buffJson["dev"] = via; + break; + } + case 5: + { + topic = sensor_topic + deviceName + "/ip/config"; + buffJson["name"] = "IP"; + buffJson["uniq_id"] = deviceName + "/ip"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.ip }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:check-network"; + buffJson["dev"] = via; + break; + } + case 6: + { + topic = sensor_topic + deviceName + "/temperature/config"; + buffJson["name"] = "ESP temperature"; + buffJson["uniq_id"] = deviceName + "/temperature"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.temperature }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:coolant-temperature"; + buffJson["dev"] = via; + buffJson["dev_cla"] = "temperature"; + buffJson["stat_cla"] = "measurement"; + buffJson["unit_of_meas"] = "°C"; + break; } - if (topic != "error") { + case 7: + { + topic = sensor_topic + deviceName + "/hostname/config"; + buffJson["name"] = "Hostname"; + buffJson["uniq_id"] = deviceName + "/hostname"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.hostname }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:account-network"; + buffJson["dev"] = via; + break; + } + case 8: + { + topic = sensor_topic + deviceName + "/connections/config"; + buffJson["name"] = "Socket connections"; + buffJson["uniq_id"] = deviceName + "/connections"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.connections }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:check-network-outline"; + buffJson["dev"] = via; + break; + } + case 9: + { + topic = sensor_topic + deviceName + "/mode/config"; + buffJson["name"] = "Mode"; + buffJson["uniq_id"] = deviceName + "/mode"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.mode }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:access-point-network"; + buffJson["dev"] = via; + break; + } + case 10: + { + topic = sensor_topic + deviceName + "/zbfw/config"; + buffJson["name"] = "Zigbee fw rev"; + buffJson["uniq_id"] = deviceName + "/zbfw"; + buffJson["stat_t"] = mtopic + "/state"; + buffJson["avty_t"] = mtopic + "/avty"; + buffJson["val_tpl"] = "{{ value_json.zbfw }}"; + buffJson["json_attr_t"] = mtopic + "/state"; + buffJson["icon"] = "mdi:access-point-network"; + buffJson["dev"] = via; + break; + } + default: + topic = "error"; + break; + } + if (topic != "error") + { serializeJson(buffJson, mqttBuffer); - //DEBUG_PRINTLN(mqttBuffer); + // DEBUG_PRINTLN(mqttBuffer); mqttPublishMsg(topic, mqttBuffer, true); buffJson.clear(); mqttBuffer = ""; } - else { i = 100; } + else + { + i = 100; + } } } \ No newline at end of file diff --git a/src/mqtt.h b/src/mqtt.h index 113700d..c87a21c 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -1,6 +1,6 @@ void mqttConnectSetup(); -void mqttReconnect(); +bool mqttReconnect(); void mqttCallback(char *topic, byte *payload, unsigned int length); void mqttLoop(); void mqttPublishState(); diff --git a/src/version.h b/src/version.h index 44f1dbc..693b9f1 100644 --- a/src/version.h +++ b/src/version.h @@ -1,9 +1,5 @@ - // AUTO GENERATED FILE, DO NOT EDIT - #ifndef VERSION - #define VERSION "1.0.1" - #endif - #ifndef BUILD_TIMESTAMP - #define BUILD_TIMESTAMP "2024-03-25 00:16:26.247681" - #endif - \ No newline at end of file +// AUTO GENERATED FILE, DO NOT EDIT +#ifndef VERSION + #define VERSION "20240330" +#endif diff --git a/src/web.cpp b/src/web.cpp index 1b43158..c2f87e2 100644 --- a/src/web.cpp +++ b/src/web.cpp @@ -16,18 +16,18 @@ #include "etc.h" #include "zb.h" #include "zones.h" +// #include "hw.h" -#include "webh/PAGE_WG.html.gz.h" +#include "webh/PAGE_VPN.html.gz.h" #include "webh/PAGE_MQTT.html.gz.h" #include "webh/PAGE_ABOUT.html.gz.h" -#include "webh/PAGE_ETHERNET.html.gz.h" #include "webh/PAGE_GENERAL.html.gz.h" #include "webh/PAGE_LOADER.html.gz.h" #include "webh/PAGE_ROOT.html.gz.h" #include "webh/PAGE_SECURITY.html.gz.h" -#include "webh/PAGE_SERIAL.html.gz.h" -#include "webh/PAGE_SYSTOOLS.html.gz.h" -#include "webh/PAGE_WIFI.html.gz.h" +#include "webh/PAGE_ZIGBEE.html.gz.h" +#include "webh/PAGE_TOOLS.html.gz.h" +#include "webh/PAGE_NETWORK.html.gz.h" #include "webh/PAGE_LOGOUT.html.gz.h" #include "webh/bootstrap.min.js.gz.h" #include "webh/functions.js.gz.h" @@ -46,12 +46,21 @@ // #define HTTP_MAX_SEND_WAIT 10000 // ms to wait for data chunk to be ACKed // #define HTTP_MAX_CLOSE_WAIT 4000 // ms to wait for the client to close the connection -extern struct ConfigSettingsStruct ConfigSettings; +// extern struct ConfigSettingsStruct ConfigSettings; extern struct zbVerStruct zbVer; -extern struct MqttSettingsStruct MqttSettings; -extern struct WgSettingsStruct WgSettings; +// extern struct MqttSettingsStruct MqttSettings; +// extern struct WgSettingsStruct WgSettings; extern struct BrdConfigStruct hwConfig; -extern struct CurrentModesStruct modes; +extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT]; + +// extern struct CurrentModesStruct modes; + +extern struct SystemConfigStruct systemCfg; +extern struct NetworkConfigStruct networkCfg; +extern struct VpnConfigStruct vpnCfg; +extern struct MqttConfigStruct mqttCfg; + +extern struct SysVarsStruct vars; bool wifiWebSetupInProgress = false; extern const char *coordMode; @@ -78,21 +87,21 @@ const char *tempFile = "/config/fw.hex"; bool opened = false; File fwFile; -extern bool loadConfigMqtt(); -extern bool loadConfigWg(); +extern bool loadFileConfigMqtt(); +extern bool loadFileConfigWg(); enum API_PAGE_t : uint8_t { API_PAGE_ROOT, API_PAGE_GENERAL, API_PAGE_ETHERNET, - API_PAGE_WIFI, - API_PAGE_ZHA_Z2M, + API_PAGE_NETWORK, + API_PAGE_ZIGBEE, API_PAGE_SECURITY, - API_PAGE_SYSTOOLS, + API_PAGE_TOOLS, API_PAGE_ABOUT, API_PAGE_MQTT, - API_PAGE_WG + API_PAGE_VPN }; WebServer serverWeb(80); @@ -138,19 +147,19 @@ void initWebServer() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); serverWeb.on("/security", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); - serverWeb.on("/wifi", []() + serverWeb.on("/network", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); serverWeb.on("/ethernet", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); - serverWeb.on("/zha-z2m", []() + serverWeb.on("/zigbee", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); serverWeb.on("/about", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); - serverWeb.on("/sys-tools", []() + serverWeb.on("/tools", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); serverWeb.on("/mqtt", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); - serverWeb.on("/wg", []() + serverWeb.on("/vpn", []() { sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len); }); serverWeb.on("/saveParams", HTTP_POST, handleSaveParams); serverWeb.on("/cmdZigRST", handleZigbeeRestart); @@ -395,7 +404,7 @@ void handleApi() const char *wrongArgs = "wrong args"; const char *ok = "ok"; - if (ConfigSettings.webAuth) + if (systemCfg.webAuth) { if (!checkAuth()) { // Authentication @@ -423,7 +432,7 @@ void handleApi() { case API_FLASH_ZB: { - ConfigSettings.zbFlashing = 1; + vars.zbFlashing = 1; const char *fwurlArg = "fwurl"; const uint8_t eventLen = 11; const char *tagZB_FW_info = "ZB_FW_info"; @@ -483,7 +492,7 @@ void handleApi() { serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, "missing arg 1"); } - ConfigSettings.zbFlashing = 0; + vars.zbFlashing = 0; } break; case API_GET_LOG: @@ -634,7 +643,7 @@ void handleApi() { if (serverWeb.arg(param) == "refreshLogs") { - resp = (String)ConfigSettings.refreshLogs; + resp = (String)systemCfg.refreshLogs; } else if (serverWeb.arg(param) == "coordMode") { @@ -644,7 +653,7 @@ void handleApi() } else { - resp = (String)ConfigSettings.coordinator_mode; + resp = (String)vars.workMode; } } else if (serverWeb.arg(param) == "zbRev") @@ -655,6 +664,25 @@ void handleApi() { resp = VERSION; } + else if (serverWeb.arg(param) == "wifiEnable") + { + resp = networkCfg.wifiEnable; + } + else if (serverWeb.arg(param) == "all") + { + resp = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg); + } + else if (serverWeb.arg(param) == "vars") + { + resp = makeJsonConfig(NULL, NULL, NULL, NULL, &vars); + } + else if (serverWeb.arg(param) == "root") + { + resp = ""; + DynamicJsonDocument doc(1024); + doc = getRootData(); + serializeJson(doc, resp); + } } serverWeb.send(HTTP_CODE_OK, contTypeText, resp); } @@ -695,7 +723,7 @@ void handleApi() wifi_0["secure"] = WiFi.encryptionType(i); } WiFi.scanDelete(); - // if (ConfigSettings.coordinator_mode == COORDINATOR_MODE_LAN) WiFi.mode(WIFI_OFF); no more wifi scan in lan mode + // if (vars.workMode == WORK_MODE_NETWORK) WiFi.mode(WIFI_OFF); no more wifi scan in lan mode } if (timeout < 10) { @@ -706,7 +734,7 @@ void handleApi() doc[scanDone] = true; WiFi.scanDelete(); timeout = 0; - // if (ConfigSettings.coordinator_mode == COORDINATOR_MODE_LAN) WiFi.mode(WIFI_OFF); + // if (vars.workMode == WORK_MODE_NETWORK) WiFi.mode(WIFI_OFF); } serializeJson(doc, result); @@ -731,25 +759,25 @@ void handleApi() handleGeneral(); sendGzip(contTypeTextHtml, PAGE_GENERAL_html_gz, PAGE_GENERAL_html_gz_len); break; - case API_PAGE_ETHERNET: + /*case API_PAGE_ETHERNET: handleEther(); sendGzip(contTypeTextHtml, PAGE_ETHERNET_html_gz, PAGE_ETHERNET_html_gz_len); + break;*/ + case API_PAGE_NETWORK: + handleNetwork(); + sendGzip(contTypeTextHtml, PAGE_NETWORK_html_gz, PAGE_NETWORK_html_gz_len); break; - case API_PAGE_WIFI: - handleWifi(); - sendGzip(contTypeTextHtml, PAGE_WIFI_html_gz, PAGE_WIFI_html_gz_len); - break; - case API_PAGE_ZHA_Z2M: + case API_PAGE_ZIGBEE: handleSerial(); - sendGzip(contTypeTextHtml, PAGE_SERIAL_html_gz, PAGE_SERIAL_html_gz_len); + sendGzip(contTypeTextHtml, PAGE_ZIGBEE_html_gz, PAGE_ZIGBEE_html_gz_len); break; case API_PAGE_SECURITY: handleSecurity(); sendGzip(contTypeTextHtml, PAGE_SECURITY_html_gz, PAGE_SECURITY_html_gz_len); break; - case API_PAGE_SYSTOOLS: + case API_PAGE_TOOLS: handleSysTools(); - sendGzip(contTypeTextHtml, PAGE_SYSTOOLS_html_gz, PAGE_SYSTOOLS_html_gz_len); + sendGzip(contTypeTextHtml, PAGE_TOOLS_html_gz, PAGE_TOOLS_html_gz_len); break; case API_PAGE_ABOUT: // handleAbout(); @@ -759,9 +787,9 @@ void handleApi() handleMqtt(); sendGzip(contTypeTextHtml, PAGE_MQTT_html_gz, PAGE_MQTT_html_gz_len); break; - case API_PAGE_WG: - handleWg(); - sendGzip(contTypeTextHtml, PAGE_WG_html_gz, PAGE_WG_html_gz_len); + case API_PAGE_VPN: + handleVpn(); + sendGzip(contTypeTextHtml, PAGE_VPN_html_gz, PAGE_VPN_html_gz_len); break; default: break; @@ -795,334 +823,338 @@ void handleApi() void handleSaveParams() { - String result; - DynamicJsonDocument doc(512); - const char *pageId = "pageId"; - const char *on = "on"; - File configFile; - const uint8_t one = 1; - const uint8_t zero = 0; - if (serverWeb.hasArg(pageId)) + updateConfiguration(serverWeb, systemCfg, networkCfg, vpnCfg, mqttCfg); +} +/* +String result; +DynamicJsonDocument doc(512); +const char *pageId = "pageId"; +const char *on = "on"; +File configFile; +const uint8_t one = 1; +const uint8_t zero = 0; +if (serverWeb.hasArg(pageId)) +{ + switch (serverWeb.arg(pageId).toInt()) + { + case API_PAGE_GENERAL: { - switch (serverWeb.arg(pageId).toInt()) - { - case API_PAGE_GENERAL: - { - configFile = LittleFS.open(configFileGeneral, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - if (serverWeb.hasArg(coordMode)) - { - const uint8_t mode = serverWeb.arg(coordMode).toInt(); - if (mode <= 2 && mode >= zero) - { - // ConfigSettings.coordinator_mode = static_cast(mode); - if (mode == 1) - wifiWebSetupInProgress = true; - doc[coordMode] = static_cast(mode); - } - } - const char *keepWeb = "keepWeb"; - if (serverWeb.arg(keepWeb) == on) - { - doc[keepWeb] = one; - } - else - { - doc[keepWeb] = zero; - } - const char *disableLedPwr = "disableLedPwr"; - if (serverWeb.arg(disableLedPwr) == on) + configFile = LittleFS.open(configFileGeneral, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + + if (serverWeb.hasArg(coordMode)) + { + const uint8_t mode = serverWeb.arg(coordMode).toInt(); + if (mode <= 2 && mode >= zero) { - doc[disableLedPwr] = one; + // vars.workMode = static_cast(mode); + if (mode == 1) + wifiWebSetupInProgress = true; + doc[coordMode] = static_cast(mode); } - else + } + const char *keepWeb = "keepWeb"; + if (serverWeb.arg(keepWeb) == on) + { + doc[keepWeb] = one; + } + else + { + doc[keepWeb] = zero; + } + const char *disableLedPwr = "disableLedPwr"; + if (serverWeb.arg(disableLedPwr) == on) + { + doc[disableLedPwr] = one; + } + else + { + doc[disableLedPwr] = zero; + } + const char *disableLedUSB = "disableLedUSB"; + if (serverWeb.arg(disableLedUSB) == on) + { + doc[disableLedUSB] = one; + } + else + { + doc[disableLedUSB] = zero; + } + configFile = LittleFS.open(configFileGeneral, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + } + break; + case API_PAGE_ETHERNET: + { + configFile = LittleFS.open(configFileEther, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + doc["ip"] = serverWeb.arg("ipAddress"); + doc["mask"] = serverWeb.arg("ipMask"); + doc["gw"] = serverWeb.arg("ipGW"); + const char *dhcp = "dhcp"; + if (serverWeb.arg(dhcp) == "on") + { + doc[dhcp] = one; + } + else + { + doc[dhcp] = zero; + if (doc["mask"] == "") { - doc[disableLedPwr] = zero; + doc["mask"] = "255.255.255.0"; } - const char *disableLedUSB = "disableLedUSB"; - if (serverWeb.arg(disableLedUSB) == on) + if (doc["ip"] == "") { - doc[disableLedUSB] = one; + doc["ip"] = "192.168.0.1"; } - else + if (doc["gw"] == "") { - doc[disableLedUSB] = zero; + doc["gw"] = "192.168.0.1"; } - configFile = LittleFS.open(configFileGeneral, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); } - break; - case API_PAGE_ETHERNET: - { - configFile = LittleFS.open(configFileEther, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - doc["ip"] = serverWeb.arg("ipAddress"); - doc["mask"] = serverWeb.arg("ipMask"); - doc["gw"] = serverWeb.arg("ipGW"); - const char *dhcp = "dhcp"; - if (serverWeb.arg(dhcp) == "on") - { - doc[dhcp] = one; - } - else - { - doc[dhcp] = zero; - if (doc["mask"] == "") - { - doc["mask"] = "255.255.255.0"; - } - if (doc["ip"] == "") - { - doc["ip"] = "192.168.0.1"; - } - if (doc["gw"] == "") - { - doc["gw"] = "192.168.0.1"; - } - } - // const char* disablePingCtrl = "disablePingCtrl"; - // if (serverWeb.arg(disablePingCtrl) == on) { - // doc[disablePingCtrl] = one; - // } else { - // doc[disablePingCtrl] = zero; - // } - configFile = LittleFS.open(configFileEther, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); + // const char* disablePingCtrl = "disablePingCtrl"; + // if (serverWeb.arg(disablePingCtrl) == on) { + // doc[disablePingCtrl] = one; + // } else { + // doc[disablePingCtrl] = zero; + // } + configFile = LittleFS.open(configFileEther, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + } + case API_PAGE_MQTT: + { + configFile = LittleFS.open(configFileMqtt, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + doc["server"] = serverWeb.arg("MqttServer"); + doc["port"] = serverWeb.arg("MqttPort"); + doc["user"] = serverWeb.arg("MqttUser"); + doc["pass"] = serverWeb.arg("MqttPass"); + doc["topic"] = serverWeb.arg("MqttTopic"); + doc["interval"] = serverWeb.arg("MqttInterval"); + + const char *enable = "enable"; + if (serverWeb.arg("MqttEnable") == "on") + { + doc[enable] = one; + } + else + { + doc[enable] = zero; } - case API_PAGE_MQTT: - { - configFile = LittleFS.open(configFileMqtt, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - doc["server"] = serverWeb.arg("MqttServer"); - doc["port"] = serverWeb.arg("MqttPort"); - doc["user"] = serverWeb.arg("MqttUser"); - doc["pass"] = serverWeb.arg("MqttPass"); - doc["topic"] = serverWeb.arg("MqttTopic"); - doc["interval"] = serverWeb.arg("MqttInterval"); - - const char *enable = "enable"; - if (serverWeb.arg("MqttEnable") == "on") - { - doc[enable] = one; - } - else - { - doc[enable] = zero; - } - const char *discovery = "discovery"; - if (serverWeb.arg("MqttDiscovery") == "on") - { - doc[discovery] = one; - } - else - { - doc[discovery] = zero; - } + const char *discovery = "discovery"; + if (serverWeb.arg("MqttDiscovery") == "on") + { + doc[discovery] = one; + } + else + { + doc[discovery] = zero; + } - // const char* disablePingCtrl = "disablePingCtrl"; - // if (serverWeb.arg(disablePingCtrl) == on) { - // doc[disablePingCtrl] = one; - // } else { - // doc[disablePingCtrl] = zero; - // } - configFile = LittleFS.open(configFileMqtt, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); - loadConfigMqtt(); + // const char* disablePingCtrl = "disablePingCtrl"; + // if (serverWeb.arg(disablePingCtrl) == on) { + // doc[disablePingCtrl] = one; + // } else { + // doc[disablePingCtrl] = zero; + // } + configFile = LittleFS.open(configFileMqtt, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + loadFileConfigMqtt(); + } + break; + case API_PAGE_VPN: + { + configFile = LittleFS.open(configFileWg, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + doc["localAddr"] = serverWeb.arg("WgLocalAddr"); + doc["localIP"] = serverWeb.arg("WgLocalPrivKey"); + doc["endAddr"] = serverWeb.arg("WgEndAddr"); + doc["endPubKey"] = serverWeb.arg("WgEndPubKey"); + doc["endPort"] = serverWeb.arg("WgEndPort"); + + const char *enable = "enable"; + if (serverWeb.arg("WgEnable") == "on") + { + doc[enable] = one; + } + else + { + doc[enable] = zero; } - break; - case API_PAGE_WG: - { - configFile = LittleFS.open(configFileWg, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - doc["localAddr"] = serverWeb.arg("WgLocalAddr"); - doc["localIP"] = serverWeb.arg("WgLocalPrivKey"); - doc["endAddr"] = serverWeb.arg("WgEndAddr"); - doc["endPubKey"] = serverWeb.arg("WgEndPubKey"); - doc["endPort"] = serverWeb.arg("WgEndPort"); - - const char *enable = "enable"; - if (serverWeb.arg("WgEnable") == "on") - { - doc[enable] = one; - } - else - { - doc[enable] = zero; - } - configFile = LittleFS.open(configFileWg, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); - loadConfigWg(); + configFile = LittleFS.open(configFileWg, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + loadFileConfigWg(); + } + break; + case API_PAGE_NETWORK: + { + configFile = LittleFS.open(configFileWifi, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + doc["ssid"] = serverWeb.arg("WIFISSID"); + doc["pass"] = serverWeb.arg("WIFIpassword"); + const char *dhcpWiFi = "dhcpWiFi"; + if (serverWeb.arg(dhcpWiFi) == on) + { + doc[dhcpWiFi] = 1; } - break; - case API_PAGE_WIFI: - { - configFile = LittleFS.open(configFileWifi, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - doc["ssid"] = serverWeb.arg("WIFISSID"); - doc["pass"] = serverWeb.arg("WIFIpassword"); - const char *dhcpWiFi = "dhcpWiFi"; - if (serverWeb.arg(dhcpWiFi) == on) - { - doc[dhcpWiFi] = 1; - } - else - { - doc[dhcpWiFi] = 0; - } - doc["ip"] = serverWeb.arg("ipAddress"); - doc["mask"] = serverWeb.arg("ipMask"); - doc["gw"] = serverWeb.arg("ipGW"); - configFile = LittleFS.open(configFileWifi, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); - WiFi.persistent(false); - if (ConfigSettings.apStarted) - { - WiFi.mode(WIFI_AP_STA); - } - else - { - WiFi.mode(WIFI_STA); - } - WiFi.begin(serverWeb.arg("WIFISSID").c_str(), serverWeb.arg("WIFIpassword").c_str()); + else + { + doc[dhcpWiFi] = 0; } - break; - case API_PAGE_ZHA_Z2M: + doc["ip"] = serverWeb.arg("ipAddress"); + doc["mask"] = serverWeb.arg("ipMask"); + doc["gw"] = serverWeb.arg("ipGW"); + configFile = LittleFS.open(configFileWifi, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + WiFi.persistent(false); + if (vars.apStarted) { - configFile = LittleFS.open(configFileSerial, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - const char *baud = "baud"; - if (serverWeb.hasArg(baud)) - { - doc[baud] = serverWeb.arg(baud); - } - else - { - doc[baud] = 115200; - } - const char *port = "port"; - if (serverWeb.hasArg(baud)) - { - doc[port] = serverWeb.arg(port); - } - else - { - doc[port] = 6638; - } - configFile = LittleFS.open(configFileSerial, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); + WiFi.mode(WIFI_AP_STA); } - break; - case API_PAGE_SECURITY: + else { - configFile = LittleFS.open(configFileSecurity, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - const char *disableWeb = "disableWeb"; - if (serverWeb.arg(disableWeb) == on) - { - doc[disableWeb] = 1; - } - else - { - doc[disableWeb] = 0; - } - const char *webAuth = "webAuth"; - if (serverWeb.arg(webAuth) == on) - { - doc[webAuth] = 1; - } - else - { - doc[webAuth] = 0; - } - const char *webUser = "webUser"; - if (serverWeb.arg(webUser) != "") - { - doc[webUser] = serverWeb.arg(webUser); - } - else - { - doc[webUser] = "admin"; - } - const char *fwEnabled = "fwEnabled"; - if (serverWeb.arg(fwEnabled) == on) - { - doc[fwEnabled] = 1; - } - else - { - doc[fwEnabled] = 0; - } - const char *fwIp = "fwIp"; - doc[fwIp] = serverWeb.arg(fwIp); - doc["webPass"] = serverWeb.arg("webPass"); - - configFile = LittleFS.open(configFileSecurity, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); + WiFi.mode(WIFI_STA); } - break; - case API_PAGE_SYSTOOLS: - { - const char *refreshLogs = "refreshLogs"; - const char *hostname = "hostname"; - configFile = LittleFS.open(configFileGeneral, FILE_READ); - deserializeJson(doc, configFile); - configFile.close(); - if (serverWeb.hasArg(refreshLogs)) - { - ConfigSettings.refreshLogs = serverWeb.arg(refreshLogs).toInt(); - doc[refreshLogs] = ConfigSettings.refreshLogs; - } - if (serverWeb.hasArg(hostname)) - { - doc[hostname] = serverWeb.arg(hostname); - strlcpy(ConfigSettings.hostname, serverWeb.arg(hostname).c_str(), sizeof(ConfigSettings.hostname)); - } - const char *timeZoneName = "timeZoneName"; - if (serverWeb.hasArg(timeZoneName)) - { - doc[timeZoneName] = serverWeb.arg(timeZoneName); - } - configFile = LittleFS.open(configFileGeneral, FILE_WRITE); - configFile = LittleFS.open(configFileGeneral, FILE_WRITE); - serializeJson(doc, configFile); - configFile.close(); + WiFi.begin(serverWeb.arg("WIFISSID").c_str(), serverWeb.arg("WIFIpassword").c_str()); + } + break; + case API_PAGE_ZIGBEE: + { + configFile = LittleFS.open(configFileSerial, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + const char *baud = "baud"; + if (serverWeb.hasArg(baud)) + { + doc[baud] = serverWeb.arg(baud); } - break; - - default: - break; + else + { + doc[baud] = 115200; + } + const char *port = "port"; + if (serverWeb.hasArg(baud)) + { + doc[port] = serverWeb.arg(port); + } + else + { + doc[port] = 6638; } - serverWeb.send(HTTP_CODE_OK, contTypeText, "ok"); + configFile = LittleFS.open(configFileSerial, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); } - else + break; + case API_PAGE_SECURITY: + { + configFile = LittleFS.open(configFileSecurity, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + const char *disableWeb = "disableWeb"; + if (serverWeb.arg(disableWeb) == on) + { + doc[disableWeb] = 1; + } + else + { + doc[disableWeb] = 0; + } + const char *webAuth = "webAuth"; + if (serverWeb.arg(webAuth) == on) + { + doc[webAuth] = 1; + } + else + { + doc[webAuth] = 0; + } + const char *webUser = "webUser"; + if (serverWeb.arg(webUser) != "") + { + doc[webUser] = serverWeb.arg(webUser); + } + else + { + doc[webUser] = "admin"; + } + const char *fwEnabled = "fwEnabled"; + if (serverWeb.arg(fwEnabled) == on) + { + doc[fwEnabled] = 1; + } + else + { + doc[fwEnabled] = 0; + } + const char *fwIp = "fwIp"; + doc[fwIp] = serverWeb.arg(fwIp); + doc["webPass"] = serverWeb.arg("webPass"); + + configFile = LittleFS.open(configFileSecurity, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + } + break; + case API_PAGE_TOOLS: { - serverWeb.send(500, contTypeText, "bad args"); + const char *refreshLogs = "refreshLogs"; + const char *hostname = "hostname"; + configFile = LittleFS.open(configFileGeneral, FILE_READ); + deserializeJson(doc, configFile); + configFile.close(); + if (serverWeb.hasArg(refreshLogs)) + { + systemCfg.refreshLogs = serverWeb.arg(refreshLogs).toInt(); + doc[refreshLogs] = systemCfg.refreshLogs; + } + if (serverWeb.hasArg(hostname)) + { + doc[hostname] = serverWeb.arg(hostname); + strlcpy(systemCfg.hostname, serverWeb.arg(hostname).c_str(), sizeof(systemCfg.hostname)); + } + const char *timeZoneName = "timeZoneName"; + if (serverWeb.hasArg(timeZoneName)) + { + doc[timeZoneName] = serverWeb.arg(timeZoneName); + } + configFile = LittleFS.open(configFileGeneral, FILE_WRITE); + //configFile = LittleFS.open(configFileGeneral, FILE_WRITE); + serializeJson(doc, configFile); + configFile.close(); + } + break; + + default: + break; } + serverWeb.send(HTTP_CODE_OK, contTypeText, "ok"); } +else +{ + serverWeb.send(500, contTypeText, "bad args"); +} +}*/ bool checkAuth() { - if (!ConfigSettings.webAuth) + if (!systemCfg.webAuth) return true; const char *www_realm = "Login Required"; - if (!serverWeb.authenticate(ConfigSettings.webUser, ConfigSettings.webPass)) + if (!serverWeb.authenticate(systemCfg.webUser, systemCfg.webPass)) { serverWeb.requestAuthentication(DIGEST_AUTH, www_realm, "Authentication failed"); return false; @@ -1140,79 +1172,128 @@ void handleGeneral() // doc["pageName"] = "General"; // DEBUG_PRINTLN(ConfigSettings.usbMode); - switch (ConfigSettings.coordinator_mode) + switch (vars.workMode) { - case COORDINATOR_MODE_USB: + case WORK_MODE_USB: doc["checkedUsbMode"] = checked; break; - case COORDINATOR_MODE_WIFI: + /*case COORDINATOR_MODE_WIFI: doc["checkedWifiMode"] = checked; - break; - case COORDINATOR_MODE_LAN: + break;*/ + case WORK_MODE_NETWORK: doc["checkedLanMode"] = checked; break; default: break; } - // DEBUG_PRINTLN(ConfigSettings.disableLedPwr); - if (ConfigSettings.keepWeb) + // DEBUG_PRINTLN(systemCfg.disableLedPwr); + if (systemCfg.keepWeb) { doc["keepWeb"] = checked; } - if (ConfigSettings.disableLedPwr) + if (systemCfg.disableLedPwr) { doc["checkedDisableLedPwr"] = checked; } - // DEBUG_PRINTLN(ConfigSettings.disableLedUSB); - if (ConfigSettings.disableLedUSB) + // DEBUG_PRINTLN(systemCfg.disableLedUSB); + if (systemCfg.disableLedUSB) { doc["checkedDisableLedUSB"] = checked; } + // serializeJson(doc, result); + // serverWeb.sendHeader(respHeaderName, result); + + // String result; + // DynamicJsonDocument doc(512); + + doc["hostname"] = systemCfg.hostname; + doc["refreshLogs"] = systemCfg.refreshLogs; + if (systemCfg.timeZone) + { + doc["timeZoneName"] = systemCfg.timeZone; + } + doc["ntpServ1"] = systemCfg.ntpServ1; //.toString(); + doc["ntpServ2"] = systemCfg.ntpServ2; //.toString(); + serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); + + DynamicJsonDocument zones(10240); + String results; + + JsonArray zonesArray = zones.to(); + for (int i = 0; i < timeZoneCount; i++) + { + zonesArray.add(timeZones[i].zone); + } + + serializeJson(zones, results); + serverWeb.sendHeader(respTimeZonesName, results); } void handleSecurity() { String result; DynamicJsonDocument doc(1024); - if (ConfigSettings.disableWeb) + if (systemCfg.disableWeb) { doc["disableWeb"] = checked; } - if (ConfigSettings.webAuth) + if (systemCfg.webAuth) { doc["webAuth"] = checked; } - doc["webUser"] = (String)ConfigSettings.webUser; - doc["webPass"] = (String)ConfigSettings.webPass; - if (ConfigSettings.fwEnabled) + doc["webUser"] = (String)systemCfg.webUser; + doc["webPass"] = (String)systemCfg.webPass; + if (systemCfg.fwEnabled) { doc["fwEnabled"] = checked; } - doc["fwIp"] = ConfigSettings.fwIp.toString(); + doc["fwIp"] = systemCfg.fwIp; //.toString(); serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); } -void handleWifi() +void handleNetwork() { String result; DynamicJsonDocument doc(1024); // doc["pageName"] = "Config WiFi"; - doc["ssid"] = String(ConfigSettings.ssid); - doc["passWifi"] = String(ConfigSettings.password); - if (ConfigSettings.dhcpWiFi) + + if (networkCfg.ethEnable) + { + doc["ethEnbl"] = checked; + } + if (networkCfg.ethDhcp) + { + doc["modeEther"] = checked; + } + doc["ipEther"] = networkCfg.ethAddr; + doc["maskEther"] = networkCfg.ethMask; + doc["GWEther"] = networkCfg.ethGate; + + doc["ethDns1"] = networkCfg.ethDns1; + doc["ethDns2"] = networkCfg.ethDns2; + + if (networkCfg.wifiEnable) + { + doc["wifiEnbl"] = checked; + } + doc["ssid"] = String(networkCfg.wifiSsid); + doc["passWifi"] = String(networkCfg.wifiPassword); + if (networkCfg.wifiDhcp) { doc["dchp"] = checked; } - doc["ip"] = ConfigSettings.ipAddressWiFi; - doc["mask"] = ConfigSettings.ipMaskWiFi; - doc["gw"] = ConfigSettings.ipGWWiFi; + doc["ip"] = networkCfg.wifiAddr; + doc["mask"] = networkCfg.wifiMask; + doc["gw"] = networkCfg.wifiGate; + doc["wifiDns1"] = networkCfg.wifiDns1; + doc["wifiDns2"] = networkCfg.wifiDns2; serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); @@ -1223,23 +1304,23 @@ void handleSerial() String result; DynamicJsonDocument doc(1024); - if (ConfigSettings.serialSpeed == 9600) + if (systemCfg.serialSpeed == 9600) { doc["9600"] = checked; } - else if (ConfigSettings.serialSpeed == 19200) + else if (systemCfg.serialSpeed == 19200) { doc["19200"] = checked; } - else if (ConfigSettings.serialSpeed == 38400) + else if (systemCfg.serialSpeed == 38400) { doc["8400"] = checked; } - else if (ConfigSettings.serialSpeed == 57600) + else if (systemCfg.serialSpeed == 57600) { doc["57600"] = checked; } - else if (ConfigSettings.serialSpeed == 115200) + else if (systemCfg.serialSpeed == 115200) { doc["115200"] = checked; } @@ -1247,7 +1328,7 @@ void handleSerial() { doc["115200"] = checked; } - doc["socketPort"] = String(ConfigSettings.socketPort); + doc["socketPort"] = String(systemCfg.socketPort); serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); @@ -1255,18 +1336,19 @@ void handleSerial() void handleEther() { + /* String result; DynamicJsonDocument doc(1024); // doc["pageName"] = "Config Ethernet"; - if (ConfigSettings.dhcp) + if (networkCfg.ethDhcp) { doc["modeEther"] = checked; } - doc["ipEther"] = ConfigSettings.ipAddress; - doc["maskEther"] = ConfigSettings.ipMask; - doc["GWEther"] = ConfigSettings.ipGW; + doc["ipEther"] = networkCfg.ethAddr; + doc["maskEther"] = networkCfg.ethMask; + doc["GWEther"] = networkCfg.ethGate; // if (ConfigSettings.disablePingCtrl) { // doc["disablePingCtrl"] = checked; @@ -1274,6 +1356,7 @@ void handleEther() serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); + */ } void handleMqtt() @@ -1281,18 +1364,18 @@ void handleMqtt() String result; DynamicJsonDocument doc(1024); - if (MqttSettings.enable) + if (mqttCfg.enable) { doc["enableMqtt"] = checked; } - doc["serverMqtt"] = MqttSettings.server; - doc["portMqtt"] = MqttSettings.port; - doc["userMqtt"] = MqttSettings.user; - doc["passMqtt"] = MqttSettings.pass; - doc["topicMqtt"] = MqttSettings.topic; - doc["intervalMqtt"] = MqttSettings.interval; - - if (MqttSettings.discovery) + doc["serverMqtt"] = mqttCfg.server; + doc["portMqtt"] = mqttCfg.port; + doc["userMqtt"] = mqttCfg.user; + doc["passMqtt"] = mqttCfg.pass; + doc["topicMqtt"] = mqttCfg.topic; + doc["intervalMqtt"] = mqttCfg.updateInt; + + if (mqttCfg.discovery) { doc["discoveryMqtt"] = checked; } @@ -1301,20 +1384,28 @@ void handleMqtt() serverWeb.sendHeader(respHeaderName, result); } -void handleWg() +void handleVpn() { String result; DynamicJsonDocument doc(1024); - if (WgSettings.enable) + if (vpnCfg.wgEnable) { doc["enableWg"] = checked; } - doc["localAddrWg"] = WgSettings.localAddr; - doc["localPrivKeyWg"] = WgSettings.localPrivKey; - doc["endAddrWg"] = WgSettings.endAddr; - doc["endPubKeyWg"] = WgSettings.endPubKey; - doc["endPortWg"] = WgSettings.endPort; + doc["localAddrWg"] = vpnCfg.wgLocalIP.toString(); /// WgSettings.localAddr; + doc["localPrivKeyWg"] = vpnCfg.wgLocalPrivKey; + doc["endAddrWg"] = vpnCfg.wgEndAddr; + doc["endPubKeyWg"] = vpnCfg.wgEndPubKey; + doc["endPortWg"] = vpnCfg.wgEndPort; + + if (vpnCfg.hnEnable) + { + doc["enableHn"] = checked; + } + doc["joinCodeHn"] = vpnCfg.hnJoinCode; + doc["hostNameHn"] = vpnCfg.hnHostName; + doc["dashUrlHn"] = vpnCfg.hnDashUrl; serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); @@ -1332,7 +1423,7 @@ DynamicJsonDocument getRootData() doc["VERSION"] = String(verArr); String readableTime; - getReadableTime(readableTime, ConfigSettings.socketTime); + getReadableTime(readableTime, vars.socketTime); const char *connectedSocketStatus = "connectedSocketStatus"; const char *connectedSocket = "connectedSocket"; const char *notConnected = "Not connected"; @@ -1341,16 +1432,16 @@ DynamicJsonDocument getRootData() const char *on = "On"; const char *off = "Off"; - if (ConfigSettings.connectedClients > 0) + if (vars.connectedClients > 0) { - if (ConfigSettings.connectedClients > 1) + if (vars.connectedClients > 1) { - doc[connectedSocketStatus] = "Yes, " + String(ConfigSettings.connectedClients) + "connection"; + doc[connectedSocketStatus] = "Yes, " + String(vars.connectedClients) + "connection"; doc[connectedSocket] = readableTime; } else { - doc[connectedSocketStatus] = "Yes, " + String(ConfigSettings.connectedClients) + " connections"; + doc[connectedSocketStatus] = "Yes, " + String(vars.connectedClients) + " connections"; doc[connectedSocket] = readableTime; } } @@ -1360,16 +1451,16 @@ DynamicJsonDocument getRootData() doc[connectedSocket] = notConnected; } const char *operationalMode = "operationalMode"; - switch (ConfigSettings.coordinator_mode) + switch (vars.workMode) { - case COORDINATOR_MODE_USB: + case WORK_MODE_USB: doc[operationalMode] = "Zigbee-to-USB"; break; - case COORDINATOR_MODE_WIFI: + /*case COORDINATOR_MODE_WIFI: doc[operationalMode] = "Zigbee-to-WiFi"; - break; - case COORDINATOR_MODE_LAN: - doc[operationalMode] = "Zigbee-to-Ethernet"; + break;*/ + case WORK_MODE_NETWORK: + doc[operationalMode] = "Zigbee-to-Network"; break; default: @@ -1378,14 +1469,8 @@ DynamicJsonDocument getRootData() // ETHERNET TAB const char *ethDhcp = "ethDhcp"; - if (ConfigSettings.dhcp) - { - doc[ethDhcp] = on; - } - else - { - doc[ethDhcp] = off; - } + + doc[ethDhcp] = networkCfg.ethDhcp ? on : off; const char *connectedEther = "connectedEther"; const char *ethConnection = "ethConnection"; @@ -1394,25 +1479,32 @@ DynamicJsonDocument getRootData() const char *ethIp = "ethIp"; const char *etchMask = "etchMask"; const char *ethGate = "ethGate"; - if (ConfigSettings.connectedEther) + const char *ethDns = "ethDns"; + // + if (networkCfg.ethEnable) { - doc[connectedEther] = yes; - doc[ethConnection] = "Connected"; - doc[ethMac] = ETH.macAddress(); - doc[ethSpd] = String(ETH.linkSpeed()) + String(" Mbps"); - doc[ethIp] = ETH.localIP().toString(); - doc[etchMask] = ETH.subnetMask().toString(); - doc[ethGate] = ETH.gatewayIP().toString(); - } - else - { - doc[connectedEther] = no; - doc[ethConnection] = notConnected; - doc[ethMac] = notConnected; - doc[ethSpd] = notConnected; - doc[ethIp] = notConnected; - doc[etchMask] = notConnected; - doc[ethGate] = notConnected; + if (vars.connectedEther) + { + + doc[connectedEther] = yes; + doc[ethConnection] = "Connected"; + doc[ethMac] = ETH.macAddress(); + doc[ethSpd] = String(ETH.linkSpeed()) + String(" Mbps"); + doc[ethIp] = ETH.localIP().toString(); + doc[etchMask] = ETH.subnetMask().toString(); + doc[ethGate] = ETH.gatewayIP().toString(); + doc[ethDns] = ETH.dnsIP().toString(); + } + else + { + doc[connectedEther] = no; + doc[ethConnection] = notConnected; + doc[ethMac] = notConnected; + doc[ethSpd] = notConnected; + doc[ethIp] = notConnected; + doc[etchMask] = notConnected; + doc[ethGate] = notConnected; + } } getReadableTime(readableTime, 0); @@ -1457,6 +1549,7 @@ DynamicJsonDocument getRootData() } doc["espFlashSize"] = String(ESP.getFlashChipSize() / (1024 * 1024)); + // wifi const char *wifiSsid = "wifiSsid"; const char *wifiRssi = "wifiRssi"; @@ -1469,10 +1562,13 @@ DynamicJsonDocument getRootData() const char *wifiModeAPStatus = "wifiModeAPStatus"; const char *wifiModeAP = "wifiModeAP"; const char *wifiDhcp = "wifiDhcp"; + const char *wifiDns = "wifiDns"; + doc["wifiMac"] = String(WiFi.macAddress().c_str()); - if (ConfigSettings.coordinator_mode == COORDINATOR_MODE_WIFI) + // if (vars.workMode == WORK_MODE_NETWORK) + if (networkCfg.wifiEnable) { - doc[wifiEnabled] = yes; + // doc[wifiEnabled] = yes; doc[wifiMode] = "Client"; if (WiFi.status() == WL_CONNECTED) { // STA connected @@ -1483,27 +1579,21 @@ DynamicJsonDocument getRootData() doc[wifiIp] = WiFi.localIP().toString(); doc[wifiMask] = WiFi.subnetMask().toString(); doc[wifiGate] = WiFi.gatewayIP().toString(); + doc[wifiDns] = WiFi.dnsIP().toString(); } else { const char *connecting = "Connecting..."; - doc["wifiSsid"] = ConfigSettings.ssid; + doc["wifiSsid"] = networkCfg.wifiSsid; doc[wifiRssi] = connecting; doc[wifiConnected] = connecting; - doc[wifiIp] = ConfigSettings.dhcpWiFi ? WiFi.localIP().toString() : connecting; - doc[wifiMask] = ConfigSettings.dhcpWiFi ? WiFi.subnetMask().toString() : connecting; - doc[wifiGate] = ConfigSettings.dhcpWiFi ? WiFi.gatewayIP().toString() : connecting; - } - if (ConfigSettings.dhcpWiFi) - { - doc[wifiDhcp] = on; - } - else - { - doc[wifiDhcp] = off; + doc[wifiIp] = networkCfg.wifiDhcp ? WiFi.localIP().toString() : connecting; + doc[wifiMask] = networkCfg.wifiDhcp ? WiFi.subnetMask().toString() : connecting; + doc[wifiGate] = networkCfg.wifiDhcp ? WiFi.gatewayIP().toString() : connecting; } + doc[wifiDhcp] = networkCfg.wifiDhcp ? on : off; } - else + /*else { doc[wifiEnabled] = no; doc[wifiConnected] = notConnected; @@ -1514,16 +1604,16 @@ DynamicJsonDocument getRootData() doc[wifiGate] = off; doc[wifiRssi] = off; doc[wifiDhcp] = off; - } - if (ConfigSettings.apStarted) + }*/ + if (vars.apStarted) { // AP active String AP_NameString; - char apSsid[18]; + char apSsid[MAX_DEV_ID_LONG]; getDeviceID(apSsid); - char wifiSsidBuf[35]; + char wifiSsidBuf[MAX_DEV_ID_LONG + 25]; sprintf(wifiSsidBuf, "%s (no password)", apSsid); doc[wifiSsid] = wifiSsidBuf; - doc[wifiIp] = "192.168.1.1 (UZG-01 web interface)"; + doc[wifiIp] = "192.168.1.1 (XZG web interface)"; doc[wifiMask] = "255.255.255.0 (Access point)"; doc[wifiGate] = "192.168.1.1 (this device)"; doc[wifiDhcp] = "On (Access point)"; @@ -1540,14 +1630,14 @@ DynamicJsonDocument getRootData() } // MQTT - if (MqttSettings.enable) + if (mqttCfg.enable) { const char *mqConnect = "mqConnect"; const char *mqBroker = "mqBroker"; - doc[mqBroker] = MqttSettings.server; + doc[mqBroker] = mqttCfg.server; - if (MqttSettings.connect) + if (vars.mqttConn) { doc[mqConnect] = yes; } @@ -1557,23 +1647,41 @@ DynamicJsonDocument getRootData() } } - // VPN - if (WgSettings.enable) + // VPN WireGuard + if (vpnCfg.wgEnable) { const char *wgInit = "wgInit"; const char *wgDeviceAddr = "wgDeviceAddr"; const char *wgRemoteAddr = "wgRemoteAddr"; + const char *wgConnect = "wgConnect"; + const char *wgRemoteIP = "wgRemoteIp"; + // const char *wgEndPort = "wgEndPort"; - doc[wgDeviceAddr] = WgSettings.localAddr; - doc[wgRemoteAddr] = WgSettings.endAddr; + doc[wgInit] = vars.vpnWgInit ? yes : no; + doc[wgDeviceAddr] = vpnCfg.wgLocalIP.toString(); + doc[wgRemoteAddr] = vpnCfg.wgEndAddr; + // doc[wgEndPort] = vpnCfg.wgEndPort; + + doc[wgConnect] = vars.vpnWgConnect ? yes : no; + + doc[wgRemoteIP] = vars.vpnWgPeerIp.toString(); + } + // VPN Husarnet + if (vpnCfg.hnEnable) + { + const char *hnInit = "hnInit"; + const char *hnHostName = "hnHostName"; - if (WgSettings.init) + // doc[wgDeviceAddr] = vpnCfg.wgLocalIP.toString();//WgSettings.localAddr; + doc[hnHostName] = vpnCfg.hnHostName; + + if (vars.vpnHnInit) { - doc[wgInit] = yes; + doc[hnInit] = yes; } else { - doc[wgInit] = no; + doc[hnInit] = no; } } @@ -1595,7 +1703,7 @@ void handleStatus() DynamicJsonDocument doc(1024); // Authentication is needed for status page as well (if enabled) - if (ConfigSettings.webAuth) + if (systemCfg.webAuth) { if (!checkAuth()) { @@ -1616,29 +1724,31 @@ void handleStatus() void handleSysTools() { + String result; DynamicJsonDocument doc(512); - doc["hostname"] = ConfigSettings.hostname; - doc["refreshLogs"] = ConfigSettings.refreshLogs; - if (ConfigSettings.timeZone) - { - doc["timeZoneName"] = ConfigSettings.timeZone; - } + // doc["hostname"] = systemCfg.hostname; + doc["refreshLogs"] = systemCfg.refreshLogs; + // if (systemCfg.timeZone) + //{ + // doc["timeZoneName"] = systemCfg.timeZone; + // } serializeJson(doc, result); serverWeb.sendHeader(respHeaderName, result); + /* + DynamicJsonDocument zones(10240); + String results; - DynamicJsonDocument zones(10240); - String results; - - JsonArray zonesArray = zones.to(); - for (int i = 0; i < timeZoneCount; i++) - { - zonesArray.add(timeZones[i].zone); - } + JsonArray zonesArray = zones.to(); + for (int i = 0; i < timeZoneCount; i++) + { + zonesArray.add(timeZones[i].zone); + } - serializeJson(zones, results); - serverWeb.sendHeader(respTimeZonesName, results); + serializeJson(zones, results); + serverWeb.sendHeader(respTimeZonesName, results); + */ } void handleSavefile() @@ -1673,7 +1783,7 @@ void handleSavefile() } file.close(); - serverWeb.sendHeader(F("Location"), F("/sys-tools")); + serverWeb.sendHeader(F("Location"), F("/tools")); serverWeb.send(303); } } diff --git a/src/web.h b/src/web.h index 9c81d46..d4cfb27 100644 --- a/src/web.h +++ b/src/web.h @@ -5,10 +5,10 @@ void webServerHandleClient(); void handleGeneral(); void handleSecurity(); void handleRoot(); -void handleWifi(); +void handleNetwork(); void handleEther(); void handleMqtt(); -void handleWg(); +void handleVpn(); void handleZigbeeBSL(); void handleZigbeeRestart(); void handleSerial(); @@ -21,6 +21,7 @@ void printLogTime(); void printLogMsg(String msg); void handleSaveParams(); bool checkAuth(); +DynamicJsonDocument getRootData(); void sendEvent(const char *event, const uint8_t evsz, const String data); void progressFunc(unsigned int progress, unsigned int total); @@ -28,4 +29,5 @@ void progressFunc(unsigned int progress, unsigned int total); void getEspUpdate(String esp_fw_url); void runEspUpdateFirmware(uint8_t *data, size_t len); -#define UPD_FILE "https://github.com/mercenaruss/uzg-firmware/releases/latest/download/UZG-01.bin" \ No newline at end of file + +#define UPD_FILE "https://github.com/mercenaruss/uzg-firmware/releases/latest/download/XZG.bin" \ No newline at end of file diff --git a/src/websrc/css/custom.css b/src/websrc/css/custom.css index 87be232..c35cf8b 100644 --- a/src/websrc/css/custom.css +++ b/src/websrc/css/custom.css @@ -12,7 +12,7 @@ label.swFx { } /* Preloader */ -.uzg-loader { +.xzg-loader { width: 100px; height: 100px; border-radius: 50%; @@ -27,7 +27,7 @@ label.swFx { } } -#uzPreloader { +#xzgPreloader { position: absolute; left: calc(50% - 50px); top: calc(50% - 50px); @@ -57,7 +57,12 @@ label.swFx { position: fixed; left: -250px; transition: all 0.3s ease-out; - top: -1px !important; + /*top: -1px !important;*/ + } + + .nav-link { + justify-content: center !important; + display: flex !important; } nav.navbar { @@ -65,11 +70,22 @@ label.swFx { z-index: 99; } - #pagenamePC { + /*#pagenamePC { display: none; + }*/ +} + +@media (min-width: 767px) { + .navbar-toggler-icon { + display: none !important; } } +.navbar>.container { + width: 100% !important; + max-width: 100% !important; +} + .sidenav-active { left: -1px !important; transition: all 0.6s ease-out; @@ -229,6 +245,16 @@ div#main { white-space: normal !important; } +.nav-link { + padding: 0.5rem 0.5rem !important; +} + +.nav-item { + padding-left: 0px !important; + padding-right: 0px !important; + /*min-width: 125px !important;*/ +} + .card { background-color: var(--card-background-color) !important; } @@ -240,6 +266,7 @@ div#main { body { color: var(--text-color) !important; background-color: var(--background-color) !important; + margin: -1 !important; } .table { @@ -250,6 +277,45 @@ body { background-color: var(--form-disabled-background-color) !important; } +.switches-container { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 20px; +} + +.card_icon { + width: 16px; + height: 16px; + fill: currentColor; + margin-right: 6px; +} + +.status_icon { + width: 22px; + height: 22px; + fill: currentColor; + margin-right: 10px; + color: black; + border-radius: 5px; +} + +.card-header { + display: flex !important; + align-items: center !important; + justify-content: start !important; +} + +.fixed-bottom { + text-align: right; + margin-bottom: 0; + font-weight: 100; + font-size: 80%; + margin-right: 6px; + display: none; +} + + /*========== Variables Light theme (default) ==========*/ :root { --background-color: #ffffff; @@ -318,6 +384,12 @@ body { transform: translateX(24px); } +.bi { + width: 15px; + height: 15px; + fill: currentColor; +} + .bi-moon { color: #f1c40f; } diff --git a/src/websrc/css/style.css b/src/websrc/css/style.css index 6fa796d..a9eec65 100644 --- a/src/websrc/css/style.css +++ b/src/websrc/css/style.css @@ -1,4 +1,4 @@ -@charset "UTF-8";input.swFx{border:1px solid rgba(0,0,0,.25)!important}input.swFx:checked{background-color:#303fa1!important;border-color:#303fa1!important}label.swFx{color:#000!important}.uzg-loader{width:100px;height:100px;border-radius:50%;border:16px solid;border-color:#047cc3 #0000;animation:a .5s infinite}@keyframes a{to{transform:rotate(.5turn)}}#uzPreloader{position:absolute;left:calc(50% - 50px);top:calc(50% - 50px);z-index:8;width:100px;height:100px}.card-disabled{opacity:.5;cursor:not-allowed}.card-disabled>*{pointer-events:none}@media (min-width:576px){.nav{padding-left:8px}}@media (max-width:767px){.nav-container{position:fixed;left:-250px;transition:all .3s ease-out;top:-1px!important}nav.navbar{display:flex!important;z-index:6}#pagenamePC{display:none}}.sidenav-active{left:-1px!important;transition:all .6s ease-out}.toast{z-index:7;margin-right:20px}.nav-container{min-width:fit-content;z-index:7}.nav-shadow{box-shadow:5px 0 7px 0 rgba(0,0,0,.53)}.nav{width:100%;white-space:nowrap}.logo-wrapper{padding-left:8px;padding-right:8px;margin-bottom:10px}.logo-wrapper span{padding-left:6px;vertical-align:middle}.app-main-content{padding-top:0}.cardPadding{padding-bottom:20px}.nav-active{background-color:#0000003d}.nav-item span{vertical-align:inherit}.nav-item{width:100%;padding-left:8px;padding-right:8px}.nav-item a{border-bottom:1px solid #fff!important;border-radius:0!important}.nav-item:last-child a{border-bottom:none!important}#file-input,#file-input_zb{padding:0;border:1px solid #ddd;line-height:44px;text-align:center;display:block;cursor:pointer;width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px}#bar,#bar_zb,#prgbar,#prgbar_zb{background-color:#f1f1f1;border-radius:10px}#bar,#bar_zb{background-color:#17a2b8;width:0;height:10px}form#upload_form,form#upload_form_zb{background:#fff;max-width:408px;border-radius:5px;text-align:center}h2{text-align:center}div#update_info{max-width:55%;margin:auto;margin-bottom:25px}div#main{margin-left:auto;margin-right:auto}.bg-top{background-color:var(--link-color)!important}.nav{--bs-nav-link-color:var(--link-color)!important;--bs-nav-link-hover-color:var(--link-hover-color)!important;white-space:normal!important}.card{background-color:var(--card-background-color)!important}.modal-content{background-color:var(--modal-background-color)!important}body{color:var(--text-color)!important;background-color:var(--background-color)!important}.table{color:var(--table-text-color)!important}.form-control:disabled{background-color:var(--form-disabled-background-color)!important}:root{--background-color:#fff;--text-color:#000;--card-background-color:#f0f0f0;--table-text-color:var(--bs-table-color);--modal-background-color:var(--bs-modal-bg);--form-disabled-background-color:#e9ecef;--link-color:#047cc3;--link-hover-color:#04d5ec}.dark-theme{--background-color:#121212;--text-color:#686868;--card-background-color:#1e1e1e;--table-text-color:#9c9c9c;--modal-background-color:#212529;--form-disabled-background-color:#303030;--link-color:#ff9200;--link-hover-color:#ffc33c}.checkbox{display:none}.switch-container{justify-content:center;height:50px;width:100%}.switch,.switch-container{display:flex;align-items:center}.switch{background-color:#111;border-radius:50px;cursor:pointer;justify-content:space-between;padding:5px;position:relative;height:26px;width:50px;transform:scale(1.2)}.switch .ball{background-color:#fff;border-radius:50%;position:absolute;top:2px;left:2px;height:22px;width:22px;transform:translateX(0);transition:transform .2s linear}.checkbox:checked+.switch .ball{transform:translateX(24px)}.bi-moon{color:#f1c40f}.bi-sun{color:#f39c12} +@charset "UTF-8";input.swFx{border:1px solid rgba(0,0,0,.25)!important}input.swFx:checked{background-color:#303fa1!important;border-color:#303fa1!important}label.swFx{color:#000!important}.xzg-loader{width:100px;height:100px;border-radius:50%;border:16px solid;border-color:#047cc3 #0000;animation:a .5s infinite}@keyframes a{to{transform:rotate(.5turn)}}#xzgPreloader{position:absolute;left:calc(50% - 50px);top:calc(50% - 50px);z-index:8;width:100px;height:100px}.card-disabled{opacity:.5;cursor:not-allowed}.card-disabled>*{pointer-events:none}@media (min-width:576px){.nav{padding-left:8px}}@media (max-width:767px){.nav-container{position:fixed;left:-250px;transition:all .3s ease-out}.nav-link{justify-content:center!important}.nav-link,nav.navbar{display:flex!important}nav.navbar{z-index:6}}@media (min-width:767px){.navbar-toggler-icon{display:none!important}}.navbar>.container{width:100%!important;max-width:100%!important}.sidenav-active{left:-1px!important;transition:all .6s ease-out}.toast{z-index:7;margin-right:20px}.nav-container{min-width:fit-content;z-index:7}.nav-shadow{box-shadow:5px 0 7px 0 rgba(0,0,0,.53)}.nav{width:100%;white-space:nowrap}.logo-wrapper{padding-left:8px;padding-right:8px;margin-bottom:10px}.logo-wrapper span{padding-left:6px;vertical-align:middle}.app-main-content{padding-top:0}.cardPadding{padding-bottom:20px}.nav-active{background-color:#0000003d}.nav-item span{vertical-align:inherit}.nav-item{width:100%;padding-left:8px;padding-right:8px}.nav-item a{border-bottom:1px solid #fff!important;border-radius:0!important}.nav-item:last-child a{border-bottom:none!important}#file-input,#file-input_zb{padding:0;border:1px solid #ddd;line-height:44px;text-align:center;display:block;cursor:pointer;width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px}#bar,#bar_zb,#prgbar,#prgbar_zb{background-color:#f1f1f1;border-radius:10px}#bar,#bar_zb{background-color:#17a2b8;width:0;height:10px}form#upload_form,form#upload_form_zb{background:#fff;max-width:408px;border-radius:5px;text-align:center}h2{text-align:center}div#update_info{max-width:55%;margin:auto;margin-bottom:25px}div#main{margin-left:auto;margin-right:auto}.bg-top{background-color:var(--link-color)!important}.nav{--bs-nav-link-color:var(--link-color)!important;--bs-nav-link-hover-color:var(--link-hover-color)!important;white-space:normal!important}.nav-link{padding:.5rem!important}.nav-item{padding-left:0!important;padding-right:0!important}.card{background-color:var(--card-background-color)!important}.modal-content{background-color:var(--modal-background-color)!important}body{color:var(--text-color)!important;background-color:var(--background-color)!important;margin:-1!important}.table{color:var(--table-text-color)!important}.form-control:disabled{background-color:var(--form-disabled-background-color)!important}.switches-container{display:flex;align-items:center;justify-content:flex-start;gap:20px}.card_icon{width:16px;height:16px;fill:currentColor;margin-right:6px}.status_icon{width:22px;height:22px;fill:currentColor;margin-right:10px;color:#000;border-radius:5px}.card-header{display:flex!important;align-items:center!important;justify-content:start!important}.fixed-bottom{text-align:right;margin-bottom:0;font-weight:100;font-size:80%;margin-right:6px;display:none}:root{--background-color:#fff;--text-color:#000;--card-background-color:#f0f0f0;--table-text-color:var(--bs-table-color);--modal-background-color:var(--bs-modal-bg);--form-disabled-background-color:#e9ecef;--link-color:#047cc3;--link-hover-color:#04d5ec}.dark-theme{--background-color:#121212;--text-color:#686868;--card-background-color:#1e1e1e;--table-text-color:#9c9c9c;--modal-background-color:#212529;--form-disabled-background-color:#303030;--link-color:#ff9200;--link-hover-color:#ffc33c}.checkbox{display:none}.switch-container{justify-content:center;height:50px;width:100%}.switch,.switch-container{display:flex;align-items:center}.switch{background-color:#111;border-radius:50px;cursor:pointer;justify-content:space-between;padding:5px;position:relative;height:26px;width:50px;transform:scale(1.2)}.switch .ball{background-color:#fff;border-radius:50%;position:absolute;top:2px;left:2px;height:22px;width:22px;transform:translateX(0);transition:transform .2s linear}.checkbox:checked+.switch .ball{transform:translateX(24px)}.bi{width:15px;height:15px;fill:currentColor}.bi-moon{color:#f1c40f}.bi-sun{color:#f39c12} /*! * Bootstrap v5.2.3 (https://getbootstrap.com/) diff --git a/src/websrc/html/PAGE_ABOUT.html b/src/websrc/html/PAGE_ABOUT.html index acc7be7..1ef38ea 100644 --- a/src/websrc/html/PAGE_ABOUT.html +++ b/src/websrc/html/PAGE_ABOUT.html @@ -1,31 +1,118 @@ -
+
-
- - - Official website with documentation - - - Download the latest stable version of ZigStar UZG-01 firmware - - - Report bug or feature request - - - Open a ticket - - - About us +
+
+

XZG logo

+

XZG firmware unifies the best innovations from
+ previous Zigbee gateway projects into a single, comprehensive solution.

+

By channeling the community's efforts into improving + one product, XZG aims to streamline development, enhancing the capabilities and efficiency of smart + home and IoT integrations.

+
+ +
+ +
+
+

Get in Touch

+

To learn more about the XZG firmware project visit + + + official Wiki. +

Your insights, feedback, and collaboration are invaluable as we work together to advance the state of + smart home technology.

+

+ + + Join community +

+

+
+ + + + +
+ +
+ +
+
+

Contribute

+

We invite you to join our mission to continuously refine and expand the XZG firmware. +

Whether through coding, bug reporting, or enhancing documentation, your contributions are crucial. +

+

Engage with us on the + + repository to contribute to this collaborative effort. +

+

+ + + Report a bug or request a feature +

+

+
+
+ +
+ +
+
+

Developer

+

This project is the fruition of a dedicated developer's passion for maximizing the + potential of open-source technology and IoT solutions. +

Crafted during spare hours, XZG is a testament to the power of community-driven innovation, bringing + together the most effective and proven solutions.

+

+
+
+ +
+ +
+
+

Support

+

Your support is vital for the ongoing development and sustainability of XZG. +

Financial contributions can be made through + + Sponsors, + + PayPal, or + + Buy Me a Coffee. +

If you're interested in helping in other ways or have suggestions, + please don't hesitate to + + get in touch. Every form of support makes a significant + difference and is deeply appreciated.

+

+

+
+
+ +
+ +
\ No newline at end of file diff --git a/src/websrc/html/PAGE_ETHERNET.html b/src/websrc/html/PAGE_ETHERNET.html deleted file mode 100644 index 0f3b41e..0000000 --- a/src/websrc/html/PAGE_ETHERNET.html +++ /dev/null @@ -1,44 +0,0 @@ -
-
-
-
-
-
Ethernet options
-
-
- - -
-
- - -
-
- - -
-
- - -
- -
-
- -
-
-
-
-
-
-
\ No newline at end of file diff --git a/src/websrc/html/PAGE_GENERAL.html b/src/websrc/html/PAGE_GENERAL.html index 097776e..1e81114 100644 --- a/src/websrc/html/PAGE_GENERAL.html +++ b/src/websrc/html/PAGE_GENERAL.html @@ -1,100 +1,120 @@
-
-
-
-
-
General settings
-
-
-
-
-
- Select the device operating mode: -
- - -
-
- - -
- -
- - -
-
- - -
-
- -
-
+ + +
+
+
+ General settings +
+
+
+
+
+ +
+ + +
+
+ +
+
-
-
-
- Using the Toggle buttons, you can control the state of the LEDs in the - current - session (not saved on reboot): +
+
+
+
+ Select the device operating mode: +
+ + +
+ +
+ +
-
- -
-
- Control the behavior of the LEDs (with saving on reboot) using the - switches - below: -
- -
-
- - -
+
+ + +
+
+ +
+
+
+
+ + Control the behavior of the LEDs (with saving on reboot) using the + switches + below: +
+ +
+
+ +
-
-
- -
-
- +
+
+
+
+
NTP options
+
+ +
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
-
+ +
\ No newline at end of file diff --git a/src/websrc/html/PAGE_LOADER.html b/src/websrc/html/PAGE_LOADER.html index 99ff41b..4d3fe06 100644 --- a/src/websrc/html/PAGE_LOADER.html +++ b/src/websrc/html/PAGE_LOADER.html @@ -9,8 +9,8 @@ -
-
+
+
-