Skip to content

Commit 7b42a93

Browse files
Jason2866me-no-dev
authored andcommitted
IPv6 for Arduino 3.0.0
1 parent d912710 commit 7b42a93

10 files changed

+290
-59
lines changed

libraries/WiFi/src/WiFiClient.cpp

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
#include <lwip/netdb.h>
2424
#include <errno.h>
2525

26+
#define IN6_IS_ADDR_V4MAPPED(a) \
27+
((((__const uint32_t *) (a))[0] == 0) \
28+
&& (((__const uint32_t *) (a))[1] == 0) \
29+
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))
30+
2631
#define WIFI_CLIENT_DEF_CONN_TIMEOUT_MS (3000)
2732
#define WIFI_CLIENT_MAX_WRITE_RETRY (10)
2833
#define WIFI_CLIENT_SELECT_TIMEOUT_US (1000000)
@@ -219,22 +224,33 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
219224
{
220225
return connect(ip,port,_timeout);
221226
}
227+
222228
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms)
223229
{
230+
struct sockaddr_storage serveraddr = {};
224231
_timeout = timeout_ms;
225-
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
232+
int sockfd = -1;
233+
234+
if (ip.type() == IPv6) {
235+
struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr;
236+
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
237+
tmpaddr->sin6_family = AF_INET6;
238+
memcpy(tmpaddr->sin6_addr.un.u8_addr, &ip[0], 16);
239+
tmpaddr->sin6_port = htons(port);
240+
tmpaddr->sin6_scope_id = ip.zone();
241+
} else {
242+
struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr;
243+
sockfd = socket(AF_INET, SOCK_STREAM, 0);
244+
tmpaddr->sin_family = AF_INET;
245+
tmpaddr->sin_addr.s_addr = ip;
246+
tmpaddr->sin_port = htons(port);
247+
}
226248
if (sockfd < 0) {
227249
log_e("socket: %d", errno);
228250
return 0;
229251
}
230252
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) | O_NONBLOCK );
231253

232-
uint32_t ip_addr = ip;
233-
struct sockaddr_in serveraddr;
234-
memset((char *) &serveraddr, 0, sizeof(serveraddr));
235-
serveraddr.sin_family = AF_INET;
236-
memcpy((void *)&serveraddr.sin_addr.s_addr, (const void *)(&ip_addr), 4);
237-
serveraddr.sin_port = htons(port);
238254
fd_set fdset;
239255
struct timeval tv;
240256
FD_ZERO(&fdset);
@@ -303,6 +319,19 @@ int WiFiClient::connect(const char *host, uint16_t port)
303319

304320
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout_ms)
305321
{
322+
if (WiFiGenericClass::getStatusBits() & WIFI_WANT_IP6_BIT) {
323+
ip_addr_t srv6;
324+
if(!WiFiGenericClass::hostByName6(host, srv6)){
325+
return 0;
326+
}
327+
if (srv6.type == IPADDR_TYPE_V4) {
328+
IPAddress ip(srv6.u_addr.ip4.addr);
329+
return connect(ip, port, timeout_ms);
330+
} else {
331+
IPAddress ip(IPv6, (uint8_t*)&srv6.u_addr.ip6.addr[0]);
332+
return connect(ip, port, timeout_ms);
333+
}
334+
}
306335
IPAddress srv((uint32_t)0);
307336
if(!WiFiGenericClass::hostByName(host, srv)){
308337
return 0;
@@ -574,8 +603,24 @@ IPAddress WiFiClient::remoteIP(int fd) const
574603
struct sockaddr_storage addr;
575604
socklen_t len = sizeof addr;
576605
getpeername(fd, (struct sockaddr*)&addr, &len);
577-
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
578-
return IPAddress((uint32_t)(s->sin_addr.s_addr));
606+
607+
// IPv4 socket, old way
608+
if (((struct sockaddr*)&addr)->sa_family == AF_INET) {
609+
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
610+
return IPAddress((uint32_t)(s->sin_addr.s_addr));
611+
}
612+
613+
// IPv6, but it might be IPv4 mapped address
614+
if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
615+
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr;
616+
if (IN6_IS_ADDR_V4MAPPED(saddr6->sin6_addr.un.u32_addr)) {
617+
return IPAddress(IPv4, (uint8_t*)saddr6->sin6_addr.s6_addr+12);
618+
} else {
619+
return IPAddress(IPv6, (uint8_t*)(saddr6->sin6_addr.s6_addr), saddr6->sin6_scope_id);
620+
}
621+
}
622+
log_e("WiFiClient::remoteIP Not AF_INET or AF_INET6?");
623+
return (IPAddress(0,0,0,0));
579624
}
580625

581626
uint16_t WiFiClient::remotePort(int fd) const
@@ -638,4 +683,3 @@ int WiFiClient::fd() const
638683
return clientSocketHandle->fd();
639684
}
640685
}
641-

