Skip to content

Commit c2e2432

Browse files
authored
Merge pull request #3093 from cesanta/mdns-multicast
Added MDNS and driver support for multicast
2 parents fb09964 + 1d2a768 commit c2e2432

File tree

30 files changed

+913
-223
lines changed

30 files changed

+913
-223
lines changed

mongoose.c

Lines changed: 399 additions & 111 deletions
Large diffs are not rendered by default.

mongoose.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,20 @@ typedef enum { false = 0, true = 1 } bool;
499499
#pragma comment(lib, "advapi32.lib")
500500
#endif
501501

502+
#if defined(_MSC_VER) && _MSC_VER <= 1200
503+
#ifndef IPPROTO_IP
504+
#define IPPROTO_IP 0
505+
#endif
506+
507+
#ifndef IP_ADD_MEMBERSHIP
508+
struct ip_mreq {
509+
struct in_addr imr_multiaddr;
510+
struct in_addr imr_interface;
511+
};
512+
#define IP_ADD_MEMBERSHIP 12
513+
#endif
514+
#endif
515+
502516
// Protect from calls like std::snprintf in app code
503517
// See https://github.com/cesanta/mongoose/issues/1047
504518
#ifndef __cplusplus
@@ -2655,6 +2669,8 @@ void mg_resolve_cancel(struct mg_connection *);
26552669
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
26562670
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
26572671
bool is_question, struct mg_dns_rr *);
2672+
2673+
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);
26582674

26592675

26602676

@@ -2803,6 +2819,8 @@ bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel);
28032819
bool mg_wifi_ap_stop(void);
28042820

28052821

2822+
#if MG_ENABLE_TCPIP
2823+
28062824

28072825

28082826

@@ -2833,7 +2851,6 @@ enum {
28332851
MG_TCPIP_EV_USER // Starting ID for user events
28342852
};
28352853

