diff --git a/mongoose.c b/mongoose.c index e1ce83cf..457df2da 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2142,7 +2142,6 @@ static void handle_mdns_query(struct mg_connection *c) { MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype, (unsigned int) rr.aclass, name)); if (rr.atype == MG_DNS_RTYPE_A) { - // TODO(): ensure c->fn_data ends in \0 // if we have a name to match, go; otherwise users will match and fill // req.r.name and set req.is_resp if (c->fn_data != NULL && mg_casecmp((char *) c->fn_data, name) != 0) @@ -5653,6 +5652,13 @@ size_t mg_l2_eth_trailer(struct mg_tcpip_if *ifp, size_t len, uint8_t *cur) { struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype addrtype, struct mg_addr *addr); +// Read an unaligned little-endian value from byte pointer p into a native integer. +// Safe on architectures that forbid unaligned access (e.g. Cortex-M0). +#define MG_LOAD_LE32(p) \ + ((uint32_t) (((uint32_t) MG_U8P(p)[3] << 24U) | \ + ((uint32_t) MG_U8P(p)[2] << 16U) | \ + ((uint32_t) MG_U8P(p)[1] << 8U) | MG_U8P(p)[0])) + bool mg_l2_eth_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto, struct mg_str *pay, struct mg_str *raw) { struct eth *eth = (struct eth *) raw->buf; @@ -5678,10 +5684,11 @@ bool mg_l2_eth_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto, sizeof(eth->dst)) != 0) return false; // TODO(): add multicast addresses if (ifp->enable_fcs_check && len > hdrlen + 4) { - uint32_t crc; - len -= 4; // TODO(scaprile): check on bigendian + uint32_t crc, crc_rx; + len -= 4; crc = mg_crc32(0, (const char *) raw->buf, len); - if (memcmp((void *) ((size_t) raw->buf + len), &crc, sizeof(crc))) + crc_rx = MG_LOAD_LE32(raw->buf + len); + if (crc_rx != crc) return false; } pay->buf = ((char *) eth) + hdrlen; diff --git a/mongoose.h b/mongoose.h index 9583c033..543cefd7 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4208,6 +4208,7 @@ size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, // Creates an mDNS listener on UDP multicast 224.0.0.251:5353. Registers it as // the manager's mDNS resolver (mgr->mdns). Fires MG_EV_MDNS_REQ for incoming // queries and MG_EV_MDNS_RESP for incoming responses. Returns NULL on error. +// fn_data is a NUL-terminated server name, or NULL to pass all requests to fn. struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn, void *fn_data); diff --git a/src/dns.c b/src/dns.c index 46fe4311..54ef627c 100644 --- a/src/dns.c +++ b/src/dns.c @@ -463,7 +463,6 @@ static void handle_mdns_query(struct mg_connection *c) { MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype, (unsigned int) rr.aclass, name)); if (rr.atype == MG_DNS_RTYPE_A) { - // TODO(): ensure c->fn_data ends in \0 // if we have a name to match, go; otherwise users will match and fill // req.r.name and set req.is_resp if (c->fn_data != NULL && mg_casecmp((char *) c->fn_data, name) != 0) diff --git a/src/dns.h b/src/dns.h index d4f48db6..3a1d7138 100644 --- a/src/dns.h +++ b/src/dns.h @@ -82,6 +82,7 @@ size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, // Creates an mDNS listener on UDP multicast 224.0.0.251:5353. Registers it as // the manager's mDNS resolver (mgr->mdns). Fires MG_EV_MDNS_REQ for incoming // queries and MG_EV_MDNS_RESP for incoming responses. Returns NULL on error. +// fn_data is a NUL-terminated server name, or NULL to pass all requests to fn. struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn, void *fn_data); diff --git a/src/l2_eth.c b/src/l2_eth.c index 86052349..24a735c8 100644 --- a/src/l2_eth.c +++ b/src/l2_eth.c @@ -94,6 +94,13 @@ size_t mg_l2_eth_trailer(struct mg_tcpip_if *ifp, size_t len, uint8_t *cur) { struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype addrtype, struct mg_addr *addr); +// Read an unaligned little-endian value from byte pointer p into a native integer. +// Safe on architectures that forbid unaligned access (e.g. Cortex-M0). +#define MG_LOAD_LE32(p) \ + ((uint32_t) (((uint32_t) MG_U8P(p)[3] << 24U) | \ + ((uint32_t) MG_U8P(p)[2] << 16U) | \ + ((uint32_t) MG_U8P(p)[1] << 8U) | MG_U8P(p)[0])) + bool mg_l2_eth_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto, struct mg_str *pay, struct mg_str *raw) { struct eth *eth = (struct eth *) raw->buf; @@ -119,10 +126,11 @@ bool mg_l2_eth_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto, sizeof(eth->dst)) != 0) return false; // TODO(): add multicast addresses if (ifp->enable_fcs_check && len > hdrlen + 4) { - uint32_t crc; - len -= 4; // TODO(scaprile): check on bigendian + uint32_t crc, crc_rx; + len -= 4; crc = mg_crc32(0, (const char *) raw->buf, len); - if (memcmp((void *) ((size_t) raw->buf + len), &crc, sizeof(crc))) + crc_rx = MG_LOAD_LE32(raw->buf + len); + if (crc_rx != crc) return false; } pay->buf = ((char *) eth) + hdrlen; diff --git a/test/eth_test.c b/test/eth_test.c index 55ee7a98..c7a1bbc0 100644 --- a/test/eth_test.c +++ b/test/eth_test.c @@ -63,8 +63,11 @@ static size_t mk_vlan(uint8_t *buf, const uint8_t *dst, uint16_t vlan, static size_t add_fcs(uint8_t *buf, size_t len) { uint32_t crc = mg_crc32(0, (const char *) buf, len); - memcpy(buf + len, &crc, sizeof(crc)); - return len + sizeof(crc); + buf[len++] = (uint8_t) crc; // store as LE32 + buf[len++] = (uint8_t) (crc >> 8); + buf[len++] = (uint8_t) (crc >> 16); + buf[len++] = (uint8_t) (crc >> 24); + return len; } #define DASHBOARD(x) \ @@ -150,6 +153,14 @@ static void test_fcs(void) { size_t len; uint8_t frame[64]; + { // verify add_fcs() stores the CRC bytes in the proper order + // (internal consistency test) + uint8_t payload[] = {1, 2, 3, 4}; + uint8_t fcs[] = {0xf4, 0xd4, 0x37, 0xf6}; + len = add_fcs(frame, mk_eth(frame, s_mac, 0x0800, payload, + sizeof(payload))); + ASSERT(memcmp(frame + len - sizeof(fcs), fcs, sizeof(fcs)) == 0); + } { // FCS check strips a valid CRC uint8_t payload[] = {1, 2, 3, 4}; reset_if(&ifp);