| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /* Mesh IP Internal Communication Example
- This example code is in the Public Domain (or CC0 licensed, at your option.)
- Unless required by applicable law or agreed to in writing, this
- software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied.
- */
- #include "esp_wifi.h"
- #include "esp_netif.h"
- #include "esp_log.h"
- #include <string.h>
- #include "esp_mesh.h"
- #include "esp_mac.h"
- #include "lwip/lwip_napt.h"
- #include "dhcpserver/dhcpserver.h"
- #include "esp_wifi_netif.h"
- #include "mesh_netif.h"
- /*******************************************************
- * Macros
- *******************************************************/
- #define RX_SIZE (1560)
- #if CONFIG_MESH_USE_GLOBAL_DNS_IP
- #define DNS_IP_ADDR CONFIG_MESH_GLOBAL_DNS_IP
- #endif
- /*******************************************************
- * Type Definitions
- *******************************************************/
- typedef struct mesh_netif_driver* mesh_netif_driver_t;
- typedef struct mesh_netif_driver {
- esp_netif_driver_base_t base;
- uint8_t sta_mac_addr[MAC_ADDR_LEN];
- }* mesh_netif_driver_t;
- /*******************************************************
- * Constants
- *******************************************************/
- static const char* TAG = "mesh_netif";
- const esp_netif_ip_info_t g_mesh_netif_subnet_ip = { // mesh subnet IP info
- .ip = { .addr = ESP_IP4TOADDR( 10, 0, 0, 1) },
- .gw = { .addr = ESP_IP4TOADDR( 10, 0, 0, 1) },
- .netmask = { .addr = ESP_IP4TOADDR( 255, 255, 0, 0) },
- };
- /*******************************************************
- * Variable Definitions
- *******************************************************/
- static esp_netif_t *netif_sta = NULL;
- static esp_netif_t *netif_ap = NULL;
- static bool receive_task_is_running = false;
- static mesh_addr_t s_route_table[CONFIG_MESH_ROUTE_TABLE_SIZE] = { 0 };
- static mesh_raw_recv_cb_t *s_mesh_raw_recv_cb = NULL;
- /*******************************************************
- * Function Definitions
- *******************************************************/
- // setup DHCP server's DNS OFFER
- //
- static esp_err_t set_dhcps_dns(esp_netif_t *netif, uint32_t addr)
- {
- esp_netif_dns_info_t dns;
- dns.ip.u_addr.ip4.addr = addr;
- dns.ip.type = IPADDR_TYPE_V4;
- dhcps_offer_t dhcps_dns_value = OFFER_DNS;
- ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
- ESP_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_dns_value, sizeof(dhcps_dns_value)));
- ESP_ERROR_CHECK(esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns));
- ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
- return ESP_OK;
- }
- // Receive task
- //
- static void receive_task(void *arg)
- {
- esp_err_t err;
- mesh_addr_t from;
- int flag = 0;
- mesh_data_t data;
- static uint8_t rx_buf[RX_SIZE] = { 0, };
- ESP_LOGD(TAG, "Receiving task started");
- while (receive_task_is_running) {
- data.data = rx_buf;
- data.size = RX_SIZE;
- err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "Received with err code %d %s", err, esp_err_to_name(err));
- continue;
- }
- if (data.proto == MESH_PROTO_BIN && s_mesh_raw_recv_cb) {
- s_mesh_raw_recv_cb(&from, &data);
- }
- if (esp_mesh_is_root()) {
- if (data.proto == MESH_PROTO_AP) {
- ESP_LOGD(TAG, "Root received: from: " MACSTR " to " MACSTR " size: %d",
- MAC2STR((uint8_t*)data.data) ,MAC2STR((uint8_t*)(data.data+6)), data.size);
- if (netif_ap) {
- // actual receive to TCP/IP stack
- esp_netif_receive(netif_ap, data.data, data.size, NULL);
- }
- } else if (data.proto == MESH_PROTO_STA) {
- ESP_LOGE(TAG, "Root station Should never receive data from mesh!");
- }
- } else {
- if (data.proto == MESH_PROTO_AP) {
- ESP_LOGD(TAG, "Node AP should never receive data from mesh");
- } else if (data.proto == MESH_PROTO_STA) {
- ESP_LOGD(TAG, "Node received: from: " MACSTR " to " MACSTR " size: %d",
- MAC2STR((uint8_t*)data.data) ,MAC2STR((uint8_t*)(data.data+6)), data.size);
- if (netif_sta) {
- // actual receive to TCP/IP stack
- esp_netif_receive(netif_sta, data.data, data.size, NULL);
- }
- }
- }
- }
- vTaskDelete(NULL);
- }
- // Free RX buffer (not used as the buffer is static)
- //
- static void mesh_free(void *h, void* buffer)
- {
- free(buffer);
- }
- // Transmit function variants
- //
- static esp_err_t mesh_netif_transmit_from_root_ap(void *h, void *buffer, size_t len)
- {
- // Use only to transmit data from root AP to node's AP
- static const uint8_t eth_broadcast[MAC_ADDR_LEN] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
- int route_table_size = 0;
- mesh_netif_driver_t mesh_driver = h;
- mesh_addr_t dest_addr;
- mesh_data_t data;
- ESP_LOGD(TAG, "Sending to node: " MACSTR ", size: %d" ,MAC2STR((uint8_t*)buffer), len);
- memcpy(dest_addr.addr, buffer, MAC_ADDR_LEN);
- data.data = buffer;
- data.size = len;
- data.proto = MESH_PROTO_STA; // sending from root AP -> Node's STA
- data.tos = MESH_TOS_P2P;
- if (MAC_ADDR_EQUAL(dest_addr.addr, eth_broadcast)) {
- ESP_LOGD(TAG, "Broadcasting!");
- esp_mesh_get_routing_table((mesh_addr_t *) &s_route_table,
- CONFIG_MESH_ROUTE_TABLE_SIZE * 6, &route_table_size);
- for (int i = 0; i < route_table_size; i++) {
- if (MAC_ADDR_EQUAL(s_route_table[i].addr, mesh_driver->sta_mac_addr)) {
- ESP_LOGD(TAG, "That was me, skipping!");
- continue;
- }
- ESP_LOGD(TAG, "Broadcast: Sending to [%d] " MACSTR, i, MAC2STR(s_route_table[i].addr));
- esp_err_t err = esp_mesh_send(&s_route_table[i], &data, MESH_DATA_P2P, NULL, 0);
- if (ESP_OK != err) {
- ESP_LOGE(TAG, "Send with err code %d %s", err, esp_err_to_name(err));
- }
- }
- } else {
- // Standard P2P
- esp_err_t err = esp_mesh_send(&dest_addr, &data, MESH_DATA_P2P, NULL, 0);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "Send with err code %d %s", err, esp_err_to_name(err));
- return err;
- }
- }
- return ESP_OK;
- }
- static esp_err_t mesh_netif_transmit_from_root_ap_wrap(void *h, void *buffer, size_t len, void *netstack_buf)
- {
- return mesh_netif_transmit_from_root_ap(h, buffer, len);
- }
- static esp_err_t mesh_netif_transmit_from_node_sta(void *h, void *buffer, size_t len)
- {
- mesh_data_t data;
- ESP_LOGD(TAG, "Sending to root, dest addr: " MACSTR ", size: %d" ,MAC2STR((uint8_t*)buffer), len);
- data.data = buffer;
- data.size = len;
- data.proto = MESH_PROTO_AP; // Node's station transmits data to root's AP
- data.tos = MESH_TOS_P2P;
- esp_err_t err = esp_mesh_send(NULL, &data, MESH_DATA_TODS, NULL, 0);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "Send with err code %d %s", err, esp_err_to_name(err));
- }
- return err;
- }
- static esp_err_t mesh_netif_transmit_from_node_sta_wrap(void *h, void *buffer, size_t len, void *netstack_buf)
- {
- return mesh_netif_transmit_from_node_sta(h, buffer, len);
- }
- // Construct and Destruct functions
- //
- static esp_err_t mesh_driver_start_root_ap(esp_netif_t * esp_netif, void * args)
- {
- mesh_netif_driver_t driver = args;
- driver->base.netif = esp_netif;
- esp_netif_driver_ifconfig_t driver_ifconfig = {
- .handle = driver,
- .transmit = mesh_netif_transmit_from_root_ap,
- .transmit_wrap = mesh_netif_transmit_from_root_ap_wrap,
- .driver_free_rx_buffer = mesh_free
- };
- return esp_netif_set_driver_config(esp_netif, &driver_ifconfig);
- }
- static esp_err_t mesh_driver_start_node_sta(esp_netif_t * esp_netif, void * args)
- {
- mesh_netif_driver_t driver = args;
- driver->base.netif = esp_netif;
- esp_netif_driver_ifconfig_t driver_ifconfig = {
- .handle = driver,
- .transmit = mesh_netif_transmit_from_node_sta,
- .transmit_wrap = mesh_netif_transmit_from_node_sta_wrap,
- .driver_free_rx_buffer = mesh_free
- };
- return esp_netif_set_driver_config(esp_netif, &driver_ifconfig);
- }
- void mesh_delete_if_driver(mesh_netif_driver_t driver)
- {
- // Stop the task once both drivers are removed
- // receive_task_is_running = true;
- free(driver);
- }
- mesh_netif_driver_t mesh_create_if_driver(bool is_ap, bool is_root)
- {
- mesh_netif_driver_t driver = calloc(1, sizeof(struct mesh_netif_driver));
- if (driver == NULL) {
- ESP_LOGE(TAG, "No memory to create a wifi interface handle");
- return NULL;
- }
- if (is_ap && is_root) {
- driver->base.post_attach = mesh_driver_start_root_ap;
- } else if (!is_ap && !is_root) {
- driver->base.post_attach = mesh_driver_start_node_sta;
- } else {
- return NULL;
- }
- if (!receive_task_is_running) {
- receive_task_is_running = true;
- xTaskCreate(receive_task, "netif rx task", 3072, NULL, 5, NULL);
- }
- // save station mac address to exclude it from routing-table on broadcast
- esp_wifi_get_mac(WIFI_IF_STA, driver->sta_mac_addr);
- return driver;
- }
- esp_err_t mesh_netifs_destroy(void)
- {
- receive_task_is_running = false;
- return ESP_OK;
- }
- static void mesh_netif_init_station(void)
- {
- // By default create a station that would connect to AP (expecting root to connect to external network)
- esp_netif_config_t cfg_sta = ESP_NETIF_DEFAULT_WIFI_STA();
- netif_sta = esp_netif_new(&cfg_sta);
- assert(netif_sta);
- ESP_ERROR_CHECK(esp_netif_attach_wifi_station(netif_sta));
- ESP_ERROR_CHECK(esp_wifi_set_default_wifi_sta_handlers());
- }
- // Init by default for both potential root and node
- //
- esp_err_t mesh_netifs_init(mesh_raw_recv_cb_t *cb)
- {
- mesh_netif_init_station();
- s_mesh_raw_recv_cb = cb;
- return ESP_OK;
- }
- /**
- * @brief Starts AP esp-netif link over mesh (root's AP on mesh)
- */
- static esp_err_t start_mesh_link_ap(void)
- {
- uint8_t mac[MAC_ADDR_LEN];
- esp_wifi_get_mac(WIFI_IF_AP, mac);
- esp_netif_set_mac(netif_ap, mac);
- esp_netif_action_start(netif_ap, NULL, 0, NULL);
- return ESP_OK;
- }
- /**
- * @brief Starts station link over wifi (root node to the router)
- */
- static esp_err_t start_wifi_link_sta(void)
- {
- uint8_t mac[6];
- esp_wifi_get_mac(WIFI_IF_STA, mac);
- esp_err_t ret;
- void *driver = esp_netif_get_io_driver(netif_sta);
- if ((ret = esp_wifi_register_if_rxcb(driver, esp_netif_receive, netif_sta)) != ESP_OK) {
- ESP_LOGE(TAG, "esp_wifi_register_if_rxcb for if=%p failed with %d", driver, ret);
- return ESP_FAIL;
- }
- esp_netif_set_mac(netif_sta, mac);
- esp_netif_action_start(netif_sta, NULL, 0, NULL);
- return ESP_OK;
- }
- /**
- * @brief Starts station link over mesh (node to root over mesh)
- */
- static esp_err_t start_mesh_link_sta(void)
- {
- uint8_t mac[MAC_ADDR_LEN];
- esp_wifi_get_mac(WIFI_IF_STA, mac);
- esp_netif_set_mac(netif_sta, mac);
- esp_netif_action_start(netif_sta, NULL, 0, NULL);
- esp_netif_action_connected(netif_sta, NULL, 0, NULL);
- return ESP_OK;
- }
- /**
- * @brief Creates esp-netif for AP interface over mesh
- *
- * @return Pointer to esp-netif instance
- */
- static esp_netif_t* create_mesh_link_ap(void)
- {
- esp_netif_inherent_config_t base_cfg = ESP_NETIF_INHERENT_DEFAULT_WIFI_AP();
- base_cfg.if_desc = "mesh_link_ap";
- base_cfg.ip_info = &g_mesh_netif_subnet_ip;
- esp_netif_config_t cfg = {
- .base = &base_cfg,
- .driver = NULL,
- .stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_AP };
- esp_netif_t * netif = esp_netif_new(&cfg);
- assert(netif);
- return netif;
- }
- /**
- * @brief Creates esp-netif for station interface over mesh
- *
- * @note Interface needs to be started (later) using the above APIs
- * based on the actual configuration root/node,
- * since root connects normally over wifi
- *
- * @return Pointer to esp-netif instance
- */
- static esp_netif_t* create_mesh_link_sta(void)
- {
- esp_netif_inherent_config_t base_cfg = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA();
- base_cfg.if_desc = "mesh_link_sta";
- esp_netif_config_t cfg = {
- .base = &base_cfg,
- .driver = NULL,
- .stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA };
- esp_netif_t * netif = esp_netif_new(&cfg);
- assert(netif);
- return netif;
- }
- esp_err_t mesh_netif_start_root_ap(bool is_root, uint32_t addr)
- {
- if (is_root) {
- if (netif_ap) {
- esp_netif_action_disconnected(netif_ap, NULL, 0, NULL);
- mesh_delete_if_driver(esp_netif_get_io_driver(netif_ap));
- esp_netif_destroy(netif_ap);
- netif_ap = NULL;
- }
- netif_ap = create_mesh_link_ap();
- mesh_netif_driver_t driver = mesh_create_if_driver(true, true);
- if (driver == NULL) {
- ESP_LOGE(TAG, "Failed to create wifi interface handle");
- return ESP_FAIL;
- }
- esp_netif_attach(netif_ap, driver);
- set_dhcps_dns(netif_ap, addr);
- start_mesh_link_ap();
- ip_napt_enable(g_mesh_netif_subnet_ip.ip.addr, 1);
- }
- return ESP_OK;
- }
- esp_err_t mesh_netifs_start(bool is_root)
- {
- if (is_root) {
- // ROOT: need both sta should use standard wifi, AP mesh link netif
- // Root: Station
- if (netif_sta && strcmp(esp_netif_get_desc(netif_sta), "sta") == 0) {
- ESP_LOGI(TAG, "Already wifi station, no need to do anything");
- } else if (netif_sta && strcmp(esp_netif_get_desc(netif_sta), "mesh_link_sta") == 0) {
- esp_netif_action_disconnected(netif_sta, NULL, 0, NULL);
- mesh_delete_if_driver(esp_netif_get_io_driver(netif_sta));
- esp_netif_destroy(netif_sta);
- mesh_netif_init_station();
- } else if (netif_sta == NULL) {
- mesh_netif_init_station();
- }
- // Root: AP is initialized only if GLOBAL DNS configured
- // (otherwise have to wait until the actual DNS record received from the router)
- #if CONFIG_MESH_USE_GLOBAL_DNS_IP
- mesh_netif_start_root_ap(true, htonl(DNS_IP_ADDR));
- #endif
- } else {
- // NODE: create only STA in form of mesh link
- if (netif_sta && strcmp(esp_netif_get_desc(netif_sta), "mesh_link_sta") == 0) {
- ESP_LOGI(TAG, "Already mesh link station, no need to do anything");
- return ESP_OK;
- }
- if (netif_sta) {
- esp_netif_action_disconnected(netif_sta, NULL, 0, NULL);
- // should remove the actual driver
- if (strcmp(esp_netif_get_desc(netif_sta), "sta") == 0) {
- ESP_LOGI(TAG, "It was a wifi station removing stuff");
- esp_wifi_clear_default_wifi_driver_and_handlers(netif_sta);
- }
- esp_netif_destroy(netif_sta);
- }
- netif_sta = create_mesh_link_sta();
- // now we create a mesh driver and attach it to the existing netif
- mesh_netif_driver_t driver = mesh_create_if_driver(false, false);
- if (driver == NULL) {
- ESP_LOGE(TAG, "Failed to create wifi interface handle");
- return ESP_FAIL;
- }
- esp_netif_attach(netif_sta, driver);
- start_mesh_link_sta();
- // If we have a AP on NODE -> stop and remove it!
- if (netif_ap) {
- esp_netif_action_disconnected(netif_ap, NULL, 0, NULL);
- mesh_delete_if_driver(esp_netif_get_io_driver(netif_ap));
- esp_netif_destroy(netif_ap);
- netif_ap = NULL;
- }
- }
- return ESP_OK;
- }
- esp_err_t mesh_netifs_stop(void)
- {
- if (netif_sta && strcmp(esp_netif_get_desc(netif_sta), "sta") == 0 && netif_ap == NULL) {
- return ESP_OK;
- }
- if (netif_sta) {
- if (strcmp(esp_netif_get_desc(netif_sta), "sta") == 0) {
- esp_netif_action_disconnected(netif_sta, NULL, 0, NULL);
- esp_netif_action_stop(netif_sta, NULL, 0, NULL);
- esp_wifi_clear_default_wifi_driver_and_handlers(netif_sta);
- } else {
- esp_netif_action_disconnected(netif_sta, NULL, 0, NULL);
- mesh_delete_if_driver(esp_netif_get_io_driver(netif_sta));
- }
- esp_netif_destroy(netif_sta);
- netif_sta = NULL;
- }
- if (netif_ap) {
- esp_netif_action_disconnected(netif_ap, NULL, 0, NULL);
- mesh_delete_if_driver(esp_netif_get_io_driver(netif_ap));
- esp_netif_destroy(netif_ap);
- netif_ap = NULL;
- }
- // reserve the default (STA gets ready to become root)
- mesh_netif_init_station();
- start_wifi_link_sta();
- return ESP_OK;
- }
- uint8_t* mesh_netif_get_station_mac(void)
- {
- mesh_netif_driver_t mesh = esp_netif_get_io_driver(netif_sta);
- return mesh->sta_mac_addr;
- }
|