Skip to content

Commit 7df514b

Browse files
Overhaul SimpleMDNS handling of WiFi::begin/end
Fixes #3157 LWIP MDNS was not being removed from a netif when a device ::end was called, resulting in a crash on reconnect when MDNS or things like ArduinoOTA (which uses SimpleMDNS) were used. They would not crash, however, if the initial WiFi::begin failed, because LWIP MDNS does not automatically add existing services to a "new" netif (i.e. there was no MDNS on the 2nd and following WiFi.begin() calls). To fix the crash due to null-derefernce, add a way for SimpleMDNS to remove MSND from a netif before it is netif_removed. To fix the lack of MDNS services after a WiFi reconnect, keep track of the services we've already added and add a call to hook into LwipIntfDev after a new netif has been brought up (link-state at least, if not DHCP).
1 parent e144e6d commit 7df514b

File tree

5 files changed

+108
-21
lines changed

5 files changed

+108
-21
lines changed

libraries/SimpleMDNS/src/SimpleMDNS.cpp

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,73 @@
2222
#include <Arduino.h>
2323
#include "SimpleMDNS.h"
2424
#include <LwipEthernet.h>
25-
#include <lwip/apps/mdns.h>
25+
26+
// LWIP MDNS doesn't expose a way for us to know if MDNS has been enabled on a netif, so use the private accessor. Sorry...
27+
extern "C" struct mdns_host* netif_mdns_data(struct netif *netif);
2628

2729
bool SimpleMDNS::begin(const char *hostname, unsigned int ttl) {
2830
(void) ttl;
2931

3032
if (_running) {
3133
return false;
3234
}
33-
mdns_resp_init();
35+
if (!_lwipMSNDInitted) {
36+
mdns_resp_init();
37+
_lwipMSNDInitted = true;
38+
}
3439
struct netif *n = netif_list;
3540
while (n) {
3641
mdns_resp_add_netif(n, hostname);
3742
n = n->next;
3843
}
3944
__setStateChangeCallback(_statusCB);
45+
__setAddNetifCallback(_addNetifCB);
46+
__setRemoveNetifCallback(_removeNetifCB);
47+
4048
_hostname = strdup(hostname);
4149
_running = true;
4250

4351
return true;
4452
}
4553

