Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
510 changes: 399 additions & 111 deletions mongoose.c

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,20 @@ typedef enum { false = 0, true = 1 } bool;
#pragma comment(lib, "advapi32.lib")
#endif

#if defined(_MSC_VER) && _MSC_VER <= 1200
#ifndef IPPROTO_IP
#define IPPROTO_IP 0
#endif

#ifndef IP_ADD_MEMBERSHIP
struct ip_mreq {
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
#define IP_ADD_MEMBERSHIP 12
#endif
#endif

// Protect from calls like std::snprintf in app code
// See https://github.com/cesanta/mongoose/issues/1047
#ifndef __cplusplus
Expand Down Expand Up @@ -2655,6 +2669,8 @@ void mg_resolve_cancel(struct mg_connection *);
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *);

struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);



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


#if MG_ENABLE_TCPIP




Expand Down Expand Up @@ -2833,7 +2851,6 @@ enum {
MG_TCPIP_EV_USER // Starting ID for user events
};


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

#endif



// Macros to record timestamped events that happens with a connection.
Expand Down
14 changes: 14 additions & 0 deletions src/arch_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ typedef enum { false = 0, true = 1 } bool;
#pragma comment(lib, "advapi32.lib")
#endif

#if defined(_MSC_VER) && _MSC_VER <= 1200
#ifndef IPPROTO_IP
#define IPPROTO_IP 0
#endif

#ifndef IP_ADD_MEMBERSHIP
struct ip_mreq {
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
#define IP_ADD_MEMBERSHIP 12
#endif
#endif

// Protect from calls like std::snprintf in app code
// See https://github.com/cesanta/mongoose/issues/1047
#ifndef __cplusplus
Expand Down
80 changes: 80 additions & 0 deletions src/dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
const struct mg_dns_header *h = (struct mg_dns_header *) buf;
struct mg_dns_rr rr;
size_t i, n, num_answers, ofs = sizeof(*h);
bool is_response;
memset(dm, 0, sizeof(*dm));

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

for (i = 0; i < mg_ntohs(h->num_questions); i++) {
if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
// MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass));
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
ofs += n;
}

if (!is_response) {
// For queries, there is no need to parse the answers. In this way,
// we also ensure the domain name (dm->name) is parsed from
// the question field.
return true;
}

for (i = 0; i < num_answers; i++) {
if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
// MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass,
Expand Down Expand Up @@ -265,3 +276,72 @@ void mg_resolve(struct mg_connection *c, const char *url) {
mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6);
}
}

static const uint8_t mdns_answer[] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd declare this in the handler as a stack variable.

0, 1, // 2 bytes - record type, A
0, 1, // 2 bytes - address class, INET
0, 0, 0, 120, // 4 bytes - TTL
0, 4 // 2 bytes - address length
};

static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_READ) {
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
if (c->recv.len > 12 && (qh->flags & mg_htons(0xF800)) == 0) {
// flags -> !resp, opcode=0 => query; ignore other opcodes and responses
struct mg_dns_rr rr; // Parse first question, offset 12 is header size
size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
if (n > 0) {
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
// buf and h declared here to ease future expansion to DNS-SD
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
struct mg_dns_header *h = (struct mg_dns_header *) buf;
char local_name[63 + 7]; // name label + '.' + local label + '\0'
uint8_t name_len = (uint8_t) strlen((char *)c->fn_data);
struct mg_dns_message dm;
bool unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
// uint16_t q = mg_ntohs(qh->num_questions);
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
qh->num_questions = mg_htons(1); // parser sanity
mg_dns_parse(c->recv.buf, c->recv.len, &dm);
if (name_len > (sizeof(local_name) - 7)) // leave room for .local\0
name_len = sizeof(local_name) - 7;
memcpy(local_name, c->fn_data, name_len);
strcpy(local_name + name_len, ".local"); // ensure proper name.local\0
if (strcmp(local_name, dm.name) == 0) {
uint8_t *p = &buf[sizeof(*h)];
memset(h, 0, sizeof(*h)); // clear header
h->txnid = unicast ? qh->txnid : 0; // RFC-6762 18.1
// RFC-6762 6: 0 questions, 1 Answer, 0 Auth, 0 Additional RRs
h->num_answers = mg_htons(1); // only one answer
h->flags = mg_htons(0x8400); // Authoritative response
*p++ = name_len; // label 1
memcpy(p, c->fn_data, name_len), p += name_len;
*p++ = 5; // label 2
memcpy(p, "local", 5), p += 5;
*p++ = 0; // no more labels
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
#if MG_ENABLE_TCPIP
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
#else
memcpy(p, c->data, 4), p += 4;
#endif
if (!unicast) memcpy(&c->rem, &c->loc, sizeof(c->rem));
mg_send(c, buf, (size_t)(p - buf)); // And send it!
MG_DEBUG(("mDNS %c response sent", unicast ? 'U' : 'M'));
}
}
}
mg_iobuf_del(&c->recv, 0, c->recv.len);
}
(void) ev_data;
}

void mg_multicast_add(struct mg_connection *c, char *ip);
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
struct mg_connection *c =
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name);
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
return c;
}
2 changes: 2 additions & 0 deletions src/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ void mg_resolve_cancel(struct mg_connection *);
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *);

struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);
13 changes: 13 additions & 0 deletions src/drivers/cmsis.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,20 @@ static size_t cmsis_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
return len;
}