libraries/WiFi/src/WiFiGeneric.cpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,8 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event)
10551055
} else if(event->event_id == ARDUINO_EVENT_WIFI_STA_CONNECTED) {
10561056
WiFiSTAClass::_setStatus(WL_IDLE_STATUS);
10571057
setStatusBits(STA_CONNECTED_BIT);
1058-
1059-
//esp_netif_create_ip6_linklocal(esp_netifs[ESP_IF_WIFI_STA]);
1058+
if (getStatusBits() & WIFI_WANT_IP6_BIT)
1059+
esp_netif_create_ip6_linklocal(esp_netifs[ESP_IF_WIFI_STA]);
10601060
} else if(event->event_id == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
10611061
uint8_t reason = event->event_info.wifi_sta_disconnected.reason;
10621062
// Reason 0 causes crash, use reason 1 (UNSPECIFIED) instead
@@ -1577,8 +1577,27 @@ static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param)
15771577
}
15781578

15791579
/**
1580-
* Resolve the given hostname to an IP address. If passed hostname is an IP address, it will be parsed into IPAddress structure.
1581-
* @param aHostname Name to be resolved or string containing IP address
1580+
* IPv6 compatible DNS callback
1581+
* @param name
1582+
* @param ipaddr
1583+
* @param callback_arg
1584+
*/
1585+
static void wifi_dns6_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
1586+
{
1587+
struct dns_api_msg *msg = (struct dns_api_msg *)callback_arg;
1588+
1589+
if(ipaddr && !msg->result) {
1590+
msg->ip_addr = *ipaddr;
1591+
msg->result = 1;
1592+
} else {
1593+
msg->result = -1;
1594+
}
1595+
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
1596+
}
1597+
1598+
/**
1599+
* Resolve the given hostname to an IP address.
1600+
* @param aHostname Name to be resolved
15821601
* @param aResult IPAddress structure to store the returned IP address
15831602
* @return 1 if aIPAddrString was successfully converted to an IP address,
15841603
* else error code
@@ -1608,6 +1627,37 @@ int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
16081627
return (uint32_t)aResult != 0;
16091628
}
16101629

1630+
/**
1631+
* Resolve the given hostname to an IP6 address.
1632+
* @param aHostname Name to be resolved
1633+
* @param aResult IPv6Address structure to store the returned IP address
1634+
* @return 1 if aHostname was successfully converted to an IP address,
1635+
* else error code
1636+
*/
1637+
int WiFiGenericClass::hostByName6(const char* aHostname, ip_addr_t& aResult)
1638+
{
1639+
ip_addr_t addr;
1640+
struct dns_api_msg arg;
1641+
1642+
memset(&arg, 0x0, sizeof(arg));
1643+
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
1644+
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
1645+
1646+
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns6_found_callback,
1647+
&arg, LWIP_DNS_ADDRTYPE_IPV6_IPV4);
1648+
if(err == ERR_OK) {
1649+
aResult = addr;
1650+
} else if(err == ERR_INPROGRESS) {
1651+
waitStatusBits(WIFI_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s]
1652+
clearStatusBits(WIFI_DNS_DONE_BIT);
1653+
if (arg.result == 1) {
1654+
aResult = arg.ip_addr;
1655+
}
1656+
}
1657+
setStatusBits(WIFI_DNS_IDLE_BIT);
1658+
return (uint32_t)err == ERR_OK || (err == ERR_INPROGRESS && arg.result == 1);
1659+
}
1660+
16111661
IPAddress WiFiGenericClass::calculateNetworkID(IPAddress ip, IPAddress subnet) {
16121662
IPAddress networkID;
16131663

libraries/WiFi/src/WiFiGeneric.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ static const int WIFI_SCANNING_BIT = BIT11;
141141
static const int WIFI_SCAN_DONE_BIT= BIT12;
142142
static const int WIFI_DNS_IDLE_BIT = BIT13;
143143
static const int WIFI_DNS_DONE_BIT = BIT14;
144+
static const int WIFI_WANT_IP6_BIT = BIT15;
144145

145146
typedef enum {
146147
WIFI_RX_ANT0 = 0,
@@ -154,6 +155,11 @@ typedef enum {
154155
WIFI_TX_ANT_AUTO
155156
} wifi_tx_ant_t;
156157

158+
struct dns_api_msg {
159+
ip_addr_t ip_addr;
160+
int result;
161+
};
162+
157163
class WiFiGenericClass
158164
{
159165
public:
@@ -196,6 +202,7 @@ class WiFiGenericClass
196202
static const char * getHostname();
197203
static bool setHostname(const char * hostname);
198204
static bool hostname(const String& aHostname) { return setHostname(aHostname.c_str()); }
205+
static int hostByName6(const char *aHostname, ip_addr_t& aResult);
199206

200207
static esp_err_t _eventCallback(arduino_event_t *event);
201208

libraries/WiFi/src/WiFiMulti.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
WiFiMulti::WiFiMulti()
3232
{
33+
ipv6_support = false;
3334
}
3435

3536
WiFiMulti::~WiFiMulti()
@@ -160,6 +161,8 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
160161
log_i("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb);
161162

162163
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
164+
if (ipv6_support == true)
165+
WiFi.IPv6(true);
163166
status = WiFi.status();
164167

165168
auto startTime = millis();
@@ -202,3 +205,7 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
202205

203206
return status;
204207
}
208+
209+
void WiFiMulti::IPv6(bool state) {
210+
ipv6_support = state;
211+
}

libraries/WiFi/src/WiFiMulti.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ class WiFiMulti
4242

4343
bool addAP(const char* ssid, const char *passphrase = NULL);
4444

45+
void IPv6(bool state);
4546
uint8_t run(uint32_t connectTimeout=5000);
4647

4748
private:
4849
std::vector<WifiAPlist_t> APlist;
50+
bool ipv6_support;
4951
};
5052

5153
#endif /* WIFICLIENTMULTI_H_ */

libraries/WiFi/src/WiFiSTA.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,19 @@ bool WiFiSTAClass::enableIpV6()
816816
return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)) == ESP_OK;
817817
}
818818