54+
void SimpleMDNS::_addNetifCB(struct netif *n) {
55+
MDNS.addNetif(n);
56+
}
57+
58+
void SimpleMDNS::_removeNetifCB(struct netif *n) {
59+
MDNS.removeNetif(n);
60+
}
61+
62+
63+
// Only call when __useSimpleMDNS == true!
64+
void SimpleMDNS::removeNetif(struct netif *n) {
65+
if (netif_mdns_data(n)) {
66+
mdns_resp_remove_netif(n);
67+
}
68+
}
69+
70+
// Only call when __useSimpleMDNS == true!
71+
void SimpleMDNS::addNetif(struct netif *n) {
72+
mdns_resp_add_netif(n, _hostname);
73+
for (auto svc : _svcMap) {
74+
char s[128];
75+
snprintf(s, sizeof(s), "_%s", svc.second->_service);
76+
s[sizeof(s) - 1] = 0;
77+
mdns_resp_add_service(n, _hostname, s, (mdns_sd_proto)svc.second->_proto, svc.second->_port, svc.second->_fn, svc.second->_userdata);
78+
}
79+
}
80+
4681
void SimpleMDNS::enableArduino(unsigned int port, bool passwd) {
4782
if (!_running || _arduinoAdded) {
4883
return;
4984
}
85+
SimpleMDNSService *svc = new SimpleMDNSService();
86+
svc->_service = "arduino";
87+
svc->_proto = DNSSD_PROTO_TCP;
88+
svc->_port = port;
89+
svc->_fn = _arduinoGetTxt;
90+
svc->_userdata = (void *)passwd;
91+
_svcMap.insert({svc->_service, svc});
5092
struct netif *n = netif_list;
5193
while (n) {
5294
mdns_resp_add_service(n, _hostname, "_arduino", DNSSD_PROTO_TCP, port, _arduinoGetTxt, (void *)passwd);
@@ -67,10 +109,15 @@ hMDNSService SimpleMDNS::addService(const char *service, const char *proto, unsi
67109
snprintf(s, sizeof(s), "_%s", service);
68110
s[sizeof(s) - 1] = 0;
69111
SimpleMDNSService *svc = new SimpleMDNSService();
70-
_svcMap.insert({strdup(service), svc});
112+
svc->_service = strdup(service);
113+
svc->_proto = !strcasecmp("tcp", proto) ? DNSSD_PROTO_TCP : DNSSD_PROTO_UDP;
114+
svc->_port = port;
115+
svc->_fn = SimpleMDNSService::callback;
116+
svc->_userdata = (void *)svc;
117+
_svcMap.insert({svc->_service, svc});
71118
struct netif *n = netif_list;
72119
while (n) {
73-
mdns_resp_add_service(n, _hostname, s, !strcasecmp("tcp", proto) ? DNSSD_PROTO_TCP : DNSSD_PROTO_UDP, port, SimpleMDNSService::callback, (void *)svc);
120+
mdns_resp_add_service(n, _hostname, s, (mdns_sd_proto)svc->_proto, svc->_port, svc->_fn, svc->_userdata);
74121
n = n->next;
75122
}
76123
return (hMDNSService*) service;
@@ -80,8 +127,22 @@ void SimpleMDNS::update() {
80127
/* No-op */
81128
}
82129

130+
83131
void SimpleMDNS::end() {
84-
/* No-op */
132+
if (_running) {
133+
struct netif *n = netif_list;
134+
while (n) {
135+
if (netif_mdns_data(n)) {
136+
mdns_resp_remove_netif(n);
137+
}
138+
n = n->next;
139+
}
140+
__setStateChangeCallback(nullptr);
141+
__setAddNetifCallback(nullptr);
142+
__setRemoveNetifCallback(nullptr);
143+
144+
}
145+
_running = false;
85146
}
86147

87148
void SimpleMDNS::_statusCB(struct netif *netif) {

libraries/SimpleMDNS/src/SimpleMDNS.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <string>
2525
#include <map>
2626
#include <vector>
27+
#include <lwip/apps/mdns.h>
2728

2829
typedef void* hMDNSTxt; // Unusable in SimpleMDNS, for signature compatibility only
2930

@@ -32,6 +33,13 @@ class SimpleMDNSService {
3233
SimpleMDNSService();
3334
static void callback(struct mdns_service *service, void *txt_userdata);
3435
hMDNSTxt add(const char *key, const char *val);
36+
37+
const char *_service;
38+
uint16_t _proto;
39+
uint16_t _port;
40+
service_get_txt_fn_t _fn;
41+
void *_userdata;
42+
3543
private:
3644
std::vector<const char *> txt;
3745
};
@@ -60,8 +68,9 @@ class SimpleMDNS {
6068
hMDNSTxt addServiceTxt(const hMDNSService p_hService, const char* p_pcKey, int16_t p_i16Value);
6169
hMDNSTxt addServiceTxt(const hMDNSService p_hService, const char* p_pcKey, int8_t p_i8Value);
6270

63-
// No-ops here
6471
void end();
72+
73+
// No-ops here
6574
void update();
6675

6776
private:
@@ -70,9 +79,16 @@ class SimpleMDNS {
7079
static void _arduinoGetTxt(struct mdns_service *service, void *txt_userdata);
7180

7281
bool _running = false;
82+
bool _lwipMSNDInitted = false;
7383
static const char *_hostname;
7484
std::map<std::string, SimpleMDNSService*> _svcMap;
7585
bool _arduinoAdded = false;
86+
87+
// LwipIntfDev helpers when netifs come up and down, to ensure we set the old services on the new netif
88+
static void _addNetifCB(struct netif *n);
89+
static void _removeNetifCB(struct netif *n);
90+
void removeNetif(struct netif *n);
91+
void addNetif(struct netif *n);
7692
};
7793

7894
extern SimpleMDNS MDNS;

libraries/lwIP_Ethernet/src/LwipEthernet.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,13 @@ std::function<void(struct netif *)> _scb;
293293
void __setStateChangeCallback(std::function<void(struct netif *)> s) {
294294
_scb = s;
295295
}
296+
297+
std::function<void(struct netif *)> _addNetifCB;
298+
void __setAddNetifCallback(std::function<void(struct netif *)> s) {
299+
_addNetifCB = s;
300+
}
301+
302+
std::function<void(struct netif *)> _removeNetifCB;
303+
void __setRemoveNetifCallback(std::function<void(struct netif *)> s) {
304+
_removeNetifCB = s;
305+
}

libraries/lwIP_Ethernet/src/LwipEthernet.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,7 @@ void lwipPollingPeriod(int ms);
4747

4848
// Sets the global netif state change callback
4949
void __setStateChangeCallback(std::function<void(struct netif *)> s);
50+
51+
// Set callback when a netif is added after bring-up, removed before netif_remove
52+
void __setAddNetifCallback(std::function<void(struct netif *)> s);
53+
void __setRemoveNetifCallback(std::function<void(struct netif *)> s);

libraries/lwIP_Ethernet/src/LwipIntfDev.h

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
#define DEFAULT_MTU 1500
5656
#endif
5757

58-
5958
// Dup'd to avoid CYW43 dependency
6059
// Generate a mac address if one is not set in otp
6160
static void _cyw43_hal_generate_laa_mac(__unused int idx, uint8_t buf[6]) {
@@ -340,6 +339,7 @@ bool LwipIntfDev<RawDev>::config(IPAddress local_ip, IPAddress dns) {
340339
}
341340

342341
extern char wifi_station_hostname[];
342+
extern std::function<void(struct netif *)> _addNetifCB;
343343
template<class RawDev>
344344
bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
345345
if (_started) {
@@ -369,15 +369,9 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
369369
_netif.num = n->num + 1;
370370
}
371371

372-
#if 1
373372
// forge a new mac-address from the esp's wifi sta one
374373
// I understand this is cheating with an official mac-address
375374
_cyw43_hal_generate_laa_mac(0, _macAddress);
376-
#else
377-
// https://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines
378-
memset(_macAddress, 0, 6);
379-
_macAddress[0] = 0xEE;
380-
#endif
381375
_macAddress[3] += _netif.num; // alter base mac address
382376
_macAddress[0] &= 0xfe; // set as locally administered, unicast, per
383377
_macAddress[0] |= 0x02; // https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local
@@ -459,9 +453,15 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
459453
}
460454
}
461455

456+
if (_addNetifCB) {
457+
_addNetifCB(&_netif);
458+
}
462459
return true;
463460
}
464461

462+
463+
extern std::function<void(struct netif *)> _removeNetifCB;
464+
465465
template<class RawDev>
466466
void LwipIntfDev<RawDev>::end() {
467467
if (_started) {
@@ -472,6 +472,10 @@ void LwipIntfDev<RawDev>::end() {
472472
__removeEthernetGPIO(_intrPin);
473473
}
474474

475+
if (_removeNetifCB) {
476+
_removeNetifCB(&_netif);
477+
}
478+
475479
RawDev::end();
476480

477481
netif_remove(&_netif);
@@ -493,11 +497,6 @@ void LwipIntfDev<RawDev>::_irq(void *param) {
493497
LwipIntfDev *d = static_cast<LwipIntfDev*>(param);
494498
ethernet_arch_lwip_gpio_mask(); // Disable other IRQs until we're done processing this one
495499
lwip_callback(_lwipCallback, param, &d->_irqBuffer);
496-
//ethernet_arch_lwip_begin();
497-
// d->handlePackets();
498-
// sys_check_timeouts();
499-
//ethernet_arch_lwip_end();
500-
501500
}
502501

503502
template<class RawDev>
@@ -658,9 +657,6 @@ err_t LwipIntfDev<RawDev>::handlePackets() {
658657
}
659658

660659
_packetsReceived++;
661-
//printf("recv pkt %d: ", tot_len);
662-
//for (int i=0; i < tot_len; i++) printf("%02x ", ((uint8_t*)pbuf->payload)[i]);
663-
//printf("\n");
664660
err_t err = _netif.input(pbuf, &_netif);
665661

666662
#if PHY_HAS_CAPTURE

0 commit comments

Comments
 (0)