2836-
28372854
// Network interface
28382855
struct mg_tcpip_if {
28392856
uint8_t mac[6]; // MAC address. Must be set to a valid MAC
@@ -2846,6 +2863,7 @@ struct mg_tcpip_if {
28462863
bool enable_req_sntp; // DCHP client requests SNTP server
28472864
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
28482865
bool enable_mac_check; // Do a MAC check on RX frames
2866+
bool update_mac_hash_table; // Signal drivers to update MAC controller
28492867
struct mg_tcpip_driver *driver; // Low level driver
28502868
void *driver_data; // Driver-specific data
28512869
mg_tcpip_event_handler_t fn; // User-specified event handler function
@@ -2903,6 +2921,8 @@ struct mg_tcpip_spi {
29032921
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
29042922
};
29052923

2924+
#endif
2925+
29062926

29072927

29082928
// Macros to record timestamped events that happens with a connection.

src/arch_win32.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ typedef enum { false = 0, true = 1 } bool;
7777
#pragma comment(lib, "advapi32.lib")
7878
#endif
7979

80+
#if defined(_MSC_VER) && _MSC_VER <= 1200
81+
#ifndef IPPROTO_IP
82+
#define IPPROTO_IP 0
83+
#endif
84+
85+
#ifndef IP_ADD_MEMBERSHIP
86+
struct ip_mreq {
87+
struct in_addr imr_multiaddr;
88+
struct in_addr imr_interface;
89+
};
90+
#define IP_ADD_MEMBERSHIP 12
91+
#endif
92+
#endif
93+
8094
// Protect from calls like std::snprintf in app code
8195
// See https://github.com/cesanta/mongoose/issues/1047
8296
#ifndef __cplusplus

src/dns.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
100100
const struct mg_dns_header *h = (struct mg_dns_header *) buf;
101101
struct mg_dns_rr rr;
102102
size_t i, n, num_answers, ofs = sizeof(*h);
103+
bool is_response;
103104
memset(dm, 0, sizeof(*dm));
104105

105106
if (len < sizeof(*h)) return 0; // Too small, headers dont fit
@@ -110,12 +111,22 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
110111
num_answers = 10; // Sanity cap
111112
}
112113
dm->txnid = mg_ntohs(h->txnid);
114+
is_response = mg_ntohs(h->flags) & 0x8000;
113115

114116
for (i = 0; i < mg_ntohs(h->num_questions); i++) {
115117
if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
116118
// MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass));
119+
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
117120
ofs += n;
118121
}
122+
123+
if (!is_response) {
124+
// For queries, there is no need to parse the answers. In this way,
125+
// we also ensure the domain name (dm->name) is parsed from
126+
// the question field.
127+
return true;
128+
}
129+
119130
for (i = 0; i < num_answers; i++) {
120131
if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
121132
// MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass,
@@ -265,3 +276,72 @@ void mg_resolve(struct mg_connection *c, const char *url) {
265276
mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6);
266277
}
267278
}
279+
280+
static const uint8_t mdns_answer[] = {
281+
0, 1, // 2 bytes - record type, A
282+
0, 1, // 2 bytes - address class, INET
283+
0, 0, 0, 120, // 4 bytes - TTL
284+
0, 4 // 2 bytes - address length
285+
};
286+
287+
static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
288+
if (ev == MG_EV_READ) {
289+
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
290+
if (c->recv.len > 12 && (qh->flags & mg_htons(0xF800)) == 0) {
291+
// flags -> !resp, opcode=0 => query; ignore other opcodes and responses
292+
struct mg_dns_rr rr; // Parse first question, offset 12 is header size
293+
size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
294+
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
295+
if (n > 0) {
296+
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
297+
// buf and h declared here to ease future expansion to DNS-SD
298+
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
299+
struct mg_dns_header *h = (struct mg_dns_header *) buf;
300+
char local_name[63 + 7]; // name label + '.' + local label + '\0'
301+
uint8_t name_len = (uint8_t) strlen((char *)c->fn_data);
302+
struct mg_dns_message dm;
303+
bool unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
304+
// uint16_t q = mg_ntohs(qh->num_questions);
305+
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
306+
qh->num_questions = mg_htons(1); // parser sanity
307+
mg_dns_parse(c->recv.buf, c->recv.len, &dm);
308+
if (name_len > (sizeof(local_name) - 7)) // leave room for .local\0
309+
name_len = sizeof(local_name) - 7;
310+
memcpy(local_name, c->fn_data, name_len);
311+
strcpy(local_name + name_len, ".local"); // ensure proper name.local\0
312+
if (strcmp(local_name, dm.name) == 0) {
313+
uint8_t *p = &buf[sizeof(*h)];
314+
memset(h, 0, sizeof(*h)); // clear header
315+
h->txnid = unicast ? qh->txnid : 0; // RFC-6762 18.1
316+
// RFC-6762 6: 0 questions, 1 Answer, 0 Auth, 0 Additional RRs
317+
h->num_answers = mg_htons(1); // only one answer
318+
h->flags = mg_htons(0x8400); // Authoritative response
319+
*p++ = name_len; // label 1
320+
memcpy(p, c->fn_data, name_len), p += name_len;
321+
*p++ = 5; // label 2
322+
memcpy(p, "local", 5), p += 5;
323+
*p++ = 0; // no more labels
324+
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
325+
#if MG_ENABLE_TCPIP
326+
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
327+
#else
328+
memcpy(p, c->data, 4), p += 4;
329+
#endif
330+
if (!unicast) memcpy(&c->rem, &c->loc, sizeof(c->rem));
331+
mg_send(c, buf, (size_t)(p - buf)); // And send it!
332+
MG_DEBUG(("mDNS %c response sent", unicast ? 'U' : 'M'));
333+
}
334+
}
335+
}
336+
mg_iobuf_del(&c->recv, 0, c->recv.len);
337+
}
338+
(void) ev_data;
339+
}
340+
341+
void mg_multicast_add(struct mg_connection *c, char *ip);
342+
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
343+
struct mg_connection *c =
344+
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name);
345+
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
346+
return c;
347+
}

src/dns.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ void mg_resolve_cancel(struct mg_connection *);
3636
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
3737
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
3838
bool is_question, struct mg_dns_rr *);
39+
40+
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);

src/drivers/cmsis.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,20 @@ static size_t cmsis_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
5656
return len;
5757
}
5858

