1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "esp_netif.h"
8 #include "sys/queue.h"
9 #include "esp_log.h"
10 #include "freertos/FreeRTOS.h"
11 #include "freertos/semphr.h"
12 #include "esp_netif_private.h"
13 #include <string.h>
14 
15 //
16 // Purpose of this module is to provide list of esp-netif structures
17 //  - this module has no dependency on a specific network stack (lwip)
18 //
19 
20 static const char *TAG = "esp_netif_objects";
21 
22 typedef struct slist_netifs_s slist_netifs_t;
23 struct slist_netifs_s {
24     esp_netif_t *netif;
25     SLIST_ENTRY(slist_netifs_s) next;
26 };
27 
28 SLIST_HEAD(slisthead, slist_netifs_s) s_head = { .slh_first = NULL, };
29 
30 static size_t s_esp_netif_counter = 0;
31 static SemaphoreHandle_t  s_list_lock = NULL;
32 
33 ESP_EVENT_DEFINE_BASE(IP_EVENT);
34 
esp_netif_list_lock(void)35 esp_err_t esp_netif_list_lock(void)
36 {
37     if (s_list_lock == NULL) {
38         s_list_lock = xSemaphoreCreateMutex();
39         if (s_list_lock == NULL) {
40             return ESP_ERR_NO_MEM;
41         }
42     }
43     xSemaphoreTake(s_list_lock, portMAX_DELAY);
44     return ESP_OK;
45 }
46 
esp_netif_list_unlock(void)47 void esp_netif_list_unlock(void)
48 {
49     assert(s_list_lock);
50     xSemaphoreGive(s_list_lock);
51     if (s_esp_netif_counter == 0) {
52         vQueueDelete(s_list_lock);
53         s_list_lock = NULL;
54     }
55 }
56 
57 //
58 // List manipulation functions
59 //
esp_netif_add_to_list(esp_netif_t * netif)60 esp_err_t esp_netif_add_to_list(esp_netif_t *netif)
61 {
62     esp_err_t ret;
63     struct slist_netifs_s *item = calloc(1, sizeof(struct slist_netifs_s));
64     ESP_LOGD(TAG, "%s %p", __func__, netif);
65     if (item == NULL) {
66         return ESP_ERR_NO_MEM;
67     }
68     item->netif = netif;
69 
70     if ((ret = esp_netif_list_lock()) != ESP_OK) {
71         free(item);
72         return ret;
73     }
74 
75     SLIST_INSERT_HEAD(&s_head, item, next);
76     ++s_esp_netif_counter;
77     ESP_LOGD(TAG, "%s netif added successfully (total netifs: %d)", __func__, s_esp_netif_counter);
78     esp_netif_list_unlock();
79     return ESP_OK;
80 }
81 
82 
esp_netif_remove_from_list(esp_netif_t * netif)83 esp_err_t esp_netif_remove_from_list(esp_netif_t *netif)
84 {
85     struct slist_netifs_s *item;
86     esp_err_t ret;
87     if ((ret = esp_netif_list_lock()) != ESP_OK) {
88         return ret;
89     }
90     ESP_LOGV(TAG, "%s %p", __func__, netif);
91 
92     SLIST_FOREACH(item, &s_head, next) {
93         if (item->netif == netif) {
94             SLIST_REMOVE(&s_head, item, slist_netifs_s, next);
95             assert(s_esp_netif_counter > 0);
96             --s_esp_netif_counter;
97             ESP_LOGD(TAG, "%s netif successfully removed (total netifs: %d)", __func__, s_esp_netif_counter);
98             free(item);
99             esp_netif_list_unlock();
100             return ESP_OK;
101         }
102     }
103     esp_netif_list_unlock();
104     return ESP_ERR_NOT_FOUND;
105 }
106 
esp_netif_get_nr_of_ifs(void)107 size_t esp_netif_get_nr_of_ifs(void)
108 {
109     return s_esp_netif_counter;
110 }
111 
esp_netif_next(esp_netif_t * netif)112 esp_netif_t* esp_netif_next(esp_netif_t* netif)
113 {
114     esp_err_t ret;
115     esp_netif_t* result;
116     if ((ret = esp_netif_list_lock()) != ESP_OK) {
117         ESP_LOGE(TAG, "Failed to lock esp-netif list with %d", ret);
118         return NULL;
119     }
120     result = esp_netif_next_unsafe(netif);
121     esp_netif_list_unlock();
122     return result;
123 }
124 
esp_netif_next_unsafe(esp_netif_t * netif)125 esp_netif_t* esp_netif_next_unsafe(esp_netif_t* netif)
126 {
127     ESP_LOGV(TAG, "%s %p", __func__, netif);
128     struct slist_netifs_s *item;
129     // Getting the first netif if argument is NULL
130     if (netif == NULL) {
131         item = SLIST_FIRST(&s_head);
132         return (item == NULL) ? NULL : item->netif;
133     }
134     // otherwise the next one (after the supplied netif)
135     SLIST_FOREACH(item, &s_head, next) {
136         if (item->netif == netif) {
137             item = SLIST_NEXT(item, next);
138             return (item == NULL) ? NULL : item->netif;
139         }
140     }
141     return NULL;
142 }
143 
esp_netif_is_netif_listed(esp_netif_t * esp_netif)144 bool esp_netif_is_netif_listed(esp_netif_t *esp_netif)
145 {
146     struct slist_netifs_s *item;
147     esp_err_t ret;
148     if ((ret = esp_netif_list_lock()) != ESP_OK) {
149         ESP_LOGE(TAG, "Failed to lock esp-netif list with %d", ret);
150         return false;
151     }
152 
153     SLIST_FOREACH(item, &s_head, next) {
154         if (item->netif == esp_netif) {
155             esp_netif_list_unlock();
156             return true;
157         }
158     }
159     esp_netif_list_unlock();
160     return false;
161 }
162 
esp_netif_get_handle_from_ifkey(const char * if_key)163 esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key)
164 {
165     struct slist_netifs_s *item;
166     esp_err_t ret;
167     if ((ret = esp_netif_list_lock()) != ESP_OK) {
168         ESP_LOGE(TAG, "Failed to lock esp-netif list with %d", ret);
169         return NULL;
170     }
171 
172     SLIST_FOREACH(item, &s_head, next) {
173         esp_netif_t *esp_netif = item->netif;
174         if (strcmp(if_key, esp_netif_get_ifkey(esp_netif)) == 0) {
175             esp_netif_list_unlock();
176             return esp_netif;
177         }
178     }
179     esp_netif_list_unlock();
180     return NULL;
181 }
182