819+
/**
820+
* Enable IPv6 support on the station interface.
821+
* @return true on success
822+
*/
823+
bool WiFiSTAClass::IPv6(bool state)
824+
{
825+
if (state)
826+
WiFiGenericClass::setStatusBits(WIFI_WANT_IP6_BIT);
827+
else
828+
WiFiGenericClass::clearStatusBits(WIFI_WANT_IP6_BIT);
829+
return true;
830+
}
831+
819832
/**
820833
* Get the station interface IPv6 address.
821834
* @return IPv6Address

libraries/WiFi/src/WiFiSTA.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class WiFiSTAClass
9494
uint8_t subnetCIDR();
9595

9696
bool enableIpV6();
97+
bool IPv6(bool state);
9798
IPv6Address localIPv6();
9899

99100
// STA WiFi info

libraries/WiFi/src/WiFiServer.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ WiFiClient WiFiServer::accept(){
5151
_accepted_sockfd = -1;
5252
}
5353
else {
54-
struct sockaddr_in _client;
55-
int cs = sizeof(struct sockaddr_in);
54+
struct sockaddr_in6 _client;
55+
int cs = sizeof(struct sockaddr_in6);
5656
#ifdef ESP_IDF_VERSION_MAJOR
5757
client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
5858
#else
@@ -80,14 +80,23 @@ void WiFiServer::begin(uint16_t port, int enable){
8080
if(port){
8181
_port = port;
8282
}
83-
struct sockaddr_in server;
84-
sockfd = socket(AF_INET , SOCK_STREAM, 0);
83+
struct sockaddr_in6 server;
84+
sockfd = socket(AF_INET6 , SOCK_STREAM, 0);
8585
if (sockfd < 0)
8686
return;
8787
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
88-
server.sin_family = AF_INET;
89-
server.sin_addr.s_addr = _addr;
90-
server.sin_port = htons(_port);
88+
server.sin6_family = AF_INET6;
89+
if (_addr.type() == IPv4) {
90+
// log_e("---------------- IPv4");
91+
memcpy(server.sin6_addr.s6_addr+11, (uint8_t*)&_addr[0], 4);
92+
server.sin6_addr.s6_addr[10] = 0xFF;
93+
server.sin6_addr.s6_addr[11] = 0xFF;
94+
} else {
95+
// log_e("---------------- IPv6");
96+
memcpy(server.sin6_addr.s6_addr, (uint8_t*)&_addr[0], 16);
97+
}
98+
memset(server.sin6_addr.s6_addr, 0x0, 16);
99+
server.sin6_port = htons(_port);
91100
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
92101
return;
93102
if(listen(sockfd , _max_clients) < 0)
@@ -110,8 +119,8 @@ bool WiFiServer::hasClient() {
110119
if (_accepted_sockfd >= 0) {
111120
return true;
112121
}
113-
struct sockaddr_in _client;
114-
int cs = sizeof(struct sockaddr_in);
122+
struct sockaddr_in6 _client;
123+
int cs = sizeof(struct sockaddr_in6);
115124
#ifdef ESP_IDF_VERSION_MAJOR
116125
_accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
117126
#else
@@ -140,4 +149,3 @@ void WiFiServer::close(){
140149
void WiFiServer::stop(){
141150
end();
142151
}
143-

libraries/WiFi/src/WiFiServer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class WiFiServer : public Server {
3737
public:
3838
void listenOnLocalhost(){}
3939

40-
// _addr(INADDR_ANY) is the same as _addr() ==> 0.0.0.0
4140
WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
4241
log_v("WiFiServer::WiFiServer(port=%d, ...)", port);
4342
}

0 commit comments

Comments
 (0)