59+
static void cmsis_update_hash_table(struct mg_tcpip_if *ifp) {
60+
// TODO(): read database, rebuild hash table
61+
ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0;
62+
ARM_ETH_MAC_ADDR addr;
63+
memcpy(&addr, mcast_addr, sizeof(addr));
64+
mac->SetAddressFilter(&addr, 1);
65+
(void) ifp;
66+
}
67+
5968
static bool cmsis_poll(struct mg_tcpip_if *ifp, bool s1) {
69+
if (ifp->update_mac_hash_table) {
70+
cmsis_update_hash_table(ifp);
71+
ifp->update_mac_hash_table = false;
72+
}
6073
if (!s1) return false;
6174
ARM_DRIVER_ETH_PHY *phy = &Driver_ETH_PHY0;
6275
ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0;

src/drivers/cyw.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,18 @@ static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len);
140140
static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len);
141141

142142
static size_t cyw_spi_poll(uint8_t *dest);
143+
static void cyw_update_hash_table(void);
143144

144145
// High-level comm stuff
145146

146147
static void cyw_poll(void) {
147148
struct sdpcm_hdr *sdpcm = (struct sdpcm_hdr *) resp;
148149
unsigned int channel;
150+
if (s_ifp->update_mac_hash_table) {
151+
// first call to _poll() is after _init(), so this is safe
152+
cyw_update_hash_table();
153+
s_ifp->update_mac_hash_table = false;
154+
}
149155
if (cyw_spi_poll((uint8_t *) resp) == 0) return; // BUS DEPENDENCY
150156
if ((sdpcm->len ^ sdpcm->_len) != 0xffff || sdpcm->len < sizeof(*sdpcm) ||
151157
sdpcm->len > 2048 - sizeof(*sdpcm))
@@ -822,6 +828,13 @@ static bool cyw_load_clm(struct mg_tcpip_driver_cyw_firmware *fw) {
822828
return cyw_load_clmll((void *) fw->clm_addr, fw->clm_len);
823829
}
824830

831+
static void cyw_update_hash_table(void) {
832+
// TODO(): read database, rebuild hash table
833+
uint32_t val = 0;
834+
val = 1; cyw_ioctl_iovar_set2_(0, "mcast_list", (uint8_t *)&val, sizeof(val), (uint8_t *)mcast_addr, sizeof(mcast_addr));
835+
mg_delayms(50);
836+
}
837+
825838
// CYW43 chip backplane specifics. All values read and written are in little
826839
// endian format
827840

src/drivers/imxrt.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,14 @@ static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) {
115115
ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed
116116
ENET->TDAR = MG_BIT(24); // Transmit Descriptors have changed
117117
// ENET->OPD = 0x10014;
118+
ENET->IAUR = 0;
119+
ENET->IALR = 0;
120+
ENET->GAUR = 0;
121+
ENET->GALR = 0;
118122
return true;
119123
}
120124

125+
121126
// Transmit frame
122127
static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
123128
struct mg_tcpip_if *ifp) {
@@ -142,7 +147,22 @@ static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
142147
return len;
143148
}
144149

150+
static mg_tcpip_driver_imxrt_update_hash_table(struct mg_tcpip_if *ifp) {
151+
// TODO(): read database, rebuild hash table
152+
// RM 37.3.4.3.2
153+
uint32_t hash_table[2] = {0, 0};
154+
// uint8_t hash64 = ((~mg_crc32(0, mcast_addr, 6)) >> 26) & 0x3f;
155+
// hash_table[((uint8_t)hash64) >> 5] |= (1 << (hash64 & 0x1f));
156+
hash_table[1] = MG_BIT(1); // above reduces to this for mDNS addr
157+
ENET->GAUR = hash_table[1];
158+
ENET->GALR = hash_table[0];
159+
}
160+
145161
static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) {
162+
if (ifp->update_mac_hash_table) {
163+
mg_tcpip_driver_imxrt_update_hash_table(ifp);
164+
ifp->update_mac_hash_table = false;
165+
}
146166
if (!s1) return false;
147167
struct mg_tcpip_driver_imxrt_data *d =
148168
(struct mg_tcpip_driver_imxrt_data *) ifp->driver_data;

src/drivers/pico-w.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
5151
s_scanning = 0;
5252
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
5353
}
54+
if (ifp->update_mac_hash_table) {
55+
// first call to _poll() is after _init(), so this is safe
56+
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *)mcast_addr, true);
57+
ifp->update_mac_hash_table = false;
58+
}
5459
if (!s1) return false;
5560
struct mg_tcpip_driver_pico_w_data *d =
5661
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;

