diff --git a/mongoose.c b/mongoose.c index 3cd70896..0715905a 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5040,6 +5040,10 @@ struct pkt { struct dhcp *dhcp; }; +static void mg_tcpip_call(struct mg_tcpip_if *ifp, int ev, void *ev_data) { + if (ifp->fn != NULL) ifp->fn(ifp, ev, ev_data); +} + static void send_syn(struct mg_connection *c); static void mkpay(struct pkt *pkt, void *p) { @@ -5109,6 +5113,7 @@ static void onstatechange(struct mg_tcpip_if *ifp) { } else if (ifp->state == MG_TCPIP_STATE_DOWN) { MG_ERROR(("Link down")); } + mg_tcpip_call(ifp, MG_TCPIP_EV_ST_CHG, &ifp->state); } static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst, @@ -5169,20 +5174,25 @@ static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; -// RFC-2131 #4.3.6, #4.4.1 +// RFC-2131 #4.3.6, #4.4.1; RFC-2132 #9.8 static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req, uint32_t ip_srv) { uint8_t opts[] = { - 53, 1, 3, // Type: DHCP request - 55, 2, 1, 3, // GW and mask - 12, 3, 'm', 'i', 'p', // Host name: "mip" - 54, 4, 0, 0, 0, 0, // DHCP server ID - 50, 4, 0, 0, 0, 0, // Requested IP - 255 // End of options + 53, 1, 3, // Type: DHCP request + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 54, 4, 0, 0, 0, 0, // DHCP server ID + 50, 4, 0, 0, 0, 0, // Requested IP + 55, 2, 1, 3, 255, 255, // GW, mask [DNS] [SNTP] + 255 // End of options }; - memcpy(opts + 14, &ip_srv, sizeof(ip_srv)); - memcpy(opts + 20, &ip_req, sizeof(ip_req)); - tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); + uint8_t addopts = 0; + memcpy(opts + 10, &ip_srv, sizeof(ip_srv)); + memcpy(opts + 16, &ip_req, sizeof(ip_req)); + if (ifp->enable_req_dns) opts[24 + addopts++] = 6; // DNS + if (ifp->enable_req_sntp) opts[24 + addopts++] = 42; // SNTP + opts[21] += addopts; + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, + sizeof(opts) + addopts - 2, false); MG_DEBUG(("DHCP req sent")); } @@ -5278,7 +5288,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { - uint32_t ip = 0, gw = 0, mask = 0, lease = 0; + uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0; uint8_t msgtype = 0, state = ifp->state; // perform size check first, then access fields uint8_t *p = pkt->dhcp->options, @@ -5291,6 +5301,12 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW memcpy(&gw, p + 2, sizeof(gw)); ip = pkt->dhcp->yiaddr; + } else if (ifp->enable_req_dns && p[0] == 6 && p[1] == sizeof(dns) && + p + 6 < end) { // DNS + memcpy(&dns, p + 2, sizeof(dns)); + } else if (ifp->enable_req_sntp && p[0] == 42 && p[1] == sizeof(sntp) && + p + 6 < end) { // SNTP + memcpy(&sntp, p + 2, sizeof(sntp)); } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease memcpy(&lease, p + 2, sizeof(lease)); lease = mg_ntohl(lease); @@ -5319,6 +5335,10 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint64_t rand; mg_random(&rand, sizeof(rand)); srand((unsigned int) (rand + mg_millis())); + if (ifp->enable_req_dns && dns != 0) + mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_DNS, &dns); + if (ifp->enable_req_sntp && sntp != 0) + mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew ifp->lease_expire = ifp->now + lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); diff --git a/mongoose.h b/mongoose.h index 79f0d6e7..ae5bf136 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2568,6 +2568,16 @@ struct mg_tcpip_driver { bool (*up)(struct mg_tcpip_if *); // Up/down status }; +typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev, + void *ev_data); + +enum { + MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state) + MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr + MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr + 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 @@ -2576,10 +2586,13 @@ struct mg_tcpip_if { bool enable_dhcp_client; // Enable DCHP client bool enable_dhcp_server; // Enable DCHP server bool enable_get_gateway; // DCHP server sets client as gateway + bool enable_req_dns; // DCHP client requests DNS server + 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 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 struct mg_mgr *mgr; // Mongoose event manager struct mg_queue recv_queue; // Receive queue uint16_t mtu; // Interface MTU diff --git a/src/net_builtin.c b/src/net_builtin.c index 63b9e677..b41e5d2d 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -138,6 +138,10 @@ struct pkt { struct dhcp *dhcp; }; +static void mg_tcpip_call(struct mg_tcpip_if *ifp, int ev, void *ev_data) { + if (ifp->fn != NULL) ifp->fn(ifp, ev, ev_data); +} + static void send_syn(struct mg_connection *c); static void mkpay(struct pkt *pkt, void *p) { @@ -207,6 +211,7 @@ static void onstatechange(struct mg_tcpip_if *ifp) { } else if (ifp->state == MG_TCPIP_STATE_DOWN) { MG_ERROR(("Link down")); } + mg_tcpip_call(ifp, MG_TCPIP_EV_ST_CHG, &ifp->state); } static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst, @@ -267,20 +272,25 @@ static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; -// RFC-2131 #4.3.6, #4.4.1 +// RFC-2131 #4.3.6, #4.4.1; RFC-2132 #9.8 static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req, uint32_t ip_srv) { uint8_t opts[] = { - 53, 1, 3, // Type: DHCP request - 55, 2, 1, 3, // GW and mask - 12, 3, 'm', 'i', 'p', // Host name: "mip" - 54, 4, 0, 0, 0, 0, // DHCP server ID - 50, 4, 0, 0, 0, 0, // Requested IP - 255 // End of options + 53, 1, 3, // Type: DHCP request + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 54, 4, 0, 0, 0, 0, // DHCP server ID + 50, 4, 0, 0, 0, 0, // Requested IP + 55, 2, 1, 3, 255, 255, // GW, mask [DNS] [SNTP] + 255 // End of options }; - memcpy(opts + 14, &ip_srv, sizeof(ip_srv)); - memcpy(opts + 20, &ip_req, sizeof(ip_req)); - tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); + uint8_t addopts = 0; + memcpy(opts + 10, &ip_srv, sizeof(ip_srv)); + memcpy(opts + 16, &ip_req, sizeof(ip_req)); + if (ifp->enable_req_dns) opts[24 + addopts++] = 6; // DNS + if (ifp->enable_req_sntp) opts[24 + addopts++] = 42; // SNTP + opts[21] += addopts; + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, + sizeof(opts) + addopts - 2, false); MG_DEBUG(("DHCP req sent")); } @@ -376,7 +386,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { - uint32_t ip = 0, gw = 0, mask = 0, lease = 0; + uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0; uint8_t msgtype = 0, state = ifp->state; // perform size check first, then access fields uint8_t *p = pkt->dhcp->options, @@ -389,6 +399,12 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW memcpy(&gw, p + 2, sizeof(gw)); ip = pkt->dhcp->yiaddr; + } else if (ifp->enable_req_dns && p[0] == 6 && p[1] == sizeof(dns) && + p + 6 < end) { // DNS + memcpy(&dns, p + 2, sizeof(dns)); + } else if (ifp->enable_req_sntp && p[0] == 42 && p[1] == sizeof(sntp) && + p + 6 < end) { // SNTP + memcpy(&sntp, p + 2, sizeof(sntp)); } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease memcpy(&lease, p + 2, sizeof(lease)); lease = mg_ntohl(lease); @@ -417,6 +433,10 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint64_t rand; mg_random(&rand, sizeof(rand)); srand((unsigned int) (rand + mg_millis())); + if (ifp->enable_req_dns && dns != 0) + mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_DNS, &dns); + if (ifp->enable_req_sntp && sntp != 0) + mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew ifp->lease_expire = ifp->now + lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); diff --git a/src/net_builtin.h b/src/net_builtin.h index 024cbc0b..618ce991 100644 --- a/src/net_builtin.h +++ b/src/net_builtin.h @@ -14,6 +14,16 @@ struct mg_tcpip_driver { bool (*up)(struct mg_tcpip_if *); // Up/down status }; +typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev, + void *ev_data); + +enum { + MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state) + MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr + MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr + 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 @@ -22,10 +32,13 @@ struct mg_tcpip_if { bool enable_dhcp_client; // Enable DCHP client bool enable_dhcp_server; // Enable DCHP server bool enable_get_gateway; // DCHP server sets client as gateway + bool enable_req_dns; // DCHP client requests DNS server + 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 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 struct mg_mgr *mgr; // Mongoose event manager struct mg_queue recv_queue; // Receive queue uint16_t mtu; // Interface MTU diff --git a/tutorials/tcpip/tap-driver/main.c b/tutorials/tcpip/tap-driver/main.c index bc38381c..17fc0d07 100644 --- a/tutorials/tcpip/tap-driver/main.c +++ b/tutorials/tcpip/tap-driver/main.c @@ -42,6 +42,23 @@ static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) { return (size_t) received; } +char *s_dns = NULL, *s_sntp = NULL; + +static void mif_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) { + if (ev == MG_TCPIP_EV_ST_CHG) { + MG_INFO(("State change: %u", *(uint8_t *) ev_data)); + } else if (ev == MG_TCPIP_EV_DHCP_DNS) { + free(s_dns); + s_dns = mg_mprintf("udp://%M:53", mg_print_ip4, (uint32_t *) ev_data); + ifp->mgr->dns4.url = s_dns; + MG_INFO(("Set DNS to %s", ifp->mgr->dns4.url)); + } else if (ev == MG_TCPIP_EV_DHCP_SNTP) { + free(s_sntp); + s_sntp = mg_mprintf("udp://%M:123", mg_print_ip4, (uint32_t *) ev_data); + MG_INFO(("Set SNTP to %s", s_sntp)); + } +} + int main(int argc, char *argv[]) { const char *iface = "tap0"; // Network iface const char *mac = "02:00:01:02:03:77"; // MAC address @@ -93,7 +110,11 @@ int main(int argc, char *argv[]) { mg_mgr_init(&mgr); // Initialise event manager struct mg_tcpip_driver driver = {.tx = tap_tx, .up = tap_up, .rx = tap_rx}; - struct mg_tcpip_if mif = {.driver = &driver, .driver_data = &fd}; + struct mg_tcpip_if mif = {.driver = &driver, + .driver_data = &fd, + .enable_req_dns = true, + .enable_req_sntp = true, + .fn = mif_fn}; sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1], &mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]); mg_tcpip_init(&mgr, &mif); @@ -107,6 +128,8 @@ int main(int argc, char *argv[]) { web_init(&mgr); while (s_signo == 0) mg_mgr_poll(&mgr, 100); // Infinite event loop + free(s_dns); + free(s_sntp); mg_mgr_free(&mgr); close(fd); printf("Exiting on signal %d\n", s_signo);