static void cmsis_update_hash_table(struct mg_tcpip_if *ifp) {
// TODO(): read database, rebuild hash table
ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0;
ARM_ETH_MAC_ADDR addr;
memcpy(&addr, mcast_addr, sizeof(addr));
mac->SetAddressFilter(&addr, 1);
(void) ifp;
}

static bool cmsis_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
cmsis_update_hash_table(ifp);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
ARM_DRIVER_ETH_PHY *phy = &Driver_ETH_PHY0;
ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0;
Expand Down
13 changes: 13 additions & 0 deletions src/drivers/cyw.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,18 @@ static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len);
static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len);

static size_t cyw_spi_poll(uint8_t *dest);
static void cyw_update_hash_table(void);

// High-level comm stuff

static void cyw_poll(void) {
struct sdpcm_hdr *sdpcm = (struct sdpcm_hdr *) resp;
unsigned int channel;
if (s_ifp->update_mac_hash_table) {
// first call to _poll() is after _init(), so this is safe
cyw_update_hash_table();
s_ifp->update_mac_hash_table = false;
}
if (cyw_spi_poll((uint8_t *) resp) == 0) return; // BUS DEPENDENCY
if ((sdpcm->len ^ sdpcm->_len) != 0xffff || sdpcm->len < sizeof(*sdpcm) ||
sdpcm->len > 2048 - sizeof(*sdpcm))
Expand Down Expand Up @@ -822,6 +828,13 @@ static bool cyw_load_clm(struct mg_tcpip_driver_cyw_firmware *fw) {
return cyw_load_clmll((void *) fw->clm_addr, fw->clm_len);
}

static void cyw_update_hash_table(void) {
// TODO(): read database, rebuild hash table
uint32_t val = 0;
val = 1; cyw_ioctl_iovar_set2_(0, "mcast_list", (uint8_t *)&val, sizeof(val), (uint8_t *)mcast_addr, sizeof(mcast_addr));
mg_delayms(50);
}

// CYW43 chip backplane specifics. All values read and written are in little
// endian format

Expand Down
20 changes: 20 additions & 0 deletions src/drivers/imxrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,14 @@ static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) {
ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed
ENET->TDAR = MG_BIT(24); // Transmit Descriptors have changed
// ENET->OPD = 0x10014;
ENET->IAUR = 0;
ENET->IALR = 0;
ENET->GAUR = 0;
ENET->GALR = 0;
return true;
}


// Transmit frame
static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
Expand All @@ -142,7 +147,22 @@ static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
return len;
}

static mg_tcpip_driver_imxrt_update_hash_table(struct mg_tcpip_if *ifp) {
// TODO(): read database, rebuild hash table
// RM 37.3.4.3.2
uint32_t hash_table[2] = {0, 0};
// uint8_t hash64 = ((~mg_crc32(0, mcast_addr, 6)) >> 26) & 0x3f;
// hash_table[((uint8_t)hash64) >> 5] |= (1 << (hash64 & 0x1f));
hash_table[1] = MG_BIT(1); // above reduces to this for mDNS addr
ENET->GAUR = hash_table[1];
ENET->GALR = hash_table[0];
}

static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
mg_tcpip_driver_imxrt_update_hash_table(ifp);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_imxrt_data *d =
(struct mg_tcpip_driver_imxrt_data *) ifp->driver_data;
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/pico-w.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
s_scanning = 0;
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
}
if (ifp->update_mac_hash_table) {
// first call to _poll() is after _init(), so this is safe
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *)mcast_addr, true);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
Expand Down
27 changes: 17 additions & 10 deletions src/drivers/ra.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,24 @@ static uint16_t smi_rd(uint16_t header) {
pir = 0; // read, mdc = 0
ETHERC->PIR = pir;
raspin(s_smispin / 2); // 1/4 clock period, 300ns max access time
data |= (uint16_t)(ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio
raspin(s_smispin / 2); // 1/4 clock period
pir |= MG_BIT(0); // mdc = 1
data |= (uint16_t) (ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio
raspin(s_smispin / 2); // 1/4 clock period
pir |= MG_BIT(0); // mdc = 1
ETHERC->PIR = pir;
raspin(s_smispin);
}
return data;
}

static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) {
return smi_rd((uint16_t)((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0)));
return smi_rd(
(uint16_t) ((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0)));
}

static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
smi_wr((uint16_t)((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)), val);
smi_wr(
(uint16_t) ((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)),
val);
}

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

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

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

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

static bool mg_tcpip_driver_ra_poll(struct mg_tcpip_if *ifp, bool s1) {
if (ifp->update_mac_hash_table) {
EDMAC->EESIPR = MG_BIT(18) | MG_BIT(7); // FR, RMAF: Frame and mcast IRQ
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_ra_data *d =
(struct mg_tcpip_driver_ra_data *) ifp->driver_data;
Expand All @@ -225,7 +232,7 @@ static uint32_t s_rxno;
void EDMAC_IRQHandler(void) {
struct mg_tcpip_driver_ra_data *d =
(struct mg_tcpip_driver_ra_data *) s_ifp->driver_data;
EDMAC->EESR = MG_BIT(18); // Ack IRQ in EDMAC 1st
EDMAC->EESR = MG_BIT(18) | MG_BIT(7); // Ack IRQ in EDMAC 1st
ICU_IELSR[d->irqno] &= ~MG_BIT(16); // Ack IRQ in ICU last
// Frame received, loop
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
Expand Down
Loading
Loading