-
Notifications
You must be signed in to change notification settings - Fork 7.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding IPv6 support to arduino-esp32 #6712
Closed
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
4735f66
IPv6 support: Add proper link-local and SLAAC in STA and WifiMulti
nuclearcat e8711c0
WiFiClient::remoteIP and remoteIP6 IPv6 support
nuclearcat 4f63dac
Add IPv6 support to WiFiServer
nuclearcat 9337b5c
Add WiFiTelnetToSerialIPv6 example
nuclearcat 7b27e78
Add IPv6 to WifiClient (client)
nuclearcat 01dd9c4
IPv6 support for WiFiClientSecure / ssl_client
nuclearcat ae62e6b
Merge branch 'master' into ipv6-support
SuGlider File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
libraries/WiFi/examples/WiFiTelnetToSerialIPv6/WiFiTelnetToSerialIPv6.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
WiFiTelnetToSerial - Example Transparent UART to Telnet Server for ESP32 | ||
|
||
Copyright (c) 2017 Hristo Gochkov. All rights reserved. | ||
This file is part of the ESP32 WiFi library for Arduino environment. | ||
|
||
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 <WiFi.h> | ||
#include <WiFiMulti.h> | ||
|
||
WiFiMulti wifiMulti; | ||
|
||
//Even this example state IPv6, it is dual stack and compatible with IPv4 too | ||
|
||
//how many clients should be able to telnet to this ESP32 | ||
#define MAX_SRV_CLIENTS 1 | ||
const char* ssid = "**********"; | ||
const char* password = "**********"; | ||
|
||
WiFiServer server(23); | ||
WiFiClient serverClients[MAX_SRV_CLIENTS]; | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
Serial.println("\nConnecting"); | ||
|
||
wifiMulti.IPv6(true); | ||
wifiMulti.addAP(ssid, password); | ||
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); | ||
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); | ||
|
||
Serial.println("Connecting Wifi "); | ||
for (int loops = 10; loops > 0; loops--) { | ||
if (wifiMulti.run() == WL_CONNECTED) { | ||
Serial.println(""); | ||
Serial.print("WiFi connected "); | ||
Serial.print("IP address: "); | ||
Serial.println(WiFi.localIP()); | ||
break; | ||
} | ||
else { | ||
Serial.println(loops); | ||
delay(1000); | ||
} | ||
} | ||
if (wifiMulti.run() != WL_CONNECTED) { | ||
Serial.println("WiFi connect failed"); | ||
delay(1000); | ||
ESP.restart(); | ||
} | ||
|
||
//start UART and the server | ||
Serial1.begin(9600); | ||
server.begin(); | ||
server.setNoDelay(true); | ||
|
||
Serial.print("Ready! Use 'telnet "); | ||
Serial.print(WiFi.localIP()); | ||
Serial.println(" 23' to connect"); | ||
} | ||
|
||
void loop() { | ||
uint8_t i; | ||
if (wifiMulti.run() == WL_CONNECTED) { | ||
//check if there are any new clients | ||
if (server.hasClient()){ | ||
for(i = 0; i < MAX_SRV_CLIENTS; i++){ | ||
//find free/disconnected spot | ||
if (!serverClients[i] || !serverClients[i].connected()){ | ||
if(serverClients[i]) serverClients[i].stop(); | ||
serverClients[i] = server.available(); | ||
if (!serverClients[i]) Serial.println("available broken"); | ||
Serial.print("New client: "); | ||
Serial.print(i); Serial.print(' '); | ||
Serial.println(serverClients[i].remoteIP6()); | ||
break; | ||
} | ||
} | ||
if (i >= MAX_SRV_CLIENTS) { | ||
//no free/disconnected spot so reject | ||
server.available().stop(); | ||
} | ||
} | ||
//check clients for data | ||
for(i = 0; i < MAX_SRV_CLIENTS; i++){ | ||
if (serverClients[i] && serverClients[i].connected()){ | ||
if(serverClients[i].available()){ | ||
//get data from the telnet client and push it to the UART | ||
while(serverClients[i].available()) Serial1.write(serverClients[i].read()); | ||
} | ||
} | ||
else { | ||
if (serverClients[i]) { | ||
serverClients[i].stop(); | ||
} | ||
} | ||
} | ||
//check UART for data | ||
if(Serial1.available()){ | ||
size_t len = Serial1.available(); | ||
uint8_t sbuf[len]; | ||
Serial1.readBytes(sbuf, len); | ||
//push UART data to all connected telnet clients | ||
for(i = 0; i < MAX_SRV_CLIENTS; i++){ | ||
if (serverClients[i] && serverClients[i].connected()){ | ||
serverClients[i].write(sbuf, len); | ||
delay(1); | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
Serial.println("WiFi not connected!"); | ||
for(i = 0; i < MAX_SRV_CLIENTS; i++) { | ||
if (serverClients[i]) serverClients[i].stop(); | ||
} | ||
delay(1000); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One complexity with IPv6 is that with IPv4 usually you will only have one local IP address (public address, private network, or if there is no network a link-local 169.254 address), however with IPv6 you will almost always have multiple addresses -- at least both an autoconfigure link local (fe80: address) as well as an address with the network global prefix, and possibly a ULA prefix as well, and outgoing addresses with privacy enhancements may have rotating outgoing addresses.
One way I was handling this was with the signature
IPAddress localIP(uint8_t index = 0)
, returning one value for each index (or NULL / none once they run out), with another signatureint8_t getLocalIPs(IPAddress addresses[], uint8_t max)
to get multiple addresses, filling an array up to the max (and returning the number of addresses).Usually you don't want to do a lot with the local address except display it, but with IPv6 you want to check which one to display.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can just add globalIP6 and localIP6? This will keep it simple for Arduino users. We can iterate and by prefix identify who is local and who is global.
Privacy enhancements as far as i know is not available in lwip, yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Be careful with terminology not to mix up the concepts of "local" and "link-local", as they are different things.
Local vs remote: Local means this end of the connection, i.e. the IP address of the device, as opposed to remote, which is the other end.
Link-local vs global are scopes: Link-local is confined to the local link only, global is a routeable.
You can have both.
With IPv4 you usually only have one local address, and it usually has a global scope. With IPv6 you have multiple local addresses, both link-local and global scopes.
Generally the global scoped addresses are more useful, e.g. to use as a server address to connect to a device, or when looking in logs. (Although not always, e.g. if the destination machines is on the same link, then IPv6 will use the link-local address.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Examples, from a SIMCOM GSM NB-IoT library I am working on: https://github.com/sgryphon/AdvancedGsmClient/blob/main/src/SIM7020/SIM7020GsmModem.cpp#L470
When I connect the NB-IoT modem, it gets assigned 3 local addresses, plus it's address list includes a localhost address:
Local addresses:
The actual order the addresses are reported by the device is fe80:, 2001:, 10.88, 127.0, however my
getLocalIPs()
method sorts them from largest scope (global) to smallest scope (link-local), and then within each scope according to the RFC 6724 precedence rules (which includes IPv6 before IPv4), to get the order listed above.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my local desktop computer, sorting my addresses a similar way (but using the bytes; my simple GSM algorithm is using strings and so sorts ':' differently), to sort them in order of usefulness:
Global scope is sorted before link-local (because it is more useful to contact me as a server), with the precedence order IPv6, then IPv4, then IPv6 unique local address (ULA).
As a server the ::8e6 address is better, although outgoing logs will use the temporary addresses (probably not an issue for Arduino). If I was communicating with an IPv4 only server, then it would see the IPv4 address.
So, to really investigate I would need to list all of my addresses (e.g. in logs). Even the ULA addresses could be used, for local communications, and the IPv6 link-local address could even be used in some cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you really want to stick with separate properties for IPv6 and IPv4, for only one of each type, then you want to try and return a global scope address if possible:
localIP4()
- Shows the local IPv4 address (this will usually be a global scope address); there is usually only one. To be consistent, in case there is more than one IPv4, you should also sort by scope (e.g. if a device has two IP addresses 169.254.1.2 and 10.1.2.3, then show 10.1.2.3 ... although that would be really weird as IPv4 doesn't work that way).localIP6()
- shows the first IPv6 address, sorting global scope before link-local scope.localIP()
- for a single address should show the biggest scope, highest precedence address. i.e. global IPv6 if you have one, otherwise global IPv4, and then finally (if you have no global addresses), then the link-local IPv6.I do think you should have a getLocalIPs() that returns all of the addresses, which you could then use to select out the other values, e.g. for logging, although in the case of the GSM code I know it only ever gets max 4 addresses (i.e. no temporary, only one IPv6 prefix, etc), so I just log the first 2 address, which will be the one global IPv6 and the one global IPv4.