From 7cef2e2954356ca65ce1e4cb0033c3e4b4d94865 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Fri, 6 Jan 2017 00:54:46 +0200 Subject: [PATCH] Add initial IPv6 Support --- cores/esp32/IPv6Address.cpp | 90 +++++++++++++ cores/esp32/IPv6Address.h | 94 ++++++++++++++ libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino | 119 ++++++++++++++++++ libraries/WiFi/src/WiFi.h | 1 + libraries/WiFi/src/WiFiAP.cpp | 45 +++++++ libraries/WiFi/src/WiFiAP.h | 6 + libraries/WiFi/src/WiFiSTA.cpp | 45 +++++++ libraries/WiFi/src/WiFiSTA.h | 6 + 8 files changed, 406 insertions(+) create mode 100644 cores/esp32/IPv6Address.cpp create mode 100644 cores/esp32/IPv6Address.h create mode 100644 libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino diff --git a/cores/esp32/IPv6Address.cpp b/cores/esp32/IPv6Address.cpp new file mode 100644 index 00000000..7d3c0de5 --- /dev/null +++ b/cores/esp32/IPv6Address.cpp @@ -0,0 +1,90 @@ +/* + IPv6Address.cpp - Base class that provides IPv6Address + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +IPv6Address::IPv6Address() +{ + memset(_address.bytes, 0, sizeof(_address.bytes)); +} + +IPv6Address::IPv6Address(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +IPv6Address::IPv6Address(const uint32_t *address) +{ + memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes)); +} + +IPv6Address& IPv6Address::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +bool IPv6Address::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPv6Address::printTo(Print& p) const +{ + size_t n = 0; + for(int i = 0; i < 16; i+=2) { + if(i){ + n += p.print(':'); + } + n += p.printf("%02x", _address.bytes[i]); + n += p.printf("%02x", _address.bytes[i+1]); + + } + return n; +} + +String IPv6Address::toString() const +{ + char szRet[40]; + sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3], + _address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7], + _address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11], + _address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]); + return String(szRet); +} + +bool IPv6Address::fromString(const char *address) +{ + //format 0011:2233:4455:6677:8899:aabb:ccdd:eeff + if(strlen(address) != 39){ + return false; + } + char * pos = (char *)address; + size_t i = 0; + for(i = 0; i < 16; i+=2) { + if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){ + return false; + } + pos += 5; + } + return true; +} diff --git a/cores/esp32/IPv6Address.h b/cores/esp32/IPv6Address.h new file mode 100644 index 00000000..e61d0e7b --- /dev/null +++ b/cores/esp32/IPv6Address.h @@ -0,0 +1,94 @@ +/* + IPv6Address.h - Base class that provides IPv6Address + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef IPv6Address_h +#define IPv6Address_h + +#include +#include +#include + +// A class to make it easier to handle and pass around IP addresses + +class IPv6Address: public Printable +{ +private: + union { + uint8_t bytes[16]; // IPv4 address + uint32_t dword[4]; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() + { + return _address.bytes; + } + +public: + // Constructors + IPv6Address(); + IPv6Address(const uint8_t *address); + IPv6Address(const uint32_t *address); + virtual ~IPv6Address() {} + + bool fromString(const char *address); + bool fromString(const String &address) { return fromString(address.c_str()); } + + operator const uint8_t*() const + { + return _address.bytes; + } + operator const uint32_t*() const + { + return _address.dword; + } + bool operator==(const IPv6Address& addr) const + { + return (_address.dword[0] == addr._address.dword[0]) + && (_address.dword[1] == addr._address.dword[1]) + && (_address.dword[2] == addr._address.dword[2]) + && (_address.dword[3] == addr._address.dword[3]); + } + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const + { + return _address.bytes[index]; + } + uint8_t& operator[](int index) + { + return _address.bytes[index]; + } + + // Overloaded copy operators to allow initialisation of IPv6Address objects from other types + IPv6Address& operator=(const uint8_t *address); + + virtual size_t printTo(Print& p) const; + String toString() const; + + friend class UDP; + friend class Client; + friend class Server; +}; + +#endif diff --git a/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino b/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino new file mode 100644 index 00000000..15803876 --- /dev/null +++ b/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino @@ -0,0 +1,119 @@ +#include "WiFi.h" + +#define STA_SSID "nbis-test" +#define STA_PASS "1234567890" +#define AP_SSID "esp32" + +static volatile bool wifi_connected = false; + +WiFiUDP ntpClient; + +void wifiOnConnect(){ + Serial.println("STA Connected"); + Serial.print("STA IPv4: "); + Serial.println(WiFi.localIP()); + + ntpClient.begin(2390); +} + +void wifiOnDisconnect(){ + Serial.println("STA Disconnected"); + delay(1000); + WiFi.begin(STA_SSID, STA_PASS); +} + +void wifiConnectedLoop(){ + //lets check the time + const int NTP_PACKET_SIZE = 48; + byte ntpPacketBuffer[NTP_PACKET_SIZE]; + + IPAddress address; + WiFi.hostByName("time.nist.gov", address); + memset(ntpPacketBuffer, 0, NTP_PACKET_SIZE); + ntpPacketBuffer[0] = 0b11100011; // LI, Version, Mode + ntpPacketBuffer[1] = 0; // Stratum, or type of clock + ntpPacketBuffer[2] = 6; // Polling Interval + ntpPacketBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + ntpPacketBuffer[12] = 49; + ntpPacketBuffer[13] = 0x4E; + ntpPacketBuffer[14] = 49; + ntpPacketBuffer[15] = 52; + ntpClient.beginPacket(address, 123); //NTP requests are to port 123 + ntpClient.write(ntpPacketBuffer, NTP_PACKET_SIZE); + ntpClient.endPacket(); + + delay(1000); + + int packetLength = ntpClient.parsePacket(); + if (packetLength){ + if(packetLength >= NTP_PACKET_SIZE){ + ntpClient.read(ntpPacketBuffer, NTP_PACKET_SIZE); + } + ntpClient.flush(); + uint32_t secsSince1900 = (uint32_t)ntpPacketBuffer[40] << 24 | (uint32_t)ntpPacketBuffer[41] << 16 | (uint32_t)ntpPacketBuffer[42] << 8 | ntpPacketBuffer[43]; + //Serial.printf("Seconds since Jan 1 1900: %u\n", secsSince1900); + uint32_t epoch = secsSince1900 - 2208988800UL; + //Serial.printf("EPOCH: %u\n", epoch); + uint8_t h = (epoch % 86400L) / 3600; + uint8_t m = (epoch % 3600) / 60; + uint8_t s = (epoch % 60); + Serial.printf("UTC: %02u:%02u:%02u (GMT)\n", h, m, s); + } + + delay(9000); +} + +void WiFiEvent(WiFiEvent_t event){ + switch(event) { + + case SYSTEM_EVENT_AP_START: + //can set ap hostname here + WiFi.softAPsetHostname(AP_SSID); + //enable ap ipv6 here + WiFi.softAPenableIpV6(); + break; + + case SYSTEM_EVENT_STA_START: + //set sta hostname here + WiFi.setHostname(AP_SSID); + break; + case SYSTEM_EVENT_STA_CONNECTED: + //enable sta ipv6 here + WiFi.enableIpV6(); + break; + case SYSTEM_EVENT_AP_STA_GOT_IP6: + //both interfaces get the same event + Serial.print("STA IPv6: "); + Serial.println(WiFi.localIPv6()); + Serial.print("AP IPv6: "); + Serial.println(WiFi.softAPIPv6()); + break; + case SYSTEM_EVENT_STA_GOT_IP: + wifiOnConnect(); + wifi_connected = true; + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + wifi_connected = false; + wifiOnDisconnect(); + break; + default: + break; + } +} + +void setup(){ + Serial.begin(115200); + WiFi.disconnect(true); + WiFi.onEvent(WiFiEvent); + WiFi.mode(WIFI_MODE_APSTA); + WiFi.softAP(AP_SSID); + WiFi.begin(STA_SSID, STA_PASS); +} + +void loop(){ + if(wifi_connected){ + wifiConnectedLoop(); + } + while(Serial.available()) Serial.write(Serial.read()); +} diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index 53c5b2e9..b53b6619 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -26,6 +26,7 @@ #include "Print.h" #include "IPAddress.h" +#include "IPv6Address.h" #include "WiFiType.h" #include "WiFiSTA.h" diff --git a/libraries/WiFi/src/WiFiAP.cpp b/libraries/WiFi/src/WiFiAP.cpp index 5886fd92..8fb10ad1 100644 --- a/libraries/WiFi/src/WiFiAP.cpp +++ b/libraries/WiFi/src/WiFiAP.cpp @@ -232,3 +232,48 @@ String WiFiAPClass::softAPmacAddress(void) sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return String(macStr); } + +/** + * Get the softAP interface Host name. + * @return char array hostname + */ +const char * WiFiAPClass::softAPgetHostname() +{ + const char * hostname; + if(tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &hostname)) { + return NULL; + } + return hostname; +} + +/** + * Set the softAP interface Host name. + * @param hostname pointer to const string + * @return true on success + */ +bool WiFiAPClass::softAPsetHostname(const char * hostname) +{ + return tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_AP, hostname) == 0; +} + +/** + * Enable IPv6 on the softAP interface. + * @return true on success + */ +bool WiFiAPClass::softAPenableIpV6() +{ + return tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_AP) == 0; +} + +/** + * Get the softAP interface IPv6 address. + * @return IPv6Address softAP IPv6 + */ +IPv6Address WiFiAPClass::softAPIPv6() +{ + static ip6_addr_t addr; + if(tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_AP, &addr)) { + return IPv6Address(); + } + return IPv6Address(addr.addr); +} diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h index c7124a0b..cbb47c64 100644 --- a/libraries/WiFi/src/WiFiAP.h +++ b/libraries/WiFi/src/WiFiAP.h @@ -45,6 +45,12 @@ public: IPAddress softAPIP(); + bool softAPenableIpV6(); + IPv6Address softAPIPv6(); + + const char * softAPgetHostname(); + bool softAPsetHostname(const char * hostname); + uint8_t* softAPmacAddress(uint8_t* mac); String softAPmacAddress(void); diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index fd4c90d0..c570d82c 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -453,3 +453,48 @@ int32_t WiFiSTAClass::RSSI(void) { return 0;//wifi_station_get_rssi(); } + +/** + * Get the station interface Host name. + * @return char array hostname + */ +const char * WiFiSTAClass::getHostname() +{ + const char * hostname; + if(tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &hostname)){ + return NULL; + } + return hostname; +} + +/** + * Set the station interface Host name. + * @param hostname pointer to const string + * @return true on success + */ +bool WiFiSTAClass::setHostname(const char * hostname) +{ + return tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, hostname) == 0; +} + +/** + * Enable IPv6 on the station interface. + * @return true on success + */ +bool WiFiSTAClass::enableIpV6() +{ + return tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA) == 0; +} + +/** + * Get the station interface IPv6 address. + * @return IPv6Address + */ +IPv6Address WiFiSTAClass::localIPv6() +{ + static ip6_addr_t addr; + if(tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_STA, &addr)){ + return IPv6Address(); + } + return IPv6Address(addr.addr); +} diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 587eaefb..5e1fcab4 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -63,6 +63,12 @@ public: IPAddress subnetMask(); IPAddress gatewayIP(); IPAddress dnsIP(uint8_t dns_no = 0); + + bool enableIpV6(); + IPv6Address localIPv6(); + + const char * getHostname(); + bool setHostname(const char * hostname); // STA WiFi info wl_status_t status();