src/drivers/ra.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,24 @@ static uint16_t smi_rd(uint16_t header) {
101101
pir = 0; // read, mdc = 0
102102
ETHERC->PIR = pir;
103103
raspin(s_smispin / 2); // 1/4 clock period, 300ns max access time
104-
data |= (uint16_t)(ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio
105-
raspin(s_smispin / 2); // 1/4 clock period
106-
pir |= MG_BIT(0); // mdc = 1
104+
data |= (uint16_t) (ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio
105+
raspin(s_smispin / 2); // 1/4 clock period
106+
pir |= MG_BIT(0); // mdc = 1
107107
ETHERC->PIR = pir;
108108
raspin(s_smispin);
109109
}
110110
return data;
111111
}
112112

113113
static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) {
114-
return smi_rd((uint16_t)((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0)));
114+
return smi_rd(
115+
(uint16_t) ((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0)));
115116
}
116117

117118
static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
118-
smi_wr((uint16_t)((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)), val);
119+
smi_wr(
120+
(uint16_t) ((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)),
121+
val);
119122
}
120123

121124
// MDC clock is generated manually; as per 802.3, it must not exceed 2.5MHz
@@ -152,7 +155,7 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
152155

153156
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
154157
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
155-
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY
158+
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY
156159

157160
// Select RMII mode,
158161
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
@@ -171,9 +174,9 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
171174
EDMAC->FDR = 0x070f; // (27.2.11)
172175
EDMAC->RMCR = MG_BIT(0); // (27.2.12)
173176
ETHERC->ECMR |= MG_BIT(6) | MG_BIT(5); // TE RE
174-
EDMAC->EESIPR = MG_BIT(18); // Enable Rx IRQ
175-
EDMAC->EDRRR = MG_BIT(0); // Receive Descriptors have changed
176-
EDMAC->EDTRR = MG_BIT(0); // Transmit Descriptors have changed
177+
EDMAC->EESIPR = MG_BIT(18); // FR: Enable Rx (frame) IRQ
178+
EDMAC->EDRRR = MG_BIT(0); // Receive Descriptors have changed
179+
EDMAC->EDTRR = MG_BIT(0); // Transmit Descriptors have changed
177180
return true;
178181
}
179182

@@ -199,6 +202,10 @@ static size_t mg_tcpip_driver_ra_tx(const void *buf, size_t len,
199202
}
200203

201204
static bool mg_tcpip_driver_ra_poll(struct mg_tcpip_if *ifp, bool s1) {
205+
if (ifp->update_mac_hash_table) {
206+
EDMAC->EESIPR = MG_BIT(18) | MG_BIT(7); // FR, RMAF: Frame and mcast IRQ
207+
ifp->update_mac_hash_table = false;
208+
}
202209
if (!s1) return false;
203210
struct mg_tcpip_driver_ra_data *d =
204211
(struct mg_tcpip_driver_ra_data *) ifp->driver_data;
@@ -225,7 +232,7 @@ static uint32_t s_rxno;
225232
void EDMAC_IRQHandler(void) {
226233
struct mg_tcpip_driver_ra_data *d =
227234
(struct mg_tcpip_driver_ra_data *) s_ifp->driver_data;
228-
EDMAC->EESR = MG_BIT(18); // Ack IRQ in EDMAC 1st
235+
EDMAC->EESR = MG_BIT(18) | MG_BIT(7); // Ack IRQ in EDMAC 1st
229236
ICU_IELSR[d->irqno] &= ~MG_BIT(16); // Ack IRQ in ICU last
230237
// Frame received, loop
231238
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever

0 commit comments

Comments